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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2bce27799394aabf7194c7ec674b2db1886d7491ce048e72f59b161860c4fc4
4
- data.tar.gz: 9561de3dfb0453f87cbea9409576b3a657c34f8c29211c6209de72d376168064
3
+ metadata.gz: 7065dd93f08e6f53cce0a60e91bda0fdbfe9fd305d4bea5e35dc5a82f5e87f75
4
+ data.tar.gz: 9bda38b5eb8d4c70a269ec574fd1a9db7dabb1ffd8004da6adc6e9e0fe16197e
5
5
  SHA512:
6
- metadata.gz: c85f80903cdb0af93630d84d886c09339f559ed0e2d544b8e59b89cc4e211c76918501d43f8f94d08831604fa1f550d7b5abbb46ad9b4d8497514c909defb4a7
7
- data.tar.gz: 6d8423b4a8c4e2ade0efd34be94a5a110fa7befb8c188c30219da9afa70b68e82f51dd42c38d8c53bfe4c8107b12a73a8d4a17ffb839b8ee8abd0c226315c6e6
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
- | :pixel_fromat | String or Symbol | input pixel format |
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 |
@@ -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
- for (i = 0; i < ptr->num_text; i++) {
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 void
193
- mem_io_write_data(png_structp ctx, png_bytep src, png_size_t size)
379
+ static size_t
380
+ rb_encoder_size(const void* _ptr)
194
381
  {
195
- VALUE buf;
382
+ size_t ret;
383
+ png_encoder_t* ptr;
384
+ int i;
196
385
 
197
- buf = (VALUE)png_get_io_ptr(ctx);
198
- rb_str_buf_cat(buf, (const char *)src, size);
199
- }
386
+ ptr = (png_encoder_t*)_ptr;
200
387
 
201
- static void
202
- mem_io_flush(png_structp ctx)
203
- {
204
- // ignore
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 Data_Wrap_Struct(encoder_klass, 0, rb_encoder_free, ptr);
448
+ return TypedData_Wrap_Struct(encoder_klass, &png_encoder_data_type, ptr);
224
449
  }
225
450
 
226
- static void
227
- eval_encoder_opt_color_type(png_encoder_t* ptr, VALUE opt)
451
+ static VALUE
452
+ eval_encoder_opt_pixel_format(png_encoder_t* ptr, VALUE opt)
228
453
  {
229
- if (opt != Qundef) {
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
- ptr->c_type = PNG_COLOR_TYPE_GRAY;
232
- ptr->num_comp = 1;
469
+ type = PNG_COLOR_TYPE_GRAY;
470
+ comp = 1;
233
471
 
234
472
  } else if (EQ_STR(opt, "GA")) {
235
- ptr->c_type = PNG_COLOR_TYPE_GA;
236
- ptr->num_comp = 2;
473
+ type = PNG_COLOR_TYPE_GA;
474
+ comp = 2;
237
475
 
238
476
  } else if (EQ_STR(opt, "RGB")) {
239
- ptr->c_type = PNG_COLOR_TYPE_RGB;
240
- ptr->num_comp = 3;
477
+ type = PNG_COLOR_TYPE_RGB;
478
+ comp = 3;
241
479
 
242
480
  } else if (EQ_STR(opt, "RGBA")) {
243
- ptr->c_type = PNG_COLOR_TYPE_RGBA;
244
- ptr->num_comp = 4;
481
+ type = PNG_COLOR_TYPE_RGBA;
482
+ comp = 4;
245
483
 
246
484
  } else {
247
- ARGUMENT_ERROR(":color_type is invalid value");
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 void
502
+ static VALUE
253
503
  eval_encoder_opt_interlace(png_encoder_t* ptr, VALUE opt)
254
504
  {
255
- if (opt != Qundef) {
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 void
518
+ static VALUE
261
519
  eval_encoder_opt_compression(png_encoder_t* ptr, VALUE opt)
262
520
  {
263
- int val;
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
- case T_STRING:
275
- case T_SYMBOL:
276
- if (EQ_STR(opt, "NO_COMPRESSION")) {
277
- val = Z_NO_COMPRESSION;
524
+ ret = Qnil;
278
525
 
279
- } else if (EQ_STR(opt, "BEST_SPEED")) {
280
- val = Z_BEST_SPEED;
526
+ switch (TYPE(opt)) {
527
+ case T_UNDEF:
528
+ lv = Z_DEFAULT_COMPRESSION;
529
+ break;
281
530
 
282
- } else if (EQ_STR(opt, "BEST_COMPRESSION")) {
283
- val = Z_BEST_COMPRESSION;
531
+ case T_STRING:
532
+ case T_SYMBOL:
533
+ if (EQ_STR(opt, "NO_COMPRESSION")) {
534
+ lv = Z_NO_COMPRESSION;
284
535
 
285
- } else if (EQ_STR(opt, "DEFAULT")) {
286
- val = Z_DEFAULT_COMPRESSION;
536
+ } else if (EQ_STR(opt, "BEST_SPEED")) {
537
+ lv = Z_BEST_SPEED;
287
538
 
288
- } else {
289
- ARGUMENT_ERROR(":interlace is invalid value");
290
- }
291
- break;
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
- default:
294
- TYPE_ERROR(":interlace is not Symbol and String");
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
- ptr->c_level = val;
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
- static char*
317
- clone_cstr(VALUE s)
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
- char* ret;
320
- size_t sz;
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
- sz = RSTRING_LEN(s);
323
- ret = (char*)malloc(sz + 1);
600
+ arg = (struct convert_text_rb2c_arg*)_arg;
601
+ src = arg->src;
602
+ dst = arg->dst;
324
603
 
325
- memcpy(ret, RSTRING_PTR(s), sz);
326
- ret[sz] = '\0';
604
+ /*
605
+ * 途中で例外が発生する可能性があるので資源回収できる様に
606
+ * 0クリアを最初に済ませておく。
607
+ */
608
+ keys = rb_funcall(src, rb_intern("keys"), 0);
327
609
 
328
- return ret;
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
- static void
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 keys;
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
- text = NULL;
342
-
343
- if (opt != Qundef) {
344
- if (TYPE(opt) == T_HASH && RHASH_SIZE(opt) > 0) {
345
- keys = rb_funcall(opt, rb_intern("keys"), 0);
346
- text = (png_text*)xmalloc(sizeof(png_text) * RHASH_SIZE(opt));
347
-
348
- /*
349
- * 途中で例外が発生する可能性があるので rb_encoder_free()で
350
- * 資源回収できる様に 0クリアとコンテキスト登録を最初に済ま
351
- * せておく。
352
- *
353
- * なお、この処理はinitialize()の過程で呼び出される。このた
354
- * め例外が発生しコンテキストの状態が中途半端な状態でユーザ
355
- * から参照されることはない。
356
- */
357
- memset(text, 0, sizeof(*text));
358
- ptr->text = text;
359
- ptr->num_text = RARRAY_LEN(keys);
360
-
361
- for (i = 0; i < RARRAY_LEN(keys); i++) {
362
- key = RARRAY_AREF(keys, i);
363
- val = rb_hash_aref(opt, key);
364
-
365
- if (TYPE(key) != T_STRING && TYPE(key) != T_SYMBOL) {
366
- ARGUMENT_ERROR(":type is invalid structure");
367
- }
368
-
369
- if (TYPE(val) != T_STRING && TYPE(val) != T_SYMBOL) {
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 void
691
+ static VALUE
391
692
  eval_encoder_opt_time(png_encoder_t* ptr, VALUE opt)
392
693
  {
393
- if (opt != Qundef) {
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 void
707
+ static VALUE
399
708
  eval_encoder_opt_gamma(png_encoder_t* ptr, VALUE opt)
400
709
  {
401
- if (opt != Qundef) {
402
- ptr->gamma = NUM2DBL(opt);
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 void
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
- const char* err;
414
- png_byte** rows;
805
+ /*
806
+ * initialize
807
+ */
808
+ ret = Qnil;
809
+ ctx = NULL;
810
+ info = NULL;
811
+ rows = NULL;
415
812
 
416
813
  /*
417
- * parse options
814
+ * argument check
418
815
  */
419
- rb_get_kwargs(opt, encoder_opt_ids, 0, N(encoder_opt_ids), opts);
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
- * set context
829
+ * parse options
423
830
  */
424
- eval_encoder_opt_color_type(ptr, opts[0]);
425
- eval_encoder_opt_interlace(ptr, opts[1]);
426
- eval_encoder_opt_compression(ptr, opts[2]);
427
- eval_encoder_opt_text(ptr, opts[3]);
428
- eval_encoder_opt_time(ptr, opts[4]);
429
- eval_encoder_opt_gamma(ptr, opts[5]);
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
- err = NULL;
436
- rows = NULL;
437
- info = NULL;
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
- err = "png_create_read_struct() failed.";
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
- err = "png_create_info_structt() failed.";
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
- err = "png_malloc() failed.";
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->ctx = ctx;
460
- ptr->info = info;
461
- ptr->width = wd;
462
- ptr->height = ht;
463
- ptr->stride = ptr->width * ptr->num_comp;
464
- ptr->pixels = ptr->stride * ptr->height;
465
- ptr->rows = rows;
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 (err != NULL) {
473
- if (ctx != NULL) {
474
- png_destroy_write_struct(&ctx, &info);
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
- Data_Get_Struct(self, png_encoder_t, ptr);
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, "21", &wd, &ht, &opts);
930
+ rb_scan_args(argc, argv, "2:", &wd, &ht, &opts);
500
931
 
501
- Check_Type(wd, T_FIXNUM);
502
- Check_Type(ht, T_FIXNUM);
503
- if (opts != Qnil) Check_Type(opts, T_HASH);
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
- set_encoder_context(ptr, FIX2INT(wd), FIX2INT(ht), opts);
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
- png_uint_32 i;
520
- uint8_t* p;
1031
+ int state;
521
1032
 
522
1033
  /*
523
1034
  * initialize
524
1035
  */
525
- ret = rb_str_buf_new(0);
1036
+ ret = rb_str_buf_new(0);
1037
+ exc = Qnil;
1038
+ state = 0;
526
1039
 
527
1040
  /*
528
1041
  * strip object
529
1042
  */
530
- Data_Get_Struct(self, png_encoder_t, ptr);
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
- time(&tm);
562
- png_convert_from_time_t(&png_time, tm);
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 (!isnan(ptr->gamma)) {
567
- png_set_gAMA(ptr->ctx, ptr->info, ptr->gamma);
1054
+ if (RSTRING_LEN(data) > ptr->data_size) {
1055
+ ARGUMENT_ERROR("image data too large");
568
1056
  }
569
1057
 
570
- png_set_compression_level(ptr->ctx, ptr->c_level);
571
-
572
- png_set_write_fn(ptr->ctx,
573
- (png_voidp)ret,
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
- p = (png_byte*)RSTRING_PTR(data);
578
- for (i = 0; i < ptr->height; i++) {
579
- ptr->rows[i] = p;
580
- p += ptr->stride;
1063
+ /*
1064
+ * do encode
1065
+ */
1066
+ if (!RTEST(exc)) {
1067
+ rb_protect(do_encode, (VALUE)ptr, &state);
581
1068
  }
582
1069
 
583
- png_set_rows(ptr->ctx, ptr->info, ptr->rows);
584
-
585
- if (setjmp(png_jmpbuf(ptr->ctx))) {
586
- RUNTIME_ERROR("encode error");
587
-
588
- } else {
589
- png_write_png(ptr->ctx, ptr->info, PNG_TRANSFORM_IDENTITY, NULL);
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
- mem_io_read_data(png_structp ctx, png_bytep dst, png_size_t rq_size)
1095
+ rb_decoder_mark(void* _ptr)
597
1096
  {
598
- mem_io_t* io;
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 Data_Wrap_Struct(decoder_klass, 0, rb_decoder_free, ptr);
1180
+ return TypedData_Wrap_Struct(decoder_klass, &png_decoder_data_type, ptr);
654
1181
  }
655
1182
 
656
- static void
1183
+ static VALUE
657
1184
  eval_decoder_opt_api_type(png_decoder_t* ptr, VALUE opt)
658
1185
  {
659
- int api_type;
1186
+ VALUE ret;
1187
+ int type;
660
1188
 
661
- if (opt != Qundef) {
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
- api_type = API_SIMPLIFIED;
1199
+ type = API_SIMPLIFIED;
664
1200
 
665
1201
  } else if (EQ_STR(opt, "classic")) {
666
- api_type = API_CLASSIC;
1202
+ type = API_CLASSIC;
667
1203
 
668
1204
  } else {
669
- ARGUMENT_ERROR(":api_type is invalid value");
1205
+ ret = create_argument_error(":api_type invalid value");
670
1206
  }
1207
+ break;
671
1208
 
672
- ptr->common.api_type = api_type;
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 void
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
- if (opt != Qundef) {
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
- ARGUMENT_ERROR(":color_type is invalid value");
1262
+ ret = create_argument_error(":pixel_format invalid value");
711
1263
  }
1264
+ break;
712
1265
 
713
- ptr->common.format = format;
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 void
1276
+ static VALUE
718
1277
  eval_decoder_opt_without_meta(png_decoder_t* ptr, VALUE opt)
719
1278
  {
720
- if (opt != Qundef) {
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 void
1292
+ static VALUE
726
1293
  eval_decoder_opt_display_gamma(png_decoder_t* ptr, VALUE opt)
727
1294
  {
728
- if (opt != Qundef) {
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 void
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
- * parse options
1315
+ * initialize
740
1316
  */
741
- rb_get_kwargs(opt, decoder_opt_ids, 0, N(decoder_opt_ids), opts);
1317
+ ret = Qnil;
742
1318
 
743
1319
  /*
744
- * set context
1320
+ * parse options
745
1321
  */
746
- eval_decoder_opt_api_type(ptr, opts[2]);
747
- eval_decoder_opt_pixel_format(ptr, opts[0]);
748
- eval_decoder_opt_without_meta(ptr, opts[1]);
749
- eval_decoder_opt_display_gamma(ptr, opts[3]);
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 opt;
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
- Data_Get_Struct(self, png_decoder_t, ptr);
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, "01", &opt);
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, opt);
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
- err = NULL;
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, NULL, NULL, NULL);
1417
+ ctx = png_create_read_struct(PNG_LIBPNG_VER_STRING,
1418
+ ptr,
1419
+ decode_error,
1420
+ decode_warn);
792
1421
  if (ctx == NULL) {
793
- err = "png_create_read_struct() failed.";
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 (fsi == NULL || bsi == NULL) {
800
- err = "png_create_info_struct() failed.";
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
- if (setjmp(png_jmpbuf(ptr->classic.ctx))) {
813
- RUNTIME_ERROR("decode error");
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 (err != NULL) {
1451
+ if (RTEST(exc)) {
823
1452
  if (ctx != NULL) {
824
1453
  png_destroy_read_struct(&ctx, &fsi, &bsi);
825
1454
  }
826
1455
 
827
- RUNTIME_ERROR(err);
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
- png_read_info(ptr->classic.ctx, ptr->classic.fsi);
1168
- get_header_info(ptr);
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
- Data_Get_Struct(self, png_decoder_t, ptr);
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
- png_read_info(ptr->classic.ctx, ptr->classic.fsi);
1967
+ if (setjmp(png_jmpbuf(ptr->classic.ctx))) {
1968
+ rb_exc_raise(ptr->common.error);
1334
1969
 
1335
- /*
1336
- * gamma correction
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
- png_set_gamma(ptr->classic.ctx, ptr->common.display_gamma, file_gamma);
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
- png_read_update_info(ptr->classic.ctx, ptr->classic.fsi);
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
- ptr->classic.width = \
1353
- png_get_image_width(ptr->classic.ctx, ptr->classic.fsi);
1986
+ /*
1987
+ * get image size
1988
+ */
1354
1989
 
1355
- ptr->classic.height = \
1356
- png_get_image_height(ptr->classic.ctx, ptr->classic.fsi);
1990
+ ptr->classic.width = \
1991
+ png_get_image_width(ptr->classic.ctx, ptr->classic.fsi);
1357
1992
 
1358
- stride = png_get_rowbytes(ptr->classic.ctx, ptr->classic.fsi);
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
- * alloc rows
1368
- */
1369
- ptr->classic.rows = png_malloc(ptr->classic.ctx,
1370
- ptr->classic.height * sizeof(png_byte*));
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
- p = (png_byte*)RSTRING_PTR(ret);
1376
- for (i = 0; i < ptr->classic.height; i++) {
1377
- ptr->classic.rows[i] = p;
1378
- p += stride;
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
- png_read_image(ptr->classic.ctx, ptr->classic.rows);
1382
- png_read_end(ptr->classic.ctx, ptr->classic.fsi);
2019
+ png_read_image(ptr->classic.ctx, ptr->classic.rows);
2020
+ png_read_end(ptr->classic.ctx, ptr->classic.fsi);
1383
2021
 
1384
- if (ptr->classic.need_meta) {
1385
- get_header_info(ptr);
1386
- rb_ivar_set(ret, id_meta, create_meta(ptr));
1387
- rb_define_singleton_method(ret, "meta", rb_decode_result_meta, 0);
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
- Data_Get_Struct(self, png_decoder_t, ptr);
2068
+ TypedData_Get_Struct(self, png_decoder_t, &png_decoder_data_type, ptr);
1426
2069
 
1427
2070
  /*
1428
2071
  * call decode funcs