libpng-ruby 0.5.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/ext/png/png.c +980 -337
- data/lib/png/version.rb +1 -1
- data/libpng-ruby.gemspec +4 -4
- metadata +15 -17
- data/bin/pnginfo +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7065dd93f08e6f53cce0a60e91bda0fdbfe9fd305d4bea5e35dc5a82f5e87f75
|
4
|
+
data.tar.gz: 9bda38b5eb8d4c70a269ec574fd1a9db7dabb1ffd8004da6adc6e9e0fe16197e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 174bcdf1fb51539d63ce18b6a32abeb7b484052ada9086106259fba1c6a7e99e740a97fb2a4f3c52fdbeac577114760ee86acbbf5f0722da199a526e236f0334
|
7
|
+
data.tar.gz: 33d169bc03a3e7cf778f2588529d1f450ff9b4af794b54780562916d5e29be0870f704d351e46d9499c70e558ae1ec9548c9dd014caefd195df3dc4ae3046942
|
data/README.md
CHANGED
@@ -59,7 +59,7 @@ IO.binwrite("test.png", enc << IO.binread("test.raw"))
|
|
59
59
|
#### encode options
|
60
60
|
| option | value type | description |
|
61
61
|
|---|---|---|
|
62
|
-
| :
|
62
|
+
| :pixel_format | String or Symbol | input pixel format |
|
63
63
|
| :interlace | Boolean | use interlace mode |
|
64
64
|
| :compression | Integer or String or Symbol | compression level |
|
65
65
|
| :text | Hash | text information |
|
data/ext/png/png.c
CHANGED
@@ -4,10 +4,6 @@
|
|
4
4
|
* Copyright (C) 2016 Hiroshi Kuwagata <kgt9221@gmail.com>
|
5
5
|
*/
|
6
6
|
|
7
|
-
/*
|
8
|
-
* $Id: png.c 67 2016-06-07 06:10:47Z pi $
|
9
|
-
*/
|
10
|
-
|
11
7
|
#include <stdio.h>
|
12
8
|
#include <stdint.h>
|
13
9
|
#include <string.h>
|
@@ -19,11 +15,13 @@
|
|
19
15
|
#include <zlib.h>
|
20
16
|
|
21
17
|
#include "ruby.h"
|
18
|
+
#include "ruby/version.h"
|
22
19
|
|
23
20
|
#define N(x) (sizeof(x)/sizeof(*x))
|
24
21
|
|
25
22
|
#define RUNTIME_ERROR(msg) rb_raise(rb_eRuntimeError, (msg))
|
26
23
|
#define ARGUMENT_ERROR(msg) rb_raise(rb_eArgError, (msg))
|
24
|
+
#define RANGE_ERROR(msg) rb_raise(rb_eRangeError, (msg))
|
27
25
|
#define TYPE_ERROR(msg) rb_raise(rb_eTypeError, (msg))
|
28
26
|
#define NOMEMORY_ERROR(msg) rb_raise(rb_eNoMemError, (msg))
|
29
27
|
|
@@ -33,6 +31,22 @@
|
|
33
31
|
#define EQ_STR(val,str) (rb_to_id(val) == rb_intern(str))
|
34
32
|
#define EQ_INT(val,n) (FIX2INT(val) == n)
|
35
33
|
|
34
|
+
#define SET_DATA(ptr, idat, odat) \
|
35
|
+
do { \
|
36
|
+
(ptr)->ibuf = (idat);\
|
37
|
+
(ptr)->obuf = (odat);\
|
38
|
+
(ptr)->error = Qnil;\
|
39
|
+
(ptr)->warn_msg = Qnil;\
|
40
|
+
} while (0)
|
41
|
+
|
42
|
+
#define CLR_DATA(ptr) \
|
43
|
+
do { \
|
44
|
+
(ptr)->ibuf = Qnil;\
|
45
|
+
(ptr)->obuf = Qnil;\
|
46
|
+
(ptr)->error = Qnil;\
|
47
|
+
(ptr)->warn_msg = Qnil;\
|
48
|
+
} while (0)
|
49
|
+
|
36
50
|
static VALUE module;
|
37
51
|
static VALUE encoder_klass;
|
38
52
|
static VALUE decoder_klass;
|
@@ -58,13 +72,10 @@ typedef struct {
|
|
58
72
|
png_infop info;
|
59
73
|
|
60
74
|
png_uint_32 width;
|
75
|
+
png_uint_32 stride;
|
61
76
|
png_uint_32 height;
|
62
|
-
|
63
|
-
png_byte** rows;
|
64
|
-
|
65
|
-
int stride;
|
77
|
+
png_uint_32 data_size;
|
66
78
|
int num_comp;
|
67
|
-
int pixels;
|
68
79
|
int with_time;
|
69
80
|
|
70
81
|
int c_type; // as 'color type'
|
@@ -72,10 +83,16 @@ typedef struct {
|
|
72
83
|
int c_level; // as 'compression level'
|
73
84
|
int f_type; // as 'filter type'
|
74
85
|
|
86
|
+
png_byte** rows;
|
75
87
|
png_text* text;
|
76
88
|
int num_text;
|
77
|
-
|
78
89
|
double gamma;
|
90
|
+
|
91
|
+
VALUE ibuf;
|
92
|
+
VALUE obuf;
|
93
|
+
|
94
|
+
VALUE error;
|
95
|
+
VALUE warn_msg;
|
79
96
|
} png_encoder_t;
|
80
97
|
|
81
98
|
typedef union {
|
@@ -84,6 +101,9 @@ typedef union {
|
|
84
101
|
int format;
|
85
102
|
int need_meta;
|
86
103
|
double display_gamma;
|
104
|
+
|
105
|
+
VALUE error;
|
106
|
+
VALUE warn_msg;
|
87
107
|
} common;
|
88
108
|
|
89
109
|
struct {
|
@@ -95,6 +115,9 @@ typedef union {
|
|
95
115
|
int need_meta;
|
96
116
|
double display_gamma;
|
97
117
|
|
118
|
+
VALUE error;
|
119
|
+
VALUE warn_msg;
|
120
|
+
|
98
121
|
/*
|
99
122
|
* classic api context
|
100
123
|
*/
|
@@ -130,6 +153,9 @@ typedef union {
|
|
130
153
|
int need_meta;
|
131
154
|
double display_gamma;
|
132
155
|
|
156
|
+
VALUE error;
|
157
|
+
VALUE warn_msg;
|
158
|
+
|
133
159
|
/*
|
134
160
|
* simplified api context
|
135
161
|
*/
|
@@ -153,16 +179,180 @@ static const char* encoder_opt_keys[] ={
|
|
153
179
|
"text", // hash<String,String>
|
154
180
|
"time", // bool (default: true)
|
155
181
|
"gamma", // float
|
182
|
+
"stride", // int >0
|
156
183
|
};
|
157
184
|
|
158
185
|
static ID encoder_opt_ids[N(encoder_opt_keys)];
|
159
186
|
|
187
|
+
static void
|
188
|
+
mem_io_write_data(png_structp ctx, png_bytep src, png_size_t size)
|
189
|
+
{
|
190
|
+
VALUE buf;
|
191
|
+
|
192
|
+
buf = (VALUE)png_get_io_ptr(ctx);
|
193
|
+
rb_str_buf_cat(buf, (const char *)src, size);
|
194
|
+
}
|
195
|
+
|
196
|
+
static void
|
197
|
+
mem_io_read_data(png_structp ctx, png_bytep dst, png_size_t rq_size)
|
198
|
+
{
|
199
|
+
mem_io_t* io;
|
200
|
+
|
201
|
+
io = (mem_io_t*)png_get_io_ptr(ctx);
|
202
|
+
|
203
|
+
if (io->pos + rq_size <= io->size) {
|
204
|
+
memcpy(dst, io->ptr + io->pos, rq_size);
|
205
|
+
io->pos += rq_size;
|
206
|
+
|
207
|
+
} else {
|
208
|
+
png_error(ctx, "data not enough.");
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
static void
|
213
|
+
mem_io_flush(png_structp ctx)
|
214
|
+
{
|
215
|
+
// ignore
|
216
|
+
}
|
217
|
+
|
218
|
+
static char*
|
219
|
+
clone_cstr(VALUE s)
|
220
|
+
{
|
221
|
+
char* ret;
|
222
|
+
size_t sz;
|
223
|
+
|
224
|
+
sz = RSTRING_LEN(s);
|
225
|
+
|
226
|
+
ret = (char*)malloc(sz + 1);
|
227
|
+
if (ret == NULL) NOMEMORY_ERROR("no memory");
|
228
|
+
|
229
|
+
memcpy(ret, RSTRING_PTR(s), sz);
|
230
|
+
ret[sz] = '\0';
|
231
|
+
|
232
|
+
return ret;
|
233
|
+
}
|
234
|
+
|
235
|
+
static VALUE
|
236
|
+
create_runtime_error(const char* fmt, ...)
|
237
|
+
{
|
238
|
+
VALUE ret;
|
239
|
+
va_list ap;
|
240
|
+
|
241
|
+
va_start(ap, fmt);
|
242
|
+
ret = rb_exc_new_str(rb_eRuntimeError, rb_vsprintf(fmt, ap));
|
243
|
+
va_end(ap);
|
244
|
+
|
245
|
+
return ret;
|
246
|
+
}
|
247
|
+
|
248
|
+
static VALUE
|
249
|
+
create_argument_error(const char* fmt, ...)
|
250
|
+
{
|
251
|
+
VALUE ret;
|
252
|
+
va_list ap;
|
253
|
+
|
254
|
+
va_start(ap, fmt);
|
255
|
+
ret = rb_exc_new_str(rb_eArgError, rb_vsprintf(fmt, ap));
|
256
|
+
va_end(ap);
|
257
|
+
|
258
|
+
return ret;
|
259
|
+
}
|
260
|
+
|
261
|
+
static VALUE
|
262
|
+
create_type_error(const char* fmt, ...)
|
263
|
+
{
|
264
|
+
VALUE ret;
|
265
|
+
va_list ap;
|
266
|
+
|
267
|
+
va_start(ap, fmt);
|
268
|
+
ret = rb_exc_new_str(rb_eTypeError, rb_vsprintf(fmt, ap));
|
269
|
+
va_end(ap);
|
270
|
+
|
271
|
+
return ret;
|
272
|
+
}
|
273
|
+
|
274
|
+
static VALUE
|
275
|
+
create_range_error(const char* fmt, ...)
|
276
|
+
{
|
277
|
+
VALUE ret;
|
278
|
+
va_list ap;
|
279
|
+
|
280
|
+
va_start(ap, fmt);
|
281
|
+
ret = rb_exc_new_str(rb_eRangeError, rb_vsprintf(fmt, ap));
|
282
|
+
va_end(ap);
|
283
|
+
|
284
|
+
return ret;
|
285
|
+
}
|
286
|
+
|
287
|
+
#if 0
|
288
|
+
static VALUE
|
289
|
+
create_not_implement_error(const char* fmt, ...)
|
290
|
+
{
|
291
|
+
VALUE ret;
|
292
|
+
va_list ap;
|
293
|
+
|
294
|
+
va_start(ap, fmt);
|
295
|
+
ret = rb_exc_new_str(rb_eNotImpError, rb_vsprintf(fmt, ap));
|
296
|
+
va_end(ap);
|
297
|
+
|
298
|
+
return ret;
|
299
|
+
}
|
300
|
+
#endif
|
301
|
+
|
302
|
+
static VALUE
|
303
|
+
create_memory_error()
|
304
|
+
{
|
305
|
+
return rb_exc_new_str(rb_eRangeError, rb_str_new_cstr("no memory"));
|
306
|
+
}
|
307
|
+
|
308
|
+
void
|
309
|
+
text_info_free(png_text* text, int n)
|
310
|
+
{
|
311
|
+
int i;
|
312
|
+
|
313
|
+
if (text != NULL) {
|
314
|
+
for (i = 0; i < n; i++) {
|
315
|
+
if (text[i].key != NULL) {
|
316
|
+
free(text[i].key);
|
317
|
+
}
|
318
|
+
|
319
|
+
if (text[i].text != NULL) {
|
320
|
+
free(text[i].text);
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
free(text);
|
325
|
+
}
|
326
|
+
}
|
327
|
+
|
328
|
+
static void
|
329
|
+
rb_encoder_mark(void* _ptr)
|
330
|
+
{
|
331
|
+
png_encoder_t* ptr;
|
332
|
+
|
333
|
+
ptr = (png_encoder_t*)_ptr;
|
334
|
+
|
335
|
+
if (ptr->ibuf != Qnil) {
|
336
|
+
rb_gc_mark(ptr->ibuf);
|
337
|
+
}
|
338
|
+
|
339
|
+
if (ptr->obuf != Qnil) {
|
340
|
+
rb_gc_mark(ptr->obuf);
|
341
|
+
}
|
342
|
+
|
343
|
+
if (ptr->error != Qnil) {
|
344
|
+
rb_gc_mark(ptr->error);
|
345
|
+
}
|
346
|
+
|
347
|
+
if (ptr->warn_msg != Qnil) {
|
348
|
+
rb_gc_mark(ptr->warn_msg);
|
349
|
+
}
|
350
|
+
}
|
160
351
|
|
161
352
|
static void
|
162
353
|
rb_encoder_free(void* _ptr)
|
163
354
|
{
|
164
355
|
png_encoder_t* ptr;
|
165
|
-
int i;
|
166
356
|
|
167
357
|
ptr = (png_encoder_t*)_ptr;
|
168
358
|
|
@@ -175,35 +365,70 @@ rb_encoder_free(void* _ptr)
|
|
175
365
|
}
|
176
366
|
|
177
367
|
if (ptr->text != NULL) {
|
178
|
-
|
179
|
-
if (ptr->text[i].key != NULL) {
|
180
|
-
xfree(ptr->text[i].key);
|
181
|
-
}
|
182
|
-
|
183
|
-
if (ptr->text[i].text != NULL) {
|
184
|
-
xfree(ptr->text[i].text);
|
185
|
-
}
|
186
|
-
}
|
368
|
+
text_info_free(ptr->text, ptr->num_text);
|
187
369
|
}
|
188
370
|
|
371
|
+
ptr->ibuf = Qnil;
|
372
|
+
ptr->obuf = Qnil;
|
373
|
+
ptr->error = Qnil;
|
374
|
+
ptr->warn_msg = Qnil;
|
375
|
+
|
189
376
|
free(ptr);
|
190
377
|
}
|
191
378
|
|
192
|
-
static
|
193
|
-
|
379
|
+
static size_t
|
380
|
+
rb_encoder_size(const void* _ptr)
|
194
381
|
{
|
195
|
-
|
382
|
+
size_t ret;
|
383
|
+
png_encoder_t* ptr;
|
384
|
+
int i;
|
196
385
|
|
197
|
-
|
198
|
-
rb_str_buf_cat(buf, (const char *)src, size);
|
199
|
-
}
|
386
|
+
ptr = (png_encoder_t*)_ptr;
|
200
387
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
388
|
+
ret = sizeof(png_encoder_t);
|
389
|
+
// ret += sizeof(png_struct);
|
390
|
+
// ret += sizeof(png_info);
|
391
|
+
ret += (sizeof(png_byte*) * ptr->width);
|
392
|
+
|
393
|
+
ret += sizeof(png_text) * ptr->num_text;
|
394
|
+
|
395
|
+
for (i = 0; i < ptr->num_text; i++) {
|
396
|
+
ret += (strlen(ptr->text[i].key) + ptr->text[i].text_length);
|
397
|
+
}
|
398
|
+
|
399
|
+
return ret;
|
205
400
|
}
|
206
401
|
|
402
|
+
#if RUBY_API_VERSION_CODE > 20600
|
403
|
+
static const rb_data_type_t png_encoder_data_type = {
|
404
|
+
"libpng-ruby encoder object", // wrap_struct_name
|
405
|
+
{
|
406
|
+
rb_encoder_mark, // function.dmark
|
407
|
+
rb_encoder_free, // function.dfree
|
408
|
+
rb_encoder_size, // function.dsize
|
409
|
+
NULL, // function.dcompact
|
410
|
+
{NULL}, // function.reserved
|
411
|
+
},
|
412
|
+
NULL, // parent
|
413
|
+
NULL, // data
|
414
|
+
(VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
|
415
|
+
};
|
416
|
+
#else /* RUBY_API_VERSION_CODE > 20600 */
|
417
|
+
static const rb_data_type_t png_encoder_data_type = {
|
418
|
+
"libpng-ruby encoder object", // wrap_struct_name
|
419
|
+
{
|
420
|
+
rb_encoder_mark, // function.dmark
|
421
|
+
rb_encoder_free, // function.dfree
|
422
|
+
rb_encoder_size, // function.dsize
|
423
|
+
{NULL, NULL}, // function.reserved
|
424
|
+
},
|
425
|
+
NULL, // parent
|
426
|
+
NULL, // data
|
427
|
+
(VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
|
428
|
+
};
|
429
|
+
#endif /* RUBY_API_VERSION_CODE > 20600 */
|
430
|
+
|
431
|
+
|
207
432
|
static VALUE
|
208
433
|
rb_encoder_alloc(VALUE self)
|
209
434
|
{
|
@@ -220,82 +445,125 @@ rb_encoder_alloc(VALUE self)
|
|
220
445
|
ptr->with_time = !0;
|
221
446
|
ptr->gamma = NAN;
|
222
447
|
|
223
|
-
return
|
448
|
+
return TypedData_Wrap_Struct(encoder_klass, &png_encoder_data_type, ptr);
|
224
449
|
}
|
225
450
|
|
226
|
-
static
|
227
|
-
|
451
|
+
static VALUE
|
452
|
+
eval_encoder_opt_pixel_format(png_encoder_t* ptr, VALUE opt)
|
228
453
|
{
|
229
|
-
|
454
|
+
VALUE ret;
|
455
|
+
int type;
|
456
|
+
int comp;
|
457
|
+
|
458
|
+
ret = Qnil;
|
459
|
+
|
460
|
+
switch (TYPE(opt)) {
|
461
|
+
case T_UNDEF:
|
462
|
+
type = PNG_COLOR_TYPE_RGB;
|
463
|
+
comp = 3;
|
464
|
+
break;
|
465
|
+
|
466
|
+
case T_STRING:
|
467
|
+
case T_SYMBOL:
|
230
468
|
if (EQ_STR(opt, "GRAY") || EQ_STR(opt, "GRAYSCALE")) {
|
231
|
-
|
232
|
-
|
469
|
+
type = PNG_COLOR_TYPE_GRAY;
|
470
|
+
comp = 1;
|
233
471
|
|
234
472
|
} else if (EQ_STR(opt, "GA")) {
|
235
|
-
|
236
|
-
|
473
|
+
type = PNG_COLOR_TYPE_GA;
|
474
|
+
comp = 2;
|
237
475
|
|
238
476
|
} else if (EQ_STR(opt, "RGB")) {
|
239
|
-
|
240
|
-
|
477
|
+
type = PNG_COLOR_TYPE_RGB;
|
478
|
+
comp = 3;
|
241
479
|
|
242
480
|
} else if (EQ_STR(opt, "RGBA")) {
|
243
|
-
|
244
|
-
|
481
|
+
type = PNG_COLOR_TYPE_RGBA;
|
482
|
+
comp = 4;
|
245
483
|
|
246
484
|
} else {
|
247
|
-
|
485
|
+
ret = create_argument_error(":pixel_format invalid value");
|
248
486
|
}
|
487
|
+
break;
|
488
|
+
|
489
|
+
default:
|
490
|
+
ret = create_type_error(":pixel_format invalid type");
|
491
|
+
break;
|
249
492
|
}
|
493
|
+
|
494
|
+
if (!RTEST(ret)) {
|
495
|
+
ptr->c_type = type;
|
496
|
+
ptr->num_comp = comp;
|
497
|
+
}
|
498
|
+
|
499
|
+
return ret;
|
250
500
|
}
|
251
501
|
|
252
|
-
static
|
502
|
+
static VALUE
|
253
503
|
eval_encoder_opt_interlace(png_encoder_t* ptr, VALUE opt)
|
254
504
|
{
|
255
|
-
|
505
|
+
switch (TYPE(opt)) {
|
506
|
+
case T_UNDEF:
|
507
|
+
ptr->i_meth = PNG_INTERLACE_NONE;
|
508
|
+
break;
|
509
|
+
|
510
|
+
default:
|
256
511
|
ptr->i_meth = (RTEST(opt))? PNG_INTERLACE_ADAM7: PNG_INTERLACE_NONE;
|
512
|
+
break;
|
257
513
|
}
|
514
|
+
|
515
|
+
return Qnil;
|
258
516
|
}
|
259
517
|
|
260
|
-
static
|
518
|
+
static VALUE
|
261
519
|
eval_encoder_opt_compression(png_encoder_t* ptr, VALUE opt)
|
262
520
|
{
|
263
|
-
|
264
|
-
|
265
|
-
if (opt != Qundef) {
|
266
|
-
switch (TYPE(opt)) {
|
267
|
-
case T_FIXNUM:
|
268
|
-
val = FIX2INT(opt);
|
269
|
-
if (val < 0 || val > 9) {
|
270
|
-
ARGUMENT_ERROR(":compress is out of range");
|
271
|
-
}
|
272
|
-
break;
|
521
|
+
VALUE ret;
|
522
|
+
int lv;
|
273
523
|
|
274
|
-
|
275
|
-
case T_SYMBOL:
|
276
|
-
if (EQ_STR(opt, "NO_COMPRESSION")) {
|
277
|
-
val = Z_NO_COMPRESSION;
|
524
|
+
ret = Qnil;
|
278
525
|
|
279
|
-
|
280
|
-
|
526
|
+
switch (TYPE(opt)) {
|
527
|
+
case T_UNDEF:
|
528
|
+
lv = Z_DEFAULT_COMPRESSION;
|
529
|
+
break;
|
281
530
|
|
282
|
-
|
283
|
-
|
531
|
+
case T_STRING:
|
532
|
+
case T_SYMBOL:
|
533
|
+
if (EQ_STR(opt, "NO_COMPRESSION")) {
|
534
|
+
lv = Z_NO_COMPRESSION;
|
284
535
|
|
285
|
-
|
286
|
-
|
536
|
+
} else if (EQ_STR(opt, "BEST_SPEED")) {
|
537
|
+
lv = Z_BEST_SPEED;
|
287
538
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
539
|
+
} else if (EQ_STR(opt, "BEST_COMPRESSION")) {
|
540
|
+
lv = Z_BEST_COMPRESSION;
|
541
|
+
|
542
|
+
} else if (EQ_STR(opt, "DEFAULT")) {
|
543
|
+
lv = Z_DEFAULT_COMPRESSION;
|
292
544
|
|
293
|
-
|
294
|
-
|
545
|
+
} else {
|
546
|
+
ret = create_argument_error(":compress is invalid value");
|
295
547
|
}
|
548
|
+
break;
|
549
|
+
|
550
|
+
case T_FIXNUM:
|
551
|
+
lv = FIX2INT(opt);
|
552
|
+
if (lv < 0 || lv > 9) {
|
553
|
+
ret = create_range_error(":compress out of range");
|
554
|
+
}
|
555
|
+
break;
|
556
|
+
|
557
|
+
default:
|
558
|
+
ret = create_type_error(":compress invalid type");
|
559
|
+
break;
|
560
|
+
}
|
296
561
|
|
297
|
-
|
562
|
+
if (!RTEST(ret)) {
|
563
|
+
ptr->c_level = lv;
|
298
564
|
}
|
565
|
+
|
566
|
+
return ret;
|
299
567
|
}
|
300
568
|
|
301
569
|
static VALUE
|
@@ -313,302 +581,522 @@ capitalize(VALUE str)
|
|
313
581
|
return rb_ary_join(tmp, rb_str_new_cstr(" "));
|
314
582
|
}
|
315
583
|
|
316
|
-
|
317
|
-
|
584
|
+
struct convert_text_rb2c_arg {
|
585
|
+
VALUE src;
|
586
|
+
png_text* dst;
|
587
|
+
};
|
588
|
+
|
589
|
+
static VALUE
|
590
|
+
convert_text_rb2c(VALUE _arg)
|
318
591
|
{
|
319
|
-
|
320
|
-
|
592
|
+
struct convert_text_rb2c_arg* arg;
|
593
|
+
VALUE src;
|
594
|
+
png_text* dst;
|
595
|
+
VALUE keys;
|
596
|
+
int i;
|
597
|
+
VALUE key;
|
598
|
+
VALUE val;
|
321
599
|
|
322
|
-
|
323
|
-
|
600
|
+
arg = (struct convert_text_rb2c_arg*)_arg;
|
601
|
+
src = arg->src;
|
602
|
+
dst = arg->dst;
|
324
603
|
|
325
|
-
|
326
|
-
|
604
|
+
/*
|
605
|
+
* 途中で例外が発生する可能性があるので資源回収できる様に
|
606
|
+
* 0クリアを最初に済ませておく。
|
607
|
+
*/
|
608
|
+
keys = rb_funcall(src, rb_intern("keys"), 0);
|
327
609
|
|
328
|
-
|
329
|
-
|
610
|
+
for (i = 0; i < RARRAY_LEN(keys); i++) {
|
611
|
+
key = rb_ary_entry(keys, i);
|
612
|
+
val = rb_hash_aref(src, key);
|
330
613
|
|
614
|
+
if (TYPE(key) != T_STRING && TYPE(key) != T_SYMBOL) {
|
615
|
+
ARGUMENT_ERROR(":type is invalid structure");
|
616
|
+
}
|
331
617
|
|
332
|
-
|
618
|
+
if (TYPE(val) != T_STRING && TYPE(val) != T_SYMBOL) {
|
619
|
+
ARGUMENT_ERROR(":type is invalid structure");
|
620
|
+
}
|
621
|
+
|
622
|
+
key = capitalize(key);
|
623
|
+
if (RSTRING_LEN(key) >= 0 && RSTRING_LEN(key) <= 79) {
|
624
|
+
dst[i].compression = PNG_TEXT_COMPRESSION_NONE;
|
625
|
+
dst[i].key = clone_cstr(key);
|
626
|
+
dst[i].text = clone_cstr(val);
|
627
|
+
dst[i].text_length = RSTRING_LEN(val);
|
628
|
+
|
629
|
+
} else {
|
630
|
+
ARGUMENT_ERROR("keyword in :text is too long");
|
631
|
+
}
|
632
|
+
}
|
633
|
+
|
634
|
+
return Qnil;
|
635
|
+
}
|
636
|
+
|
637
|
+
static VALUE
|
333
638
|
eval_encoder_opt_text(png_encoder_t* ptr, VALUE opt)
|
334
639
|
{
|
335
|
-
VALUE
|
336
|
-
VALUE key;
|
337
|
-
VALUE val;
|
338
|
-
int i;
|
640
|
+
VALUE ret;
|
339
641
|
png_text* text;
|
642
|
+
size_t size;
|
643
|
+
struct convert_text_rb2c_arg arg;
|
644
|
+
int state;
|
340
645
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
ARGUMENT_ERROR(":type is invalid structure");
|
371
|
-
}
|
372
|
-
|
373
|
-
key = capitalize(key);
|
374
|
-
if (RSTRING_LEN(key) >= 0 && RSTRING_LEN(key) <= 79) {
|
375
|
-
text[i].compression = PNG_TEXT_COMPRESSION_NONE;
|
376
|
-
text[i].key = clone_cstr(key);
|
377
|
-
text[i].text = clone_cstr(val);
|
378
|
-
text[i].text_length = RSTRING_LEN(val);
|
379
|
-
|
380
|
-
} else {
|
381
|
-
ARGUMENT_ERROR("keyword in :text is too long");
|
382
|
-
}
|
383
|
-
}
|
384
|
-
} else {
|
385
|
-
ARGUMENT_ERROR(":text is invalid value");
|
646
|
+
ret = Qnil;
|
647
|
+
text = NULL;
|
648
|
+
size = 0;
|
649
|
+
state = 0;
|
650
|
+
|
651
|
+
switch (TYPE(opt)) {
|
652
|
+
case T_UNDEF:
|
653
|
+
// ignore
|
654
|
+
break;
|
655
|
+
|
656
|
+
case T_HASH:
|
657
|
+
size = RHASH_SIZE(opt);
|
658
|
+
if (size == 0) break;
|
659
|
+
|
660
|
+
text = (png_text*)malloc(sizeof(png_text) * size);
|
661
|
+
if (text == NULL) {
|
662
|
+
ret = create_memory_error();
|
663
|
+
break;
|
664
|
+
}
|
665
|
+
|
666
|
+
arg.src = opt;
|
667
|
+
arg.dst = text;
|
668
|
+
|
669
|
+
rb_protect(convert_text_rb2c, (VALUE)&arg, &state);
|
670
|
+
|
671
|
+
if (state != 0) {
|
672
|
+
ret = rb_errinfo();
|
673
|
+
rb_set_errinfo(Qnil);
|
674
|
+
text_info_free(text, size);
|
386
675
|
}
|
676
|
+
break;
|
677
|
+
|
678
|
+
default:
|
679
|
+
ret = create_type_error(":text invalid type");
|
680
|
+
break;
|
387
681
|
}
|
682
|
+
|
683
|
+
if (!RTEST(ret)) {
|
684
|
+
ptr->text = text;
|
685
|
+
ptr->num_text = size;
|
686
|
+
}
|
687
|
+
|
688
|
+
return ret;
|
388
689
|
}
|
389
690
|
|
390
|
-
static
|
691
|
+
static VALUE
|
391
692
|
eval_encoder_opt_time(png_encoder_t* ptr, VALUE opt)
|
392
693
|
{
|
393
|
-
|
694
|
+
switch (TYPE(opt)) {
|
695
|
+
case T_UNDEF:
|
696
|
+
ptr->with_time = !0;
|
697
|
+
break;
|
698
|
+
|
699
|
+
default:
|
394
700
|
ptr->with_time = RTEST(opt);
|
701
|
+
break;
|
395
702
|
}
|
703
|
+
|
704
|
+
return Qnil;
|
396
705
|
}
|
397
706
|
|
398
|
-
static
|
707
|
+
static VALUE
|
399
708
|
eval_encoder_opt_gamma(png_encoder_t* ptr, VALUE opt)
|
400
709
|
{
|
401
|
-
|
402
|
-
|
710
|
+
VALUE ret;
|
711
|
+
double gamma;
|
712
|
+
|
713
|
+
ret = Qnil;
|
714
|
+
|
715
|
+
switch (TYPE(opt)) {
|
716
|
+
case T_UNDEF:
|
717
|
+
gamma = NAN;
|
718
|
+
break;
|
719
|
+
|
720
|
+
case T_FIXNUM:
|
721
|
+
case T_FLOAT:
|
722
|
+
case T_RATIONAL:
|
723
|
+
gamma = NUM2DBL(opt);
|
724
|
+
break;
|
725
|
+
|
726
|
+
default:
|
727
|
+
ret = create_type_error(":gamma invalid type");
|
728
|
+
break;
|
729
|
+
}
|
730
|
+
|
731
|
+
if (!RTEST(ret)) ptr->gamma = gamma;
|
732
|
+
|
733
|
+
return ret;
|
734
|
+
}
|
735
|
+
|
736
|
+
static VALUE
|
737
|
+
eval_encoder_opt_stride(png_encoder_t* ptr, VALUE opt)
|
738
|
+
{
|
739
|
+
VALUE ret;
|
740
|
+
png_uint_32 stride;
|
741
|
+
|
742
|
+
ret = Qnil;
|
743
|
+
|
744
|
+
switch (TYPE(opt)) {
|
745
|
+
case T_UNDEF:
|
746
|
+
stride = ptr->width * ptr->num_comp;
|
747
|
+
break;
|
748
|
+
|
749
|
+
case T_FIXNUM:
|
750
|
+
if (FIX2LONG(opt) >= (ptr->width * ptr->num_comp)) {
|
751
|
+
stride = FIX2LONG(opt);
|
752
|
+
|
753
|
+
} else {
|
754
|
+
ret = create_argument_error(":stride too little");
|
755
|
+
}
|
756
|
+
break;
|
757
|
+
|
758
|
+
default:
|
759
|
+
ret = create_type_error(":stride invalid type");
|
760
|
+
break;
|
761
|
+
}
|
762
|
+
|
763
|
+
if (!RTEST(ret)) ptr->stride = stride;
|
764
|
+
|
765
|
+
return ret;
|
766
|
+
}
|
767
|
+
|
768
|
+
static void
|
769
|
+
encode_error(png_structp ctx, png_const_charp msg)
|
770
|
+
{
|
771
|
+
png_encoder_t* ptr;
|
772
|
+
|
773
|
+
ptr = (png_encoder_t*)png_get_error_ptr(ctx);
|
774
|
+
|
775
|
+
ptr->error = create_runtime_error("encode error:%s", msg);
|
776
|
+
|
777
|
+
longjmp(png_jmpbuf(ptr->ctx), 1);
|
778
|
+
}
|
779
|
+
|
780
|
+
static void
|
781
|
+
encode_warn(png_structp ctx, png_const_charp msg)
|
782
|
+
{
|
783
|
+
png_encoder_t* ptr;
|
784
|
+
|
785
|
+
ptr = (png_encoder_t*)png_get_error_ptr(ctx);
|
786
|
+
|
787
|
+
if (ptr->warn_msg != Qnil) {
|
788
|
+
ptr->warn_msg = rb_ary_new();
|
403
789
|
}
|
790
|
+
|
791
|
+
rb_ary_push(ptr->warn_msg, rb_str_new_cstr(msg));
|
404
792
|
}
|
405
793
|
|
406
|
-
static
|
794
|
+
static VALUE
|
407
795
|
set_encoder_context(png_encoder_t* ptr, int wd, int ht, VALUE opt)
|
408
796
|
{
|
797
|
+
VALUE ret;
|
798
|
+
|
409
799
|
png_structp ctx;
|
410
800
|
png_infop info;
|
801
|
+
png_byte** rows;
|
802
|
+
|
411
803
|
VALUE opts[N(encoder_opt_ids)];
|
412
804
|
|
413
|
-
|
414
|
-
|
805
|
+
/*
|
806
|
+
* initialize
|
807
|
+
*/
|
808
|
+
ret = Qnil;
|
809
|
+
ctx = NULL;
|
810
|
+
info = NULL;
|
811
|
+
rows = NULL;
|
415
812
|
|
416
813
|
/*
|
417
|
-
*
|
814
|
+
* argument check
|
418
815
|
*/
|
419
|
-
|
816
|
+
do {
|
817
|
+
if (wd <= 0) {
|
818
|
+
ret = create_range_error("image width less equal zero");
|
819
|
+
break;
|
820
|
+
}
|
821
|
+
|
822
|
+
if (ht <= 0) {
|
823
|
+
ret = create_range_error("image height less equal zero");
|
824
|
+
break;
|
825
|
+
}
|
826
|
+
} while (0);
|
420
827
|
|
421
828
|
/*
|
422
|
-
*
|
829
|
+
* parse options
|
423
830
|
*/
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
831
|
+
if (!RTEST(ret)) do {
|
832
|
+
rb_get_kwargs(opt, encoder_opt_ids, 0, N(encoder_opt_ids), opts);
|
833
|
+
|
834
|
+
// オプション評価で使用するので前もって設定しておく
|
835
|
+
ptr->width = wd;
|
836
|
+
ptr->height = ht;
|
837
|
+
|
838
|
+
ret = eval_encoder_opt_pixel_format(ptr, opts[0]);
|
839
|
+
if (RTEST(ret)) break;
|
840
|
+
|
841
|
+
ret = eval_encoder_opt_interlace(ptr, opts[1]);
|
842
|
+
if (RTEST(ret)) break;
|
843
|
+
|
844
|
+
ret = eval_encoder_opt_compression(ptr, opts[2]);
|
845
|
+
if (RTEST(ret)) break;
|
846
|
+
|
847
|
+
ret = eval_encoder_opt_text(ptr, opts[3]);
|
848
|
+
if (RTEST(ret)) break;
|
849
|
+
|
850
|
+
ret = eval_encoder_opt_time(ptr, opts[4]);
|
851
|
+
if (RTEST(ret)) break;
|
852
|
+
|
853
|
+
ret = eval_encoder_opt_gamma(ptr, opts[5]);
|
854
|
+
if (RTEST(ret)) break;
|
855
|
+
|
856
|
+
ret = eval_encoder_opt_stride(ptr, opts[6]);
|
857
|
+
if (RTEST(ret)) break;
|
858
|
+
} while (0);
|
430
859
|
|
431
860
|
/*
|
432
861
|
* create PNG context
|
433
862
|
*/
|
434
|
-
do {
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
ctx = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
863
|
+
if (!RTEST(ret)) do {
|
864
|
+
ctx = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
865
|
+
ptr,
|
866
|
+
encode_error,
|
867
|
+
encode_warn);
|
440
868
|
if (ctx == NULL) {
|
441
|
-
|
869
|
+
ret = create_runtime_error("png_create_read_struct() failed");
|
442
870
|
break;
|
443
871
|
}
|
444
872
|
|
445
873
|
info = png_create_info_struct(ctx);
|
446
874
|
if (info == NULL) {
|
447
|
-
|
875
|
+
ret = create_runtime_error("png_create_info_structt() failed");
|
448
876
|
break;
|
449
877
|
}
|
450
878
|
|
451
879
|
rows = png_malloc(ctx, ht * sizeof(png_byte*));
|
452
880
|
if (rows == NULL) {
|
453
|
-
|
881
|
+
ret = create_memory_error("png_malloc() failed");
|
454
882
|
break;
|
455
883
|
}
|
456
884
|
|
457
885
|
memset(rows, 0, ht * sizeof(png_byte*));
|
458
886
|
|
459
|
-
ptr->
|
460
|
-
ptr->
|
461
|
-
ptr->
|
462
|
-
ptr->
|
463
|
-
ptr->
|
464
|
-
ptr->
|
465
|
-
ptr->
|
466
|
-
|
887
|
+
ptr->data_size = ptr->stride * ptr->height;
|
888
|
+
ptr->ctx = ctx;
|
889
|
+
ptr->info = info;
|
890
|
+
ptr->rows = rows;
|
891
|
+
ptr->ibuf = Qnil;
|
892
|
+
ptr->obuf = Qnil;
|
893
|
+
ptr->error = Qnil;
|
894
|
+
ptr->warn_msg = Qnil;
|
467
895
|
} while(0);
|
468
896
|
|
469
897
|
/*
|
470
898
|
* post process
|
471
899
|
*/
|
472
|
-
if (
|
473
|
-
if (ctx != NULL)
|
474
|
-
|
475
|
-
}
|
476
|
-
|
477
|
-
if (rows != NULL) {
|
478
|
-
png_free(ctx, rows);
|
479
|
-
}
|
900
|
+
if (RTEST(ret)) {
|
901
|
+
if (ctx != NULL) png_destroy_write_struct(&ctx, &info);
|
902
|
+
if (rows != NULL) png_free(ctx, rows);
|
480
903
|
}
|
904
|
+
|
905
|
+
return ret;
|
481
906
|
}
|
482
907
|
|
483
908
|
static VALUE
|
484
909
|
rb_encoder_initialize(int argc, VALUE* argv, VALUE self)
|
485
910
|
{
|
486
911
|
png_encoder_t* ptr;
|
912
|
+
VALUE exc;
|
487
913
|
VALUE wd;
|
488
914
|
VALUE ht;
|
489
915
|
VALUE opts;
|
490
916
|
|
917
|
+
/*
|
918
|
+
* initialize
|
919
|
+
*/
|
920
|
+
exc = Qnil;
|
921
|
+
|
491
922
|
/*
|
492
923
|
* strip object
|
493
924
|
*/
|
494
|
-
|
925
|
+
TypedData_Get_Struct(self, png_encoder_t, &png_encoder_data_type, ptr);
|
495
926
|
|
496
927
|
/*
|
497
928
|
* parse argument
|
498
929
|
*/
|
499
|
-
rb_scan_args(argc, argv, "
|
930
|
+
rb_scan_args(argc, argv, "2:", &wd, &ht, &opts);
|
500
931
|
|
501
|
-
|
502
|
-
|
503
|
-
|
932
|
+
/*
|
933
|
+
* check argument
|
934
|
+
*/
|
935
|
+
do {
|
936
|
+
if (TYPE(wd) != T_FIXNUM) {
|
937
|
+
exc = create_argument_error("invalid width");
|
938
|
+
break;
|
939
|
+
}
|
504
940
|
|
941
|
+
if (TYPE(ht) != T_FIXNUM) {
|
942
|
+
exc = create_argument_error("invalid height");
|
943
|
+
break;
|
944
|
+
}
|
945
|
+
} while (0);
|
505
946
|
|
506
947
|
/*
|
507
948
|
* set context
|
508
949
|
*/
|
509
|
-
|
950
|
+
if (!RTEST(exc)) {
|
951
|
+
exc = set_encoder_context(ptr, FIX2INT(wd), FIX2INT(ht), opts);
|
952
|
+
}
|
953
|
+
|
954
|
+
/*
|
955
|
+
* post process
|
956
|
+
*/
|
957
|
+
if (RTEST(exc)) rb_exc_raise(exc);
|
510
958
|
|
511
959
|
return self;
|
512
960
|
}
|
513
961
|
|
962
|
+
static VALUE
|
963
|
+
do_encode(VALUE arg)
|
964
|
+
{
|
965
|
+
png_encoder_t* ptr;
|
966
|
+
png_uint_32 i;
|
967
|
+
png_byte* bytes;
|
968
|
+
|
969
|
+
/*
|
970
|
+
* initialize
|
971
|
+
*/
|
972
|
+
ptr = (png_encoder_t*)arg;
|
973
|
+
|
974
|
+
if (setjmp(png_jmpbuf(ptr->ctx))) {
|
975
|
+
rb_exc_raise(ptr->error);
|
976
|
+
|
977
|
+
} else {
|
978
|
+
png_set_IHDR(ptr->ctx,
|
979
|
+
ptr->info,
|
980
|
+
ptr->width,
|
981
|
+
ptr->height,
|
982
|
+
8,
|
983
|
+
ptr->c_type,
|
984
|
+
ptr->i_meth,
|
985
|
+
PNG_COMPRESSION_TYPE_BASE,
|
986
|
+
PNG_FILTER_TYPE_BASE);
|
987
|
+
|
988
|
+
if (ptr->text) {
|
989
|
+
png_set_text(ptr->ctx, ptr->info, ptr->text, ptr->num_text);
|
990
|
+
}
|
991
|
+
|
992
|
+
if (ptr->with_time) {
|
993
|
+
time_t tm;
|
994
|
+
png_time png_time;
|
995
|
+
|
996
|
+
time(&tm);
|
997
|
+
png_convert_from_time_t(&png_time, tm);
|
998
|
+
png_set_tIME(ptr->ctx, ptr->info, &png_time);
|
999
|
+
}
|
1000
|
+
|
1001
|
+
if (!isnan(ptr->gamma)) {
|
1002
|
+
png_set_gAMA(ptr->ctx, ptr->info, ptr->gamma);
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
png_set_compression_level(ptr->ctx, ptr->c_level);
|
1006
|
+
|
1007
|
+
png_set_write_fn(ptr->ctx,
|
1008
|
+
(png_voidp)ptr->obuf,
|
1009
|
+
(png_rw_ptr)mem_io_write_data,
|
1010
|
+
(png_flush_ptr)mem_io_flush);
|
1011
|
+
|
1012
|
+
bytes = (png_byte*)RSTRING_PTR(ptr->ibuf);
|
1013
|
+
for (i = 0; i < ptr->height; i++) {
|
1014
|
+
ptr->rows[i] = bytes;
|
1015
|
+
bytes += ptr->stride;
|
1016
|
+
}
|
1017
|
+
|
1018
|
+
png_set_rows(ptr->ctx, ptr->info, ptr->rows);
|
1019
|
+
png_write_png(ptr->ctx, ptr->info, PNG_TRANSFORM_IDENTITY, NULL);
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
return Qnil;
|
1023
|
+
}
|
1024
|
+
|
514
1025
|
static VALUE
|
515
1026
|
rb_encoder_encode(VALUE self, VALUE data)
|
516
1027
|
{
|
517
1028
|
VALUE ret;
|
1029
|
+
VALUE exc;
|
518
1030
|
png_encoder_t* ptr;
|
519
|
-
|
520
|
-
uint8_t* p;
|
1031
|
+
int state;
|
521
1032
|
|
522
1033
|
/*
|
523
1034
|
* initialize
|
524
1035
|
*/
|
525
|
-
ret
|
1036
|
+
ret = rb_str_buf_new(0);
|
1037
|
+
exc = Qnil;
|
1038
|
+
state = 0;
|
526
1039
|
|
527
1040
|
/*
|
528
1041
|
* strip object
|
529
1042
|
*/
|
530
|
-
|
1043
|
+
TypedData_Get_Struct(self, png_encoder_t, &png_encoder_data_type, ptr);
|
531
1044
|
|
532
1045
|
/*
|
533
1046
|
* argument check
|
534
1047
|
*/
|
535
1048
|
Check_Type(data, T_STRING);
|
536
|
-
if (RSTRING_LEN(data) != ptr->pixels) {
|
537
|
-
ARGUMENT_ERROR("invalid data size");
|
538
|
-
}
|
539
|
-
|
540
|
-
/*
|
541
|
-
* call libpng
|
542
|
-
*/
|
543
|
-
png_set_IHDR(ptr->ctx,
|
544
|
-
ptr->info,
|
545
|
-
ptr->width,
|
546
|
-
ptr->height,
|
547
|
-
8,
|
548
|
-
ptr->c_type,
|
549
|
-
ptr->i_meth,
|
550
|
-
PNG_COMPRESSION_TYPE_BASE,
|
551
|
-
PNG_FILTER_TYPE_BASE);
|
552
|
-
|
553
|
-
if (ptr->text) {
|
554
|
-
png_set_text(ptr->ctx, ptr->info, ptr->text, ptr->num_text);
|
555
|
-
}
|
556
|
-
|
557
|
-
if (ptr->with_time) {
|
558
|
-
time_t tm;
|
559
|
-
png_time png_time;
|
560
1049
|
|
561
|
-
|
562
|
-
|
563
|
-
png_set_tIME(ptr->ctx, ptr->info, &png_time);
|
1050
|
+
if (RSTRING_LEN(data) < ptr->data_size) {
|
1051
|
+
ARGUMENT_ERROR("image data too short");
|
564
1052
|
}
|
565
1053
|
|
566
|
-
if (
|
567
|
-
|
1054
|
+
if (RSTRING_LEN(data) > ptr->data_size) {
|
1055
|
+
ARGUMENT_ERROR("image data too large");
|
568
1056
|
}
|
569
1057
|
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
(png_rw_ptr)mem_io_write_data,
|
575
|
-
(png_flush_ptr)mem_io_flush);
|
1058
|
+
/*
|
1059
|
+
* prepare
|
1060
|
+
*/
|
1061
|
+
SET_DATA(ptr, data, ret);
|
576
1062
|
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
1063
|
+
/*
|
1064
|
+
* do encode
|
1065
|
+
*/
|
1066
|
+
if (!RTEST(exc)) {
|
1067
|
+
rb_protect(do_encode, (VALUE)ptr, &state);
|
581
1068
|
}
|
582
1069
|
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
}
|
589
|
-
|
1070
|
+
/*
|
1071
|
+
* post process
|
1072
|
+
*/
|
1073
|
+
if(state == 0) {
|
1074
|
+
rb_ivar_set(ret, rb_intern("warn"), ptr->warn_msg);
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
CLR_DATA(ptr);
|
1078
|
+
|
1079
|
+
if (state != 0) {
|
1080
|
+
rb_jump_tag(state);
|
590
1081
|
}
|
591
1082
|
|
1083
|
+
/*
|
1084
|
+
* post process
|
1085
|
+
*/
|
1086
|
+
ptr->ibuf = Qnil;
|
1087
|
+
ptr->obuf = Qnil;
|
1088
|
+
|
1089
|
+
if (RTEST(exc)) rb_exc_raise(exc);
|
1090
|
+
|
592
1091
|
return ret;
|
593
1092
|
}
|
594
1093
|
|
595
1094
|
static void
|
596
|
-
|
1095
|
+
rb_decoder_mark(void* _ptr)
|
597
1096
|
{
|
598
|
-
|
599
|
-
|
600
|
-
io = (mem_io_t*)png_get_io_ptr(ctx);
|
601
|
-
|
602
|
-
if (io->pos + rq_size <= io->size) {
|
603
|
-
memcpy(dst, io->ptr + io->pos, rq_size);
|
604
|
-
io->pos += rq_size;
|
605
|
-
|
606
|
-
} else {
|
607
|
-
png_error(ctx, "data not enough.");
|
608
|
-
}
|
1097
|
+
// nothing
|
609
1098
|
}
|
610
1099
|
|
611
|
-
|
612
1100
|
static void
|
613
1101
|
rb_decoder_free(void* _ptr)
|
614
1102
|
{
|
@@ -637,6 +1125,45 @@ rb_decoder_free(void* _ptr)
|
|
637
1125
|
free(ptr);
|
638
1126
|
}
|
639
1127
|
|
1128
|
+
static size_t
|
1129
|
+
rb_decoder_size(const void* _ptr)
|
1130
|
+
{
|
1131
|
+
size_t ret;
|
1132
|
+
|
1133
|
+
ret = sizeof(png_decoder_t);
|
1134
|
+
|
1135
|
+
return ret;
|
1136
|
+
}
|
1137
|
+
|
1138
|
+
#if RUBY_API_VERSION_CODE > 20600
|
1139
|
+
static const rb_data_type_t png_decoder_data_type = {
|
1140
|
+
"libpng-ruby decoder object", // wrap_struct_name
|
1141
|
+
{
|
1142
|
+
rb_decoder_mark, // function.dmark
|
1143
|
+
rb_decoder_free, // function.dfree
|
1144
|
+
rb_decoder_size, // function.dsize
|
1145
|
+
NULL, // function.dcompact
|
1146
|
+
{NULL}, // function.reserved
|
1147
|
+
},
|
1148
|
+
NULL, // parent
|
1149
|
+
NULL, // data
|
1150
|
+
(VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
|
1151
|
+
};
|
1152
|
+
#else /* RUBY_API_VERSION_CODE > 20600 */
|
1153
|
+
static const rb_data_type_t png_decoder_data_type = {
|
1154
|
+
"libpng-ruby decoder object", // wrap_struct_name
|
1155
|
+
{
|
1156
|
+
rb_decoder_mark, // function.dmark
|
1157
|
+
rb_decoder_free, // function.dfree
|
1158
|
+
rb_decoder_size, // function.dsize
|
1159
|
+
{NULL, NULL}, // function.reserved
|
1160
|
+
},
|
1161
|
+
NULL, // parent
|
1162
|
+
NULL, // data
|
1163
|
+
(VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
|
1164
|
+
};
|
1165
|
+
#endif /* RUBY_API_VERSION_CODE > 20600 */
|
1166
|
+
|
640
1167
|
static VALUE
|
641
1168
|
rb_decoder_alloc(VALUE self)
|
642
1169
|
{
|
@@ -650,35 +1177,60 @@ rb_decoder_alloc(VALUE self)
|
|
650
1177
|
ptr->common.need_meta = !0;
|
651
1178
|
ptr->common.display_gamma = NAN;
|
652
1179
|
|
653
|
-
return
|
1180
|
+
return TypedData_Wrap_Struct(decoder_klass, &png_decoder_data_type, ptr);
|
654
1181
|
}
|
655
1182
|
|
656
|
-
static
|
1183
|
+
static VALUE
|
657
1184
|
eval_decoder_opt_api_type(png_decoder_t* ptr, VALUE opt)
|
658
1185
|
{
|
659
|
-
|
1186
|
+
VALUE ret;
|
1187
|
+
int type;
|
660
1188
|
|
661
|
-
|
1189
|
+
ret = Qnil;
|
1190
|
+
|
1191
|
+
switch (TYPE(opt)) {
|
1192
|
+
case T_UNDEF:
|
1193
|
+
type = API_SIMPLIFIED;
|
1194
|
+
break;
|
1195
|
+
|
1196
|
+
case T_STRING:
|
1197
|
+
case T_SYMBOL:
|
662
1198
|
if (EQ_STR(opt, "simplified")) {
|
663
|
-
|
1199
|
+
type = API_SIMPLIFIED;
|
664
1200
|
|
665
1201
|
} else if (EQ_STR(opt, "classic")) {
|
666
|
-
|
1202
|
+
type = API_CLASSIC;
|
667
1203
|
|
668
1204
|
} else {
|
669
|
-
|
1205
|
+
ret = create_argument_error(":api_type invalid value");
|
670
1206
|
}
|
1207
|
+
break;
|
671
1208
|
|
672
|
-
|
1209
|
+
default:
|
1210
|
+
ret = create_type_error(":api_type invalid type");
|
1211
|
+
break;
|
673
1212
|
}
|
1213
|
+
|
1214
|
+
if (!RTEST(ret)) ptr->common.api_type = type;
|
1215
|
+
|
1216
|
+
return ret;
|
674
1217
|
}
|
675
1218
|
|
676
|
-
static
|
1219
|
+
static VALUE
|
677
1220
|
eval_decoder_opt_pixel_format(png_decoder_t* ptr, VALUE opt)
|
678
1221
|
{
|
1222
|
+
VALUE ret;
|
679
1223
|
int format;
|
680
1224
|
|
681
|
-
|
1225
|
+
ret = Qnil;
|
1226
|
+
|
1227
|
+
switch (TYPE(opt)) {
|
1228
|
+
case T_UNDEF:
|
1229
|
+
format = PNG_FORMAT_RGB;
|
1230
|
+
break;
|
1231
|
+
|
1232
|
+
case T_STRING:
|
1233
|
+
case T_SYMBOL:
|
682
1234
|
if (EQ_STR(opt, "GRAY") || EQ_STR(opt, "GRAYSCALE")) {
|
683
1235
|
format = PNG_FORMAT_GRAY;
|
684
1236
|
|
@@ -707,97 +1259,179 @@ eval_decoder_opt_pixel_format(png_decoder_t* ptr, VALUE opt)
|
|
707
1259
|
format = PNG_FORMAT_ABGR;
|
708
1260
|
|
709
1261
|
} else {
|
710
|
-
|
1262
|
+
ret = create_argument_error(":pixel_format invalid value");
|
711
1263
|
}
|
1264
|
+
break;
|
712
1265
|
|
713
|
-
|
1266
|
+
default:
|
1267
|
+
ret = create_type_error(":pixel_format invalid type");
|
1268
|
+
break;
|
714
1269
|
}
|
1270
|
+
|
1271
|
+
if (!RTEST(ret)) ptr->common.format = format;
|
1272
|
+
|
1273
|
+
return ret;
|
715
1274
|
}
|
716
1275
|
|
717
|
-
static
|
1276
|
+
static VALUE
|
718
1277
|
eval_decoder_opt_without_meta(png_decoder_t* ptr, VALUE opt)
|
719
1278
|
{
|
720
|
-
|
1279
|
+
switch (TYPE(opt)) {
|
1280
|
+
case T_UNDEF:
|
1281
|
+
ptr->common.need_meta = !0;
|
1282
|
+
break;
|
1283
|
+
|
1284
|
+
default:
|
721
1285
|
ptr->common.need_meta = !RTEST(opt);
|
1286
|
+
break;
|
722
1287
|
}
|
1288
|
+
|
1289
|
+
return Qnil;
|
723
1290
|
}
|
724
1291
|
|
725
|
-
static
|
1292
|
+
static VALUE
|
726
1293
|
eval_decoder_opt_display_gamma(png_decoder_t* ptr, VALUE opt)
|
727
1294
|
{
|
728
|
-
|
1295
|
+
switch (TYPE(opt)) {
|
1296
|
+
case T_UNDEF:
|
1297
|
+
ptr->common.display_gamma = NAN;
|
1298
|
+
break;
|
1299
|
+
|
1300
|
+
default:
|
729
1301
|
ptr->common.display_gamma = NUM2DBL(opt);
|
1302
|
+
break;
|
730
1303
|
}
|
1304
|
+
|
1305
|
+
return Qnil;
|
731
1306
|
}
|
732
1307
|
|
733
|
-
static
|
1308
|
+
static VALUE
|
734
1309
|
set_decoder_context(png_decoder_t* ptr, VALUE opt)
|
735
1310
|
{
|
1311
|
+
VALUE ret;
|
736
1312
|
VALUE opts[N(decoder_opt_ids)];
|
737
1313
|
|
738
1314
|
/*
|
739
|
-
*
|
1315
|
+
* initialize
|
740
1316
|
*/
|
741
|
-
|
1317
|
+
ret = Qnil;
|
742
1318
|
|
743
1319
|
/*
|
744
|
-
*
|
1320
|
+
* parse options
|
745
1321
|
*/
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
1322
|
+
do {
|
1323
|
+
rb_get_kwargs(opt, decoder_opt_ids, 0, N(decoder_opt_ids), opts);
|
1324
|
+
|
1325
|
+
ret = eval_decoder_opt_api_type(ptr, opts[2]);
|
1326
|
+
if (RTEST(ret)) break;
|
1327
|
+
|
1328
|
+
ret = eval_decoder_opt_pixel_format(ptr, opts[0]);
|
1329
|
+
if (RTEST(ret)) break;
|
1330
|
+
|
1331
|
+
ret = eval_decoder_opt_without_meta(ptr, opts[1]);
|
1332
|
+
if (RTEST(ret)) break;
|
1333
|
+
|
1334
|
+
ret = eval_decoder_opt_display_gamma(ptr, opts[3]);
|
1335
|
+
if (RTEST(ret)) break;
|
1336
|
+
} while (0);
|
1337
|
+
|
1338
|
+
return ret;
|
750
1339
|
}
|
751
1340
|
|
752
1341
|
static VALUE
|
753
1342
|
rb_decoder_initialize(int argc, VALUE* argv, VALUE self)
|
754
1343
|
{
|
755
1344
|
png_decoder_t* ptr;
|
756
|
-
VALUE
|
1345
|
+
VALUE exc;
|
1346
|
+
VALUE opts;
|
1347
|
+
|
1348
|
+
/*
|
1349
|
+
* initialize
|
1350
|
+
*/
|
1351
|
+
exc = Qnil;
|
757
1352
|
|
758
1353
|
/*
|
759
1354
|
* strip object
|
760
1355
|
*/
|
761
|
-
|
1356
|
+
TypedData_Get_Struct(self, png_decoder_t, &png_decoder_data_type, ptr);
|
762
1357
|
|
763
1358
|
/*
|
764
1359
|
* parse argument
|
765
1360
|
*/
|
766
|
-
rb_scan_args(argc, argv, "
|
767
|
-
if (opt != Qnil) Check_Type(opt, T_HASH);
|
1361
|
+
rb_scan_args(argc, argv, "0:", &opts);
|
768
1362
|
|
769
1363
|
/*
|
770
1364
|
* set context
|
771
1365
|
*/
|
772
|
-
set_decoder_context(ptr,
|
1366
|
+
exc = set_decoder_context(ptr, opts);
|
1367
|
+
|
1368
|
+
/*
|
1369
|
+
* post process
|
1370
|
+
*/
|
1371
|
+
if (RTEST(exc)) rb_exc_raise(exc);
|
773
1372
|
|
774
1373
|
return Qtrue;
|
775
1374
|
}
|
776
1375
|
|
1376
|
+
static void
|
1377
|
+
decode_error(png_structp ctx, png_const_charp msg)
|
1378
|
+
{
|
1379
|
+
png_decoder_t* ptr;
|
1380
|
+
|
1381
|
+
ptr = (png_decoder_t*)png_get_error_ptr(ctx);
|
1382
|
+
|
1383
|
+
ptr->common.error = create_runtime_error("decode error:%s", msg);
|
1384
|
+
|
1385
|
+
longjmp(png_jmpbuf(ptr->classic.ctx), 1);
|
1386
|
+
}
|
1387
|
+
|
1388
|
+
static void
|
1389
|
+
decode_warn(png_structp ctx, png_const_charp msg)
|
1390
|
+
{
|
1391
|
+
png_decoder_t* ptr;
|
1392
|
+
|
1393
|
+
ptr = (png_decoder_t*)png_get_error_ptr(ctx);
|
1394
|
+
|
1395
|
+
if (ptr->common.warn_msg != Qnil) {
|
1396
|
+
ptr->common.warn_msg = rb_ary_new();
|
1397
|
+
}
|
1398
|
+
|
1399
|
+
rb_ary_push(ptr->common.warn_msg, rb_str_new_cstr(msg));
|
1400
|
+
}
|
1401
|
+
|
1402
|
+
|
777
1403
|
static void
|
778
1404
|
set_read_context(png_decoder_t* ptr, VALUE data)
|
779
1405
|
{
|
1406
|
+
VALUE exc;
|
780
1407
|
png_structp ctx;
|
781
1408
|
png_infop fsi;
|
782
1409
|
png_infop bsi;
|
783
1410
|
|
784
|
-
const char* err;
|
785
|
-
|
786
1411
|
do {
|
787
|
-
|
1412
|
+
exc = Qnil;
|
1413
|
+
ctx = NULL;
|
788
1414
|
fsi = NULL;
|
789
1415
|
bsi = NULL;
|
790
1416
|
|
791
|
-
ctx = png_create_read_struct(PNG_LIBPNG_VER_STRING,
|
1417
|
+
ctx = png_create_read_struct(PNG_LIBPNG_VER_STRING,
|
1418
|
+
ptr,
|
1419
|
+
decode_error,
|
1420
|
+
decode_warn);
|
792
1421
|
if (ctx == NULL) {
|
793
|
-
|
1422
|
+
exc = create_runtime_error("png_create_read_struct() failed");
|
794
1423
|
break;
|
795
1424
|
}
|
796
1425
|
|
797
1426
|
fsi = png_create_info_struct(ctx);
|
1427
|
+
if (fsi == NULL) {
|
1428
|
+
exc = create_runtime_error("png_create_info_struct() failed");
|
1429
|
+
break;
|
1430
|
+
}
|
1431
|
+
|
798
1432
|
bsi = png_create_info_struct(ctx);
|
799
|
-
if (
|
800
|
-
|
1433
|
+
if (bsi == NULL) {
|
1434
|
+
exc = create_runtime_error("png_create_info_struct() failed");
|
801
1435
|
break;
|
802
1436
|
}
|
803
1437
|
|
@@ -809,22 +1443,17 @@ set_read_context(png_decoder_t* ptr, VALUE data)
|
|
809
1443
|
ptr->classic.io.size = RSTRING_LEN(data);
|
810
1444
|
ptr->classic.io.pos = 0;
|
811
1445
|
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
} else {
|
816
|
-
png_set_read_fn(ptr->classic.ctx,
|
817
|
-
(png_voidp)&ptr->classic.io,
|
818
|
-
(png_rw_ptr)mem_io_read_data);
|
819
|
-
}
|
1446
|
+
png_set_read_fn(ptr->classic.ctx,
|
1447
|
+
(png_voidp)&ptr->classic.io,
|
1448
|
+
(png_rw_ptr)mem_io_read_data);
|
820
1449
|
} while(0);
|
821
1450
|
|
822
|
-
if (
|
1451
|
+
if (RTEST(exc)) {
|
823
1452
|
if (ctx != NULL) {
|
824
1453
|
png_destroy_read_struct(&ctx, &fsi, &bsi);
|
825
1454
|
}
|
826
1455
|
|
827
|
-
|
1456
|
+
rb_exc_raise(exc);
|
828
1457
|
}
|
829
1458
|
}
|
830
1459
|
|
@@ -1164,8 +1793,13 @@ read_header_body(VALUE _arg)
|
|
1164
1793
|
/*
|
1165
1794
|
* read header
|
1166
1795
|
*/
|
1167
|
-
|
1168
|
-
|
1796
|
+
if (setjmp(png_jmpbuf(ptr->classic.ctx))) {
|
1797
|
+
rb_exc_raise(ptr->common.error);
|
1798
|
+
|
1799
|
+
} else {
|
1800
|
+
png_read_info(ptr->classic.ctx, ptr->classic.fsi);
|
1801
|
+
get_header_info(ptr);
|
1802
|
+
}
|
1169
1803
|
|
1170
1804
|
return create_meta(ptr);
|
1171
1805
|
}
|
@@ -1201,7 +1835,7 @@ rb_decoder_read_header(VALUE self, VALUE data)
|
|
1201
1835
|
/*
|
1202
1836
|
* strip object
|
1203
1837
|
*/
|
1204
|
-
|
1838
|
+
TypedData_Get_Struct(self, png_decoder_t, &png_decoder_data_type, ptr);
|
1205
1839
|
|
1206
1840
|
/*
|
1207
1841
|
* call read header funciton
|
@@ -1330,61 +1964,66 @@ decode_classic_api_body(VALUE _arg)
|
|
1330
1964
|
/*
|
1331
1965
|
* read basic info
|
1332
1966
|
*/
|
1333
|
-
|
1967
|
+
if (setjmp(png_jmpbuf(ptr->classic.ctx))) {
|
1968
|
+
rb_exc_raise(ptr->common.error);
|
1334
1969
|
|
1335
|
-
|
1336
|
-
|
1337
|
-
*/
|
1338
|
-
if (!isnan(ptr->common.display_gamma)) {
|
1339
|
-
if (!png_get_gAMA(ptr->classic.ctx, ptr->classic.fsi, &file_gamma)) {
|
1340
|
-
file_gamma = 0.45;
|
1341
|
-
}
|
1970
|
+
} else {
|
1971
|
+
png_read_info(ptr->classic.ctx, ptr->classic.fsi);
|
1342
1972
|
|
1343
|
-
|
1344
|
-
|
1973
|
+
/*
|
1974
|
+
* gamma correction
|
1975
|
+
*/
|
1976
|
+
if (!isnan(ptr->common.display_gamma)) {
|
1977
|
+
if (!png_get_gAMA(ptr->classic.ctx, ptr->classic.fsi, &file_gamma)) {
|
1978
|
+
file_gamma = 0.45;
|
1979
|
+
}
|
1345
1980
|
|
1346
|
-
|
1981
|
+
png_set_gamma(ptr->classic.ctx, ptr->common.display_gamma, file_gamma);
|
1982
|
+
}
|
1347
1983
|
|
1348
|
-
|
1349
|
-
* get image size
|
1350
|
-
*/
|
1984
|
+
png_read_update_info(ptr->classic.ctx, ptr->classic.fsi);
|
1351
1985
|
|
1352
|
-
|
1353
|
-
|
1986
|
+
/*
|
1987
|
+
* get image size
|
1988
|
+
*/
|
1354
1989
|
|
1355
|
-
|
1356
|
-
|
1990
|
+
ptr->classic.width = \
|
1991
|
+
png_get_image_width(ptr->classic.ctx, ptr->classic.fsi);
|
1357
1992
|
|
1358
|
-
|
1993
|
+
ptr->classic.height = \
|
1994
|
+
png_get_image_height(ptr->classic.ctx, ptr->classic.fsi);
|
1359
1995
|
|
1360
|
-
|
1361
|
-
* alloc return memory
|
1362
|
-
*/
|
1363
|
-
ret = rb_str_buf_new(stride * ptr->classic.height);
|
1364
|
-
rb_str_set_len(ret, stride * ptr->classic.height);
|
1996
|
+
stride = png_get_rowbytes(ptr->classic.ctx, ptr->classic.fsi);
|
1365
1997
|
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
if (ptr->classic.rows == NULL) {
|
1372
|
-
NOMEMORY_ERROR("no memory");
|
1373
|
-
}
|
1998
|
+
/*
|
1999
|
+
* alloc return memory
|
2000
|
+
*/
|
2001
|
+
ret = rb_str_buf_new(stride * ptr->classic.height);
|
2002
|
+
rb_str_set_len(ret, stride * ptr->classic.height);
|
1374
2003
|
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1379
|
-
|
2004
|
+
/*
|
2005
|
+
* alloc rows
|
2006
|
+
*/
|
2007
|
+
ptr->classic.rows = png_malloc(ptr->classic.ctx,
|
2008
|
+
ptr->classic.height * sizeof(png_byte*));
|
2009
|
+
if (ptr->classic.rows == NULL) {
|
2010
|
+
NOMEMORY_ERROR("no memory");
|
2011
|
+
}
|
2012
|
+
|
2013
|
+
p = (png_byte*)RSTRING_PTR(ret);
|
2014
|
+
for (i = 0; i < ptr->classic.height; i++) {
|
2015
|
+
ptr->classic.rows[i] = p;
|
2016
|
+
p += stride;
|
2017
|
+
}
|
1380
2018
|
|
1381
|
-
|
1382
|
-
|
2019
|
+
png_read_image(ptr->classic.ctx, ptr->classic.rows);
|
2020
|
+
png_read_end(ptr->classic.ctx, ptr->classic.fsi);
|
1383
2021
|
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
2022
|
+
if (ptr->classic.need_meta) {
|
2023
|
+
get_header_info(ptr);
|
2024
|
+
rb_ivar_set(ret, id_meta, create_meta(ptr));
|
2025
|
+
rb_define_singleton_method(ret, "meta", rb_decode_result_meta, 0);
|
2026
|
+
}
|
1388
2027
|
}
|
1389
2028
|
|
1390
2029
|
return ret;
|
@@ -1419,10 +2058,14 @@ rb_decoder_decode(VALUE self, VALUE data)
|
|
1419
2058
|
*/
|
1420
2059
|
Check_Type(data, T_STRING);
|
1421
2060
|
|
2061
|
+
if (png_sig_cmp((png_const_bytep)RSTRING_PTR(data), 0, 8)) {
|
2062
|
+
RUNTIME_ERROR("Invalid PNG signature.");
|
2063
|
+
}
|
2064
|
+
|
1422
2065
|
/*
|
1423
2066
|
* strip object
|
1424
2067
|
*/
|
1425
|
-
|
2068
|
+
TypedData_Get_Struct(self, png_decoder_t, &png_decoder_data_type, ptr);
|
1426
2069
|
|
1427
2070
|
/*
|
1428
2071
|
* call decode funcs
|