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