libjpeg-ruby 0.8.0 → 0.10.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.
data/ext/jpeg/jpeg.c CHANGED
@@ -12,6 +12,7 @@
12
12
  #include <jpeglib.h>
13
13
 
14
14
  #include "ruby.h"
15
+ #include "ruby/version.h"
15
16
  #include "ruby/encoding.h"
16
17
 
17
18
  #define UNIT_LINES 10
@@ -23,19 +24,24 @@
23
24
  #define DEFAULT_QUALITY 75
24
25
  #define DEFAULT_INPUT_COLOR_SPACE JCS_YCbCr
25
26
  #define DEFAULT_INPUT_COMPONENTS 2
26
- #define DEFAULT_FLAGS (F_NEED_META)
27
+ #define DEFAULT_ENCODE_FLAGS (0)
28
+ #define DEFAULT_DECODE_FLAGS (F_NEED_META)
27
29
 
28
30
  #define F_NEED_META 0x00000001
29
31
  #define F_EXPAND_COLORMAP 0x00000002
30
32
  #define F_PARSE_EXIF 0x00000004
31
33
  #define F_APPLY_ORIENTATION 0x00000008
32
34
  #define F_DITHER 0x00000010
35
+ #define F_CREAT 0x00010000
33
36
 
34
37
  #define SET_FLAG(ptr, msk) ((ptr)->flags |= (msk))
35
38
  #define CLR_FLAG(ptr, msk) ((ptr)->flags &= ~(msk))
36
39
  #define TEST_FLAG(ptr, msk) ((ptr)->flags & (msk))
37
40
  #define TEST_FLAG_ALL(ptr, msk) (((ptr)->flags & (msk)) == (msk))
38
41
 
42
+ #define SET_DATA(ptr, dat) ((ptr)->data = (dat))
43
+ #define CLR_DATA(ptr) ((ptr)->data = Qnil)
44
+
39
45
  #define FMT_YUV422 1
40
46
  #define FMT_RGB565 2
41
47
  #define FMT_GRAYSCALE 3
@@ -62,13 +68,13 @@
62
68
  #define IS_COLORMAPPED(ci) (((ci)->actual_number_of_colors > 0) &&\
63
69
  ((ci)->colormap != NULL) && \
64
70
  ((ci)->output_components == 1) && \
65
- (((ci)->out_color_components == 1) || \
66
- ((ci)->out_color_components == 3)))
71
+ (((ci)->out_color_components == 1) || \
72
+ ((ci)->out_color_components == 3)))
67
73
 
68
74
  #define ALLOC_ARRAY() \
69
- ((JSAMPARRAY)xmalloc(sizeof(JSAMPROW) * UNIT_LINES))
75
+ ((JSAMPARRAY)malloc(sizeof(JSAMPROW) * UNIT_LINES))
70
76
  #define ALLOC_ROWS(w,c) \
71
- ((JSAMPROW)xmalloc(sizeof(JSAMPLE) * (w) * (c) * UNIT_LINES))
77
+ ((JSAMPROW)malloc(sizeof(JSAMPLE) * (w) * (c) * UNIT_LINES))
72
78
 
73
79
  #define EQ_STR(val,str) (rb_to_id(val) == rb_intern(str))
74
80
  #define EQ_INT(val,n) (FIX2INT(val) == n)
@@ -255,27 +261,46 @@ tag_entry_t tag_i14y[] = {
255
261
  static const char* encoder_opts_keys[] = {
256
262
  "pixel_format", // {str}
257
263
  "quality", // {integer}
258
- "scale", // {rational} or {float}
259
264
  "dct_method", // {str}
260
- "orientation" // {integer}
265
+ "orientation", // {integer}
266
+ "stride", // {integer}
261
267
  };
262
268
 
263
269
  static ID encoder_opts_ids[N(encoder_opts_keys)];
264
270
 
265
271
  typedef struct {
266
- int format;
272
+ struct jpeg_error_mgr jerr;
273
+
274
+ char msg[JMSG_LENGTH_MAX+10];
275
+ jmp_buf jmpbuf;
276
+ } ext_error_t;
277
+
278
+ typedef struct {
279
+ int flags;
267
280
  int width;
281
+ int stride;
268
282
  int height;
269
-
270
283
  int data_size;
284
+
285
+ int format;
286
+ int color_space;
287
+ int components;
288
+ int quality;
271
289
  J_DCT_METHOD dct_method;
272
290
 
273
291
  struct jpeg_compress_struct cinfo;
274
- struct jpeg_error_mgr jerr;
292
+ ext_error_t err_mgr;
275
293
 
276
294
  JSAMPARRAY array;
277
295
  JSAMPROW rows;
278
296
 
297
+ VALUE data;
298
+
299
+ struct {
300
+ unsigned char* mem;
301
+ unsigned long size;
302
+ } buf;
303
+
279
304
  int orientation;
280
305
  } jpeg_encode_t;
281
306
 
@@ -294,20 +319,12 @@ static const char* decoder_opts_keys[] = {
294
319
  "expand_colormap", // {bool}
295
320
  "scale", // {rational} or {float}
296
321
  "dct_method", // {str}
297
- "with_exif", // {bool}
298
322
  "with_exif_tags", // {bool}
299
323
  "orientation" // {bool}
300
324
  };
301
325
 
302
326
  static ID decoder_opts_ids[N(decoder_opts_keys)];
303
327
 
304
- typedef struct {
305
- struct jpeg_error_mgr jerr;
306
-
307
- char msg[JMSG_LENGTH_MAX+10];
308
- jmp_buf jmpbuf;
309
- } ext_error_t;
310
-
311
328
  typedef struct {
312
329
  int flags;
313
330
  int format;
@@ -332,12 +349,130 @@ typedef struct {
332
349
  struct jpeg_decompress_struct cinfo;
333
350
  ext_error_t err_mgr;
334
351
 
352
+ JSAMPARRAY array;
353
+
354
+ VALUE data;
355
+
335
356
  struct {
336
357
  int value;
337
358
  VALUE buf;
338
359
  } orientation;
339
360
  } jpeg_decode_t;
340
361
 
362
+ #if 0
363
+ static VALUE
364
+ create_runtime_error(const char* fmt, ...)
365
+ {
366
+ VALUE ret;
367
+ va_list ap;
368
+
369
+ va_start(ap, fmt);
370
+ ret = rb_exc_new_str(rb_eRuntimeError, rb_vsprintf(fmt, ap));
371
+ va_end(ap);
372
+
373
+ return ret;
374
+ }
375
+ #endif
376
+
377
+ static VALUE
378
+ create_argument_error(const char* fmt, ...)
379
+ {
380
+ VALUE ret;
381
+ va_list ap;
382
+
383
+ va_start(ap, fmt);
384
+ ret = rb_exc_new_str(rb_eArgError, rb_vsprintf(fmt, ap));
385
+ va_end(ap);
386
+
387
+ return ret;
388
+ }
389
+
390
+ static VALUE
391
+ create_type_error(const char* fmt, ...)
392
+ {
393
+ VALUE ret;
394
+ va_list ap;
395
+
396
+ va_start(ap, fmt);
397
+ ret = rb_exc_new_str(rb_eTypeError, rb_vsprintf(fmt, ap));
398
+ va_end(ap);
399
+
400
+ return ret;
401
+ }
402
+
403
+ static VALUE
404
+ create_range_error(const char* fmt, ...)
405
+ {
406
+ VALUE ret;
407
+ va_list ap;
408
+
409
+ va_start(ap, fmt);
410
+ ret = rb_exc_new_str(rb_eRangeError, rb_vsprintf(fmt, ap));
411
+ va_end(ap);
412
+
413
+ return ret;
414
+ }
415
+
416
+ static VALUE
417
+ create_not_implement_error(const char* fmt, ...)
418
+ {
419
+ VALUE ret;
420
+ va_list ap;
421
+
422
+ va_start(ap, fmt);
423
+ ret = rb_exc_new_str(rb_eNotImpError, rb_vsprintf(fmt, ap));
424
+ va_end(ap);
425
+
426
+ return ret;
427
+ }
428
+
429
+ static VALUE
430
+ create_memory_error()
431
+ {
432
+ return rb_exc_new_str(rb_eRangeError, rb_str_new_cstr("no memory"));
433
+ }
434
+
435
+ static void
436
+ output_message(j_common_ptr cinfo)
437
+ {
438
+ ext_error_t* err;
439
+
440
+ err = (ext_error_t*)cinfo->err;
441
+
442
+ (*err->jerr.format_message)(cinfo, err->msg);
443
+ }
444
+
445
+ static void
446
+ emit_message(j_common_ptr cinfo, int msg_level)
447
+ {
448
+ ext_error_t* err;
449
+
450
+ if (msg_level < 0) {
451
+ err = (ext_error_t*)cinfo->err;
452
+ (*err->jerr.format_message)(cinfo, err->msg);
453
+ /*
454
+ * 以前はemit_messageが呼ばれるとエラー扱いしていたが、
455
+ * Logicoolの一部のモデルなどで問題が出るので無視する
456
+ * ようにした。
457
+ * また本来であれば、警告表示を行うべきでもあるが一部
458
+ * のモデルで大量にemitされる場合があるので表示しない
459
+ * ようにしている。
460
+ * 問題が発生した際は、最後のメッセージをオブジェクト
461
+ * のインスタンスとして持たすべき。
462
+ */
463
+ // longjmp(err->jmpbuf, 1);
464
+ }
465
+ }
466
+
467
+ static void
468
+ error_exit(j_common_ptr cinfo)
469
+ {
470
+ ext_error_t* err;
471
+
472
+ err = (ext_error_t*)cinfo->err;
473
+ (*err->jerr.format_message)(cinfo, err->msg);
474
+ longjmp(err->jmpbuf, 1);
475
+ }
341
476
 
342
477
  static VALUE
343
478
  lookup_tag_symbol(tag_entry_t* tbl, size_t n, int tag)
@@ -380,40 +515,87 @@ lookup_tag_symbol(tag_entry_t* tbl, size_t n, int tag)
380
515
  }
381
516
 
382
517
  static void
383
- encode_output_message(j_common_ptr cinfo)
518
+ rb_encoder_mark(void* _ptr)
384
519
  {
385
- char msg[JMSG_LENGTH_MAX];
520
+ jpeg_encode_t* ptr;
521
+
522
+ ptr = (jpeg_encode_t*)_ptr;
386
523
 
387
- (*cinfo->err->format_message)(cinfo, msg);
524
+ if (ptr->data != Qnil) {
525
+ rb_gc_mark(ptr->data);
526
+ }
388
527
  }
389
528
 
390
529
  static void
391
- encode_error_exit(j_common_ptr cinfo)
530
+ rb_encoder_free(void* _ptr)
392
531
  {
393
- char msg[JMSG_LENGTH_MAX];
532
+ jpeg_encode_t* ptr;
394
533
 
395
- (*cinfo->err->format_message)(cinfo, msg);
534
+ ptr = (jpeg_encode_t*)_ptr;
396
535
 
397
- jpeg_destroy_compress((j_compress_ptr)cinfo);
398
- rb_raise(encerr_klass, "%s", msg);
399
- }
536
+ if (ptr->array != NULL) {
537
+ free(ptr->array);
538
+ }
400
539
 
540
+ if (ptr->rows != NULL) {
541
+ free(ptr->rows);
542
+ }
401
543
 
402
- static void
403
- rb_encoder_free( void* _ptr)
544
+ if (ptr->buf.mem != NULL) {
545
+ free(ptr->buf.mem);
546
+ }
547
+
548
+ if (TEST_FLAG(ptr, F_CREAT)) {
549
+ jpeg_destroy_compress(&ptr->cinfo);
550
+ }
551
+
552
+ free(ptr);
553
+ }
554
+
555
+ static size_t
556
+ rb_encoder_size(const void* _ptr)
404
557
  {
558
+ size_t ret;
405
559
  jpeg_encode_t* ptr;
406
560
 
407
- ptr = (jpeg_encode_t*)_ptr;
408
-
409
- if (ptr->array != NULL) xfree(ptr->array);
410
- if (ptr->rows != NULL) xfree(ptr->rows);
561
+ ptr = (jpeg_encode_t*)_ptr;
411
562
 
412
- jpeg_destroy_compress(&ptr->cinfo);
563
+ ret = sizeof(jpeg_encode_t);
564
+ ret += sizeof(JSAMPROW) * UNIT_LINES;
565
+ ret += sizeof(JSAMPLE) * ptr->stride * UNIT_LINES;
413
566
 
414
- free(_ptr);
567
+ return ret;
415
568
  }
416
569
 
570
+ #if RUBY_API_VERSION_CODE > 20600
571
+ static const rb_data_type_t jpeg_encoder_data_type = {
572
+ "libjpeg-ruby encoder object", // wrap_struct_name
573
+ {
574
+ rb_encoder_mark, // function.dmark
575
+ rb_encoder_free, // function.dfree
576
+ rb_encoder_size, // function.dsize
577
+ NULL, // function.dcompact
578
+ {NULL}, // function.reserved
579
+ },
580
+ NULL, // parent
581
+ NULL, // data
582
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
583
+ };
584
+ #else /* RUBY_API_VERSION_CODE > 20600 */
585
+ static const rb_data_type_t jpeg_encoder_data_type = {
586
+ "libjpeg-ruby encoder object", // wrap_struct_name
587
+ {
588
+ rb_encoder_mark, // function.dmark
589
+ rb_encoder_free, // function.dfree
590
+ rb_encoder_size, // function.dsize
591
+ {NULL, NULL}, // function.reserved
592
+ },
593
+ NULL, // parent
594
+ NULL, // data
595
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
596
+ };
597
+ #endif /* RUBY_API_VERSION_CODE > 20600 */
598
+
417
599
  static VALUE
418
600
  rb_encoder_alloc(VALUE self)
419
601
  {
@@ -422,203 +604,367 @@ rb_encoder_alloc(VALUE self)
422
604
  ptr = ALLOC(jpeg_encode_t);
423
605
  memset(ptr, 0, sizeof(*ptr));
424
606
 
425
- return Data_Wrap_Struct(encoder_klass, 0, rb_encoder_free, ptr);
607
+ ptr->flags = DEFAULT_ENCODE_FLAGS;
608
+
609
+ return TypedData_Wrap_Struct(encoder_klass, &jpeg_encoder_data_type, ptr);
426
610
  }
427
611
 
428
- static void
429
- set_encoder_context(jpeg_encode_t* ptr, int wd, int ht, VALUE opt)
612
+ static VALUE
613
+ eval_encoder_pixel_format_opt(jpeg_encode_t* ptr, VALUE opt)
430
614
  {
431
- VALUE opts[N(encoder_opts_ids)];
615
+ VALUE ret;
432
616
  int format;
433
617
  int color_space;
434
618
  int components;
435
- int data_size;
436
- int quality;
437
- int scale_num;
438
- int scale_denom;
439
- int i;
440
619
 
441
- /*
442
- * parse options
443
- */
444
- rb_get_kwargs(opt, encoder_opts_ids, 0, N(encoder_opts_ids), opts);
620
+ ret = Qnil;
445
621
 
446
- /*
447
- * eval :pixel_format option
448
- */
449
- if (opts[0] == Qundef||EQ_STR(opts[0], "YUV422")||EQ_STR(opts[0], "YUYV")) {
622
+ switch (TYPE(opt)) {
623
+ case T_UNDEF:
450
624
  format = FMT_YUV422;
451
625
  color_space = JCS_YCbCr;
452
626
  components = 3;
453
- data_size = (wd * ht * 2);
627
+ break;
454
628
 
455
- } else if (EQ_STR(opts[0], "RGB565")) {
456
- format = FMT_RGB565;
457
- color_space = JCS_RGB;
458
- components = 3;
459
- data_size = (wd * ht * 2);
629
+ case T_STRING:
630
+ case T_SYMBOL:
631
+ if (EQ_STR(opt, "YUV422") || EQ_STR(opt, "YUYV")) {
632
+ format = FMT_YUV422;
633
+ color_space = JCS_YCbCr;
634
+ components = 3;
460
635
 
461
- } else if (EQ_STR(opts[0], "RGB") || EQ_STR(opts[0], "RGB24")) {
462
- format = FMT_RGB;
463
- color_space = JCS_RGB;
464
- components = 3;
465
- data_size = (wd * ht * 3);
636
+ } else if (EQ_STR(opt, "RGB565")) {
637
+ format = FMT_RGB565;
638
+ color_space = JCS_RGB;
639
+ components = 3;
466
640
 
467
- } else if (EQ_STR(opts[0], "BGR") || EQ_STR(opts[0], "BGR24")) {
468
- format = FMT_BGR;
469
- color_space = JCS_EXT_BGR;
470
- components = 3;
471
- data_size = (wd * ht * 3);
641
+ } else if (EQ_STR(opt, "RGB") || EQ_STR(opt, "RGB24")) {
642
+ format = FMT_RGB;
643
+ color_space = JCS_RGB;
644
+ components = 3;
472
645
 
473
- } else if (EQ_STR(opts[0], "YUV444") || EQ_STR(opts[0], "YCbCr")) {
474
- format = FMT_YUV;
475
- color_space = JCS_YCbCr;
476
- components = 3;
477
- data_size = (wd * ht * 3);
646
+ } else if (EQ_STR(opt, "BGR") || EQ_STR(opt, "BGR24")) {
647
+ format = FMT_BGR;
648
+ color_space = JCS_EXT_BGR;
649
+ components = 3;
478
650
 
479
- } else if (EQ_STR(opts[0], "RGBX") || EQ_STR(opts[0], "RGB32")) {
480
- format = FMT_RGB32;
481
- color_space = JCS_EXT_RGBX;
482
- components = 4;
483
- data_size = (wd * ht * 4);
651
+ } else if (EQ_STR(opt, "YUV444") || EQ_STR(opt, "YCbCr")) {
652
+ format = FMT_YUV;
653
+ color_space = JCS_YCbCr;
654
+ components = 3;
484
655
 
656
+ } else if (EQ_STR(opt, "RGBX") || EQ_STR(opt, "RGB32")) {
657
+ format = FMT_RGB32;
658
+ color_space = JCS_EXT_RGBX;
659
+ components = 4;
485
660
 
486
- } else if (EQ_STR(opts[0], "BGRX") || EQ_STR(opts[0], "BGR32")) {
487
- format = FMT_BGR32;
488
- color_space = JCS_EXT_BGRX;
489
- components = 4;
490
- data_size = (wd * ht * 4);
661
+ } else if (EQ_STR(opt, "BGRX") || EQ_STR(opt, "BGR32")) {
662
+ format = FMT_BGR32;
663
+ color_space = JCS_EXT_BGRX;
664
+ components = 4;
491
665
 
666
+ } else if (EQ_STR(opt, "GRAYSCALE")) {
667
+ format = FMT_GRAYSCALE;
668
+ color_space = JCS_GRAYSCALE;
669
+ components = 1;
492
670
 
493
- } else if (EQ_STR(opts[0], "GRAYSCALE")) {
494
- format = FMT_GRAYSCALE;
495
- color_space = JCS_GRAYSCALE;
496
- components = 1;
497
- data_size = (wd * ht);
671
+ } else {
672
+ ret = create_argument_error("unsupportd :pixel_format option value");
673
+ }
674
+ break;
498
675
 
499
- } else {
500
- ARGUMENT_ERROR("Unsupportd :pixel_format option value.");
676
+ default:
677
+ ret = create_type_error("unsupportd :pixel_format option type");
678
+ break;
501
679
  }
502
680
 
503
- /*
504
- * eval :quality option
505
- */
506
- if (opts[1] == Qundef) {
507
- quality = DEFAULT_QUALITY;
508
-
509
- } else {
510
- if (TYPE(opts[1]) != T_FIXNUM) {
511
- ARGUMENT_ERROR("Unsupportd :quality option value.");
681
+ if (!RTEST(ret)) {
682
+ ptr->format = format;
683
+ ptr->color_space = color_space;
684
+ ptr->components = components;
685
+ }
512
686
 
513
- } else {
514
- quality = FIX2INT(opts[1]);
515
- }
687
+ return ret;
688
+ }
516
689
 
517
- if (quality < 0) {
518
- ARGUMENT_ERROR(":quality value is to little.");
690
+ static VALUE
691
+ eval_encoder_quality_opt(jpeg_encode_t* ptr, VALUE opt)
692
+ {
693
+ VALUE ret;
694
+ long quality;
519
695
 
520
- } else if (quality > 100) {
521
- ARGUMENT_ERROR(":quality value is to big.");
522
- }
523
- }
524
-
525
- /*
526
- * eval scale option
527
- */
528
- (void)scale_num;
529
- (void)scale_denom;
696
+ ret = Qnil;
530
697
 
531
- switch (TYPE(opts[2])) {
698
+ switch (TYPE(opt)) {
532
699
  case T_UNDEF:
533
- // Nothing
700
+ quality = DEFAULT_QUALITY;
534
701
  break;
535
702
 
536
703
  case T_FLOAT:
537
- scale_num = (int)(NUM2DBL(opts[2]) * 1000.0);
538
- scale_denom = 1000;
704
+ if (isnan(NUM2DBL(opt)) || isinf(NUM2DBL(opt))) {
705
+ ret = create_argument_error("unsupportd :quality option value");
706
+
707
+ } else if (NUM2DBL(opt) < 0.0) {
708
+ ret = create_range_error(":quality less than 0");
709
+
710
+ } else if (NUM2DBL(opt) > 100.0) {
711
+ ret = create_range_error(":quality greater than 100");
712
+
713
+ } else {
714
+ quality = NUM2INT(opt);
715
+ }
539
716
  break;
540
717
 
541
- case T_RATIONAL:
542
- scale_num = FIX2INT(rb_rational_num(opts[2]));
543
- scale_denom = FIX2INT(rb_rational_den(opts[2]));
718
+ case T_FIXNUM:
719
+ if (FIX2LONG(opt) < 0) {
720
+ ret = create_range_error(":quality less than 0");
721
+
722
+ } if (FIX2LONG(opt) > 100) {
723
+ ret = create_range_error(":quality greater than 100");
724
+
725
+ } else {
726
+ quality = FIX2INT(opt);
727
+ }
544
728
  break;
545
729
 
546
730
  default:
547
- ARGUMENT_ERROR("Unsupportd :scale option value.");
731
+ ret = create_type_error("unsupportd :quality option type");
548
732
  break;
549
733
  }
550
734
 
551
- /*
552
- * eval dct_method option
553
- */
554
- if (opts[3] == Qundef || EQ_STR(opts[3], "FASTEST")) {
555
- ptr->dct_method = JDCT_FASTEST;
556
-
557
- } else if (EQ_STR(opts[3], "ISLOW")) {
558
- ptr->dct_method = JDCT_ISLOW;
735
+ if (!RTEST(ret)) ptr->quality = quality;
559
736
 
560
- } else if (EQ_STR(opts[3], "IFAST")) {
561
- ptr->dct_method = JDCT_IFAST;
737
+ return ret;
738
+ }
562
739
 
563
- } else if (EQ_STR(opts[3], "FLOAT")) {
564
- ptr->dct_method = JDCT_FLOAT;
740
+ static VALUE
741
+ eval_encoder_dct_method_opt(jpeg_encode_t* ptr, VALUE opt)
742
+ {
743
+ VALUE ret;
744
+ int dct_method;
565
745
 
566
- } else {
567
- ARGUMENT_ERROR("Unsupportd :dct_method option value.");
568
- }
746
+ ret = Qnil;
569
747
 
570
- /*
571
- * eval orientation option
572
- */
573
- switch (TYPE(opts[4])) {
748
+ switch (TYPE(opt)) {
574
749
  case T_UNDEF:
575
- ptr->orientation = 0;
750
+ dct_method = JDCT_FASTEST;
576
751
  break;
577
752
 
578
- case T_FIXNUM:
579
- ptr->orientation = FIX2INT(opts[4]);
580
- if (ptr->orientation < 1 || ptr->orientation > 8) {
581
- RANGE_ERROR("orientation is ouf range");
582
- }
583
- break;
753
+ case T_STRING:
754
+ case T_SYMBOL:
755
+ if (EQ_STR(opt, "FASTEST")) {
756
+ dct_method = JDCT_FASTEST;
584
757
 
585
- default:
586
- ARGUMENT_ERROR("Unsupportd :orientation option value.");
587
- }
758
+ } else if (EQ_STR(opt, "ISLOW")) {
759
+ dct_method = JDCT_ISLOW;
588
760
 
589
- /*
590
- * set context
591
- */
592
- ptr->format = format;
593
- ptr->width = wd;
594
- ptr->height = ht;
595
- ptr->data_size = data_size;
596
- ptr->array = ALLOC_ARRAY();
597
- ptr->rows = ALLOC_ROWS(wd, components);
761
+ } else if (EQ_STR(opt, "IFAST")) {
762
+ dct_method = JDCT_IFAST;
598
763
 
599
- for (i = 0; i < UNIT_LINES; i++) {
600
- ptr->array[i] = ptr->rows + (i * components * wd);
764
+ } else if (EQ_STR(opt, "FLOAT")) {
765
+ dct_method = JDCT_FLOAT;
766
+
767
+ } else {
768
+ ret = create_argument_error("unsupportd :dct_method option value");
769
+ }
770
+ break;
771
+
772
+ default:
773
+ ret = create_type_error("unsupportd :dct_method option type");
774
+ break;
601
775
  }
602
776
 
603
- jpeg_create_compress(&ptr->cinfo);
777
+ if (!RTEST(ret)) ptr->dct_method = dct_method;
778
+
779
+ return ret;
780
+ }
781
+
782
+ static VALUE
783
+ eval_encoder_orientation_opt(jpeg_encode_t* ptr, VALUE opt)
784
+ {
785
+ VALUE ret;
786
+ int orientation;
787
+
788
+ ret = Qnil;
604
789
 
605
- ptr->cinfo.err = jpeg_std_error(&ptr->jerr);
606
- ptr->jerr.output_message = encode_output_message;
607
- ptr->jerr.error_exit = encode_error_exit;
790
+ switch (TYPE(opt)) {
791
+ case T_UNDEF:
792
+ orientation = 0;
793
+ break;
794
+
795
+ case T_FIXNUM:
796
+ orientation = FIX2INT(opt);
797
+ if (orientation < 1 || orientation > 8) {
798
+ ret = create_range_error(":orientation option ouf range");
799
+ }
800
+ break;
801
+
802
+ default:
803
+ ret = create_type_error("Unsupportd :orientation option type.");
804
+ break;
805
+ }
806
+
807
+ if (!RTEST(ret)) ptr->orientation = orientation;
808
+
809
+ return ret;
810
+ }
811
+
812
+ static VALUE
813
+ eval_encoder_stride_opt(jpeg_encode_t* ptr, VALUE opt)
814
+ {
815
+ VALUE ret;
816
+ int stride;
817
+
818
+ ret = Qnil;
819
+
820
+ switch (TYPE(opt)) {
821
+ case T_UNDEF:
822
+ stride = ptr->width * ptr->components;
823
+ break;
824
+
825
+ case T_FIXNUM:
826
+ stride = FIX2INT(opt);
827
+ if (stride < (ptr->width * ptr->components)) {
828
+ ret = create_range_error(":stride too little");
829
+ }
830
+ break;
608
831
 
609
- ptr->cinfo.image_width = wd;
610
- ptr->cinfo.image_height = ht;
611
- ptr->cinfo.in_color_space = color_space;
612
- ptr->cinfo.input_components = components;
832
+ default:
833
+ ret = create_type_error("unsupportd :stride option type");
834
+ }
613
835
 
614
- ptr->cinfo.optimize_coding = TRUE;
615
- ptr->cinfo.arith_code = TRUE;
616
- ptr->cinfo.raw_data_in = FALSE;
617
- ptr->cinfo.dct_method = ptr->dct_method;
836
+ if (!RTEST(ret)) ptr->stride = stride;
618
837
 
619
- jpeg_set_defaults(&ptr->cinfo);
620
- jpeg_set_quality(&ptr->cinfo, quality, TRUE);
621
- jpeg_suppress_tables(&ptr->cinfo, TRUE);
838
+ return ret;
839
+ }
840
+
841
+ static VALUE
842
+ set_encoder_context(jpeg_encode_t* ptr, int wd, int ht, VALUE opt)
843
+ {
844
+ VALUE ret;
845
+ VALUE opts[N(encoder_opts_ids)];
846
+ JSAMPARRAY ary;
847
+ JSAMPROW rows;
848
+
849
+ int i;
850
+
851
+ /*
852
+ * initialize
853
+ */
854
+ ret = Qnil;
855
+ ary = NULL;
856
+ rows = NULL;
857
+
858
+ /*
859
+ * argument check
860
+ */
861
+ do {
862
+ if (wd <= 0) {
863
+ ret = create_range_error("image width less equal zero");
864
+ break;
865
+ }
866
+
867
+ if (ht <= 0) {
868
+ ret = create_range_error("image height less equal zero");
869
+ break;
870
+ }
871
+ } while (0);
872
+
873
+ /*
874
+ * parse options
875
+ */
876
+ if (!RTEST(ret)) do {
877
+ rb_get_kwargs(opt, encoder_opts_ids, 0, N(encoder_opts_ids), opts);
878
+
879
+ // オプション評価で使用するので前もって設定しておく
880
+ ptr->width = wd;
881
+ ptr->height = ht;
882
+
883
+ ret = eval_encoder_pixel_format_opt(ptr, opts[0]);
884
+ if (RTEST(ret)) break;
885
+
886
+ ret = eval_encoder_quality_opt(ptr, opts[1]);
887
+ if (RTEST(ret)) break;
888
+
889
+ ret = eval_encoder_dct_method_opt(ptr, opts[2]);
890
+ if (RTEST(ret)) break;
891
+
892
+ ret = eval_encoder_orientation_opt(ptr, opts[3]);
893
+ if (RTEST(ret)) break;
894
+
895
+ ret = eval_encoder_stride_opt(ptr, opts[4]);
896
+ if (RTEST(ret)) break;
897
+ } while (0);
898
+
899
+ /*
900
+ * alloc memory
901
+ */
902
+ if (!RTEST(ret)) do {
903
+ ary = ALLOC_ARRAY();
904
+ if (ary == NULL) {
905
+ ret = create_memory_error();
906
+ break;
907
+ }
908
+
909
+ rows = ALLOC_ROWS(ptr->width, ptr->components);
910
+ if (rows == NULL) {
911
+ ret = create_memory_error();
912
+ break;
913
+ }
914
+ } while (0);
915
+
916
+ /*
917
+ * set the rest context parameter
918
+ */
919
+ if (!RTEST(ret)) {
920
+ ptr->err_mgr.jerr.output_message = output_message;
921
+ ptr->err_mgr.jerr.emit_message = emit_message;
922
+ ptr->err_mgr.jerr.error_exit = error_exit;
923
+
924
+ ptr->data_size = ptr->stride * ptr->height;
925
+ ptr->buf.mem = NULL;
926
+ ptr->buf.size = 0;
927
+ ptr->array = ary;
928
+ ptr->rows = rows;
929
+ ptr->data = Qnil;
930
+
931
+ for (i = 0; i < UNIT_LINES; i++) {
932
+ ptr->array[i] = ptr->rows + (i * ptr->width * ptr->components);
933
+ }
934
+ }
935
+
936
+ /*
937
+ * setup libjpeg
938
+ */
939
+ if (!RTEST(ret)) {
940
+ jpeg_create_compress(&ptr->cinfo);
941
+ SET_FLAG(ptr, F_CREAT);
942
+
943
+ ptr->cinfo.err = jpeg_std_error(&ptr->err_mgr.jerr);
944
+ ptr->cinfo.image_width = ptr->width;
945
+ ptr->cinfo.image_height = ptr->height;
946
+ ptr->cinfo.in_color_space = ptr->color_space;
947
+ ptr->cinfo.input_components = ptr->components;
948
+
949
+ ptr->cinfo.optimize_coding = TRUE;
950
+ ptr->cinfo.arith_code = TRUE;
951
+ ptr->cinfo.raw_data_in = FALSE;
952
+ ptr->cinfo.dct_method = ptr->dct_method;
953
+
954
+ jpeg_set_defaults(&ptr->cinfo);
955
+ jpeg_set_quality(&ptr->cinfo, ptr->quality, TRUE);
956
+ jpeg_suppress_tables(&ptr->cinfo, TRUE);
957
+ }
958
+
959
+ /*
960
+ * post process
961
+ */
962
+ if (RTEST(ret)) {
963
+ if (ary != NULL) free(ary);
964
+ if (rows != NULL) free(rows);
965
+ }
966
+
967
+ return ret;
622
968
  }
623
969
 
624
970
  /**
@@ -647,6 +993,7 @@ static VALUE
647
993
  rb_encoder_initialize(int argc, VALUE *argv, VALUE self)
648
994
  {
649
995
  jpeg_encode_t* ptr;
996
+ VALUE exc;
650
997
  VALUE wd;
651
998
  VALUE ht;
652
999
  VALUE opt;
@@ -654,137 +1001,169 @@ rb_encoder_initialize(int argc, VALUE *argv, VALUE self)
654
1001
  /*
655
1002
  * initialize
656
1003
  */
657
- Data_Get_Struct(self, jpeg_encode_t, ptr);
1004
+ exc = Qnil;
1005
+
1006
+ TypedData_Get_Struct(self, jpeg_encode_t, &jpeg_encoder_data_type, ptr);
658
1007
 
659
1008
  /*
660
1009
  * parse arguments
661
1010
  */
662
- rb_scan_args(argc, argv, "21", &wd, &ht, &opt);
1011
+ rb_scan_args(argc, argv, "2:", &wd, &ht, &opt);
663
1012
 
664
- Check_Type(wd, T_FIXNUM);
665
- Check_Type(ht, T_FIXNUM);
666
- if (opt != Qnil) Check_Type(opt, T_HASH);
1013
+ /*
1014
+ * argument check
1015
+ */
1016
+ do {
1017
+ if (TYPE(wd) != T_FIXNUM) {
1018
+ exc = create_argument_error("invalid width");
1019
+ break;
1020
+ }
1021
+
1022
+ if (TYPE(ht) != T_FIXNUM) {
1023
+ exc = create_argument_error("invalid height");
1024
+ break;
1025
+ }
1026
+ } while (0);
667
1027
 
668
1028
  /*
669
1029
  * set context
670
1030
  */
671
- set_encoder_context(ptr, FIX2INT(wd), FIX2INT(ht), opt);
1031
+ if (!RTEST(exc)) {
1032
+ exc = set_encoder_context(ptr, FIX2INT(wd), FIX2INT(ht), opt);
1033
+ }
1034
+
1035
+ /*
1036
+ * post process
1037
+ */
1038
+ if (RTEST(exc)) rb_exc_raise(exc);
672
1039
 
673
1040
  return Qtrue;
674
1041
  }
675
1042
 
676
- static int
677
- push_rows_yuv422(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1043
+ static void
1044
+ push_rows_yuv422(JSAMPROW dst, int wd, int st, uint8_t* data, int nrow)
678
1045
  {
679
- int size;
1046
+ uint8_t* src;
680
1047
  int i;
1048
+ int j;
681
1049
 
682
- size = wd * nrow;
1050
+ for (i = 0; i < nrow; i++) {
1051
+ src = data;
683
1052
 
684
- for (i = 0; i < size; i += 2) {
685
- rows[0] = data[0];
686
- rows[1] = data[1];
687
- rows[2] = data[3];
688
- rows[3] = data[2];
689
- rows[4] = data[1];
690
- rows[5] = data[3];
1053
+ for (j = 0; j < wd; j += 2) {
1054
+ dst[0] = src[0];
1055
+ dst[1] = src[1];
1056
+ dst[2] = src[3];
1057
+ dst[3] = src[2];
1058
+ dst[4] = src[1];
1059
+ dst[5] = src[3];
691
1060
 
692
- rows += 6;
693
- data += 4;
694
- }
1061
+ dst += 6;
1062
+ src += 4;
1063
+ }
695
1064
 
696
- return (size * 2);
1065
+ data += st;
1066
+ }
697
1067
  }
698
1068
 
699
- static int
700
- push_rows_rgb565(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1069
+ static void
1070
+ push_rows_rgb565(JSAMPROW dst, int wd, int st, uint8_t* data, int nrow)
701
1071
  {
702
- int size;
1072
+ uint8_t* src;
703
1073
  int i;
1074
+ int j;
704
1075
 
705
- size = wd * nrow;
1076
+ for (i = 0; i < nrow; i++) {
1077
+ src = data;
706
1078
 
707
- for (i = 0; i < size; i += 1) {
708
- rows[0] = data[1] & 0xf8;
709
- rows[1] = ((data[1] << 5) & 0xe0) | ((data[0] >> 3) & 0x1c);
710
- rows[2] = (data[0] << 3) & 0xf8;
1079
+ for (j = 0; j < wd; j++) {
1080
+ dst[0] = src[1] & 0xf8;
1081
+ dst[1] = ((src[1] << 5) & 0xe0) | ((src[0] >> 3) & 0x1c);
1082
+ dst[2] = (src[0] << 3) & 0xf8;
711
1083
 
712
- rows += 3;
713
- data += 2;
714
- }
1084
+ dst += 3;
1085
+ src += 2;
1086
+ }
715
1087
 
716
- return (size * 2);
1088
+ data += st;
1089
+ }
717
1090
  }
718
1091
 
719
- static int
720
- push_rows_comp3(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1092
+ static void
1093
+ push_rows_comp3(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
721
1094
  {
722
1095
  int size;
1096
+ int i;
1097
+
1098
+ size = wd * 3;
723
1099
 
724
- size = wd * nrow * 3;
725
- memcpy(rows, data, size);
1100
+ for (i = 0; i < nrow; i++) {
1101
+ memcpy(rows, data, size);
726
1102
 
727
- return size;
1103
+ rows += size;
1104
+ data += st;
1105
+ }
728
1106
  }
729
1107
 
730
- static int
731
- push_rows_comp4(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1108
+ static void
1109
+ push_rows_comp4(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
732
1110
  {
733
1111
  int size;
1112
+ int i;
734
1113
 
735
- size = wd * nrow * 4;
736
- memcpy(rows, data, size);
737
-
738
- return size;
739
- }
1114
+ size = wd * 4;
740
1115
 
1116
+ for (i = 0; i < nrow; i++) {
1117
+ memcpy(rows, data, size);
741
1118
 
1119
+ rows += size;
1120
+ data += st;
1121
+ }
1122
+ }
742
1123
 
743
- static int
744
- push_rows_grayscale(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1124
+ static void
1125
+ push_rows_grayscale(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
745
1126
  {
746
- int size;
1127
+ int i;
747
1128
 
748
- size = wd * nrow;
749
- memcpy(rows, data, size);
1129
+ for (i = 0; i < nrow; i++) {
1130
+ memcpy(rows, data, wd);
750
1131
 
751
- return size;
1132
+ rows += wd;
1133
+ data += st;
1134
+ }
752
1135
  }
753
1136
 
754
- static int
1137
+ static void
755
1138
  push_rows(jpeg_encode_t* ptr, uint8_t* data, int nrow)
756
1139
  {
757
- int ret;
758
-
759
1140
  switch (ptr->format) {
760
1141
  case FMT_YUV422:
761
- ret = push_rows_yuv422(ptr->rows, ptr->width, data, nrow);
1142
+ push_rows_yuv422(ptr->rows, ptr->width, ptr->stride, data, nrow);
762
1143
  break;
763
1144
 
764
1145
  case FMT_RGB565:
765
- ret = push_rows_rgb565(ptr->rows, ptr->width, data, nrow);
1146
+ push_rows_rgb565(ptr->rows, ptr->width, ptr->stride, data, nrow);
766
1147
  break;
767
1148
 
768
1149
  case FMT_YUV:
769
1150
  case FMT_RGB:
770
1151
  case FMT_BGR:
771
- ret = push_rows_comp3(ptr->rows, ptr->width, data, nrow);
1152
+ push_rows_comp3(ptr->rows, ptr->width, ptr->stride, data, nrow);
772
1153
  break;
773
1154
 
774
1155
  case FMT_RGB32:
775
1156
  case FMT_BGR32:
776
- ret = push_rows_comp4(ptr->rows, ptr->width, data, nrow);
1157
+ push_rows_comp4(ptr->rows, ptr->width, ptr->stride, data, nrow);
777
1158
  break;
778
1159
 
779
1160
  case FMT_GRAYSCALE:
780
- ret = push_rows_grayscale(ptr->rows, ptr->width, data, nrow);
1161
+ push_rows_grayscale(ptr->rows, ptr->width, ptr->stride, data, nrow);
781
1162
  break;
782
1163
 
783
1164
  default:
784
1165
  RUNTIME_ERROR("Really?");
785
1166
  }
786
-
787
- return ret;
788
1167
  }
789
1168
 
790
1169
  static void
@@ -816,46 +1195,60 @@ put_exif_tags(jpeg_encode_t* ptr)
816
1195
  }
817
1196
 
818
1197
  static VALUE
819
- do_encode(jpeg_encode_t* ptr, uint8_t* data)
1198
+ do_encode(VALUE _ptr)
820
1199
  {
821
1200
  VALUE ret;
822
-
823
- unsigned char* buf;
824
- unsigned long buf_size;
1201
+ jpeg_encode_t* ptr;
1202
+ uint8_t* data;
825
1203
  int nrow;
826
1204
 
827
- buf = NULL;
1205
+ /*
1206
+ * initialize
1207
+ */
1208
+ ret = Qnil;
1209
+ ptr = (jpeg_encode_t*)_ptr;
1210
+ data = (uint8_t*)RSTRING_PTR(ptr->data);
828
1211
 
829
- jpeg_mem_dest(&ptr->cinfo, &buf, &buf_size);
1212
+ /*
1213
+ * do encode
1214
+ */
1215
+ if (setjmp(ptr->err_mgr.jmpbuf)) {
1216
+ /*
1217
+ * when error occurred
1218
+ */
1219
+ jpeg_abort_compress(&ptr->cinfo);
1220
+ rb_raise(encerr_klass, "%s", ptr->err_mgr.msg);
830
1221
 
831
- jpeg_start_compress(&ptr->cinfo, TRUE);
1222
+ } else {
1223
+ /*
1224
+ * normal path
1225
+ */
1226
+ jpeg_start_compress(&ptr->cinfo, TRUE);
832
1227
 
833
- if (ptr->orientation != 0) {
834
- put_exif_tags(ptr);
835
- }
1228
+ if (ptr->orientation != 0) {
1229
+ put_exif_tags(ptr);
1230
+ }
836
1231
 
837
- while (ptr->cinfo.next_scanline < ptr->cinfo.image_height) {
838
- nrow = ptr->cinfo.image_height - ptr->cinfo.next_scanline;
839
- if (nrow > UNIT_LINES) nrow = UNIT_LINES;
1232
+ while (ptr->cinfo.next_scanline < ptr->cinfo.image_height) {
1233
+ nrow = ptr->cinfo.image_height - ptr->cinfo.next_scanline;
1234
+ if (nrow > UNIT_LINES) nrow = UNIT_LINES;
840
1235
 
841
- data += push_rows(ptr, data, nrow);
842
- jpeg_write_scanlines(&ptr->cinfo, ptr->array, nrow);
843
- }
1236
+ push_rows(ptr, data, nrow);
844
1237
 
845
- jpeg_finish_compress(&ptr->cinfo);
1238
+ jpeg_write_scanlines(&ptr->cinfo, ptr->array, nrow);
1239
+ data += (ptr->stride * nrow);
1240
+ }
846
1241
 
847
- /*
848
- * create return data
849
- */
850
- ret = rb_str_buf_new(buf_size);
851
- rb_str_set_len(ret, buf_size);
1242
+ jpeg_finish_compress(&ptr->cinfo);
852
1243
 
853
- memcpy(RSTRING_PTR(ret), buf, buf_size);
1244
+ /*
1245
+ * build return data
1246
+ */
1247
+ ret = rb_str_buf_new(ptr->buf.size);
1248
+ rb_str_set_len(ret, ptr->buf.size);
854
1249
 
855
- /*
856
- * post process
857
- */
858
- free(buf);
1250
+ memcpy(RSTRING_PTR(ret), ptr->buf.mem, ptr->buf.size);
1251
+ }
859
1252
 
860
1253
  return ret;
861
1254
  }
@@ -873,12 +1266,16 @@ static VALUE
873
1266
  rb_encoder_encode(VALUE self, VALUE data)
874
1267
  {
875
1268
  VALUE ret;
1269
+ int state;
876
1270
  jpeg_encode_t* ptr;
877
1271
 
878
1272
  /*
879
1273
  * initialize
880
1274
  */
881
- Data_Get_Struct(self, jpeg_encode_t, ptr);
1275
+ ret = Qnil;
1276
+ state = 0;
1277
+
1278
+ TypedData_Get_Struct(self, jpeg_encode_t, &jpeg_encoder_data_type, ptr);
882
1279
 
883
1280
  /*
884
1281
  * argument check
@@ -886,26 +1283,46 @@ rb_encoder_encode(VALUE self, VALUE data)
886
1283
  Check_Type(data, T_STRING);
887
1284
 
888
1285
  if (RSTRING_LEN(data) < ptr->data_size) {
889
- ARGUMENT_ERROR("raw image data is too short.");
1286
+ ARGUMENT_ERROR("image data is too short");
890
1287
  }
891
1288
 
892
1289
  if (RSTRING_LEN(data) > ptr->data_size) {
893
- ARGUMENT_ERROR("raw image data is too large.");
1290
+ ARGUMENT_ERROR("image data is too large");
894
1291
  }
895
1292
 
1293
+ /*
1294
+ * alloc memory
1295
+ */
1296
+ jpeg_mem_dest(&ptr->cinfo, &ptr->buf.mem, &ptr->buf.size);
1297
+ if (ptr->buf.mem == NULL) {
1298
+ RUNTIME_ERROR("jpeg_mem_dest() failed");
1299
+ }
1300
+
1301
+ /*
1302
+ * prepare
1303
+ */
1304
+ SET_DATA(ptr, data);
1305
+
896
1306
  /*
897
1307
  * do encode
898
1308
  */
899
- ret = do_encode(ptr, (uint8_t*)RSTRING_PTR(data));
1309
+ ret = rb_protect(do_encode, (VALUE)ptr, &state);
900
1310
 
901
- return ret;
902
- }
1311
+ /*
1312
+ * post process
1313
+ */
1314
+ CLR_DATA(ptr);
903
1315
 
904
- static void
905
- rb_decoder_free(void* ptr)
906
- {
907
- //jpeg_destroy_decompress(&(((jpeg_decode_t*)ptr)->cinfo));
908
- free(ptr);
1316
+ if (ptr->buf.mem != NULL) {
1317
+ free(ptr->buf.mem);
1318
+
1319
+ ptr->buf.mem = NULL;
1320
+ ptr->buf.size = 0;
1321
+ }
1322
+
1323
+ if (state != 0) rb_jump_tag(state);
1324
+
1325
+ return ret;
909
1326
  }
910
1327
 
911
1328
  static void
@@ -918,50 +1335,72 @@ rb_decoder_mark(void* _ptr)
918
1335
  if (ptr->orientation.buf != Qnil) {
919
1336
  rb_gc_mark(ptr->orientation.buf);
920
1337
  }
1338
+
1339
+ if (ptr->data != Qnil) {
1340
+ rb_gc_mark(ptr->data);
1341
+ }
921
1342
  }
922
1343
 
923
1344
  static void
924
- decode_output_message(j_common_ptr cinfo)
1345
+ rb_decoder_free(void* _ptr)
925
1346
  {
926
- ext_error_t* err;
1347
+ jpeg_decode_t* ptr;
927
1348
 
928
- err = (ext_error_t*)cinfo->err;
1349
+ ptr = (jpeg_decode_t*)_ptr;
929
1350
 
930
- (*err->jerr.format_message)(cinfo, err->msg);
931
- }
1351
+ if (ptr->array != NULL) {
1352
+ free(ptr->array);
1353
+ }
932
1354
 
933
- static void
934
- decode_emit_message(j_common_ptr cinfo, int msg_level)
935
- {
936
- ext_error_t* err;
1355
+ ptr->orientation.buf = Qnil;
1356
+ ptr->data = Qnil;
937
1357
 
938
- if (msg_level < 0) {
939
- err = (ext_error_t*)cinfo->err;
940
- (*err->jerr.format_message)(cinfo, err->msg);
941
- /*
942
- * 以前はemit_messageが呼ばれるとエラー扱いしていたが、
943
- * Logicoolの一部のモデルなどで問題が出るので無視する
944
- * ようにした。
945
- * また本来であれば、警告表示を行うべきでもあるが一部
946
- * のモデルで大量にemitされる場合があるので表示しない
947
- * ようにしている。
948
- * 問題が発生した際は、最後のメッセージをオブジェクト
949
- * のインスタンスとして持たすべき。
950
- */
951
- // longjmp(err->jmpbuf, 1);
1358
+ if (TEST_FLAG(ptr, F_CREAT)) {
1359
+ jpeg_destroy_decompress(&ptr->cinfo);
952
1360
  }
1361
+
1362
+ free(ptr);
953
1363
  }
954
1364
 
955
- static void
956
- decode_error_exit(j_common_ptr cinfo)
1365
+ static size_t
1366
+ rb_decoder_size(const void* ptr)
957
1367
  {
958
- ext_error_t* err;
1368
+ size_t ret;
959
1369
 
960
- err = (ext_error_t*)cinfo->err;
961
- (*err->jerr.format_message)(cinfo, err->msg);
962
- longjmp(err->jmpbuf, 1);
1370
+ ret = sizeof(jpeg_decode_t);
1371
+
1372
+ return ret;
963
1373
  }
964
1374
 
1375
+ #if RUBY_API_VERSION_CODE > 20600
1376
+ static const rb_data_type_t jpeg_decoder_data_type = {
1377
+ "libjpeg-ruby decoder object", // wrap_struct_name
1378
+ {
1379
+ rb_decoder_mark, // function.dmark
1380
+ rb_decoder_free, // function.dfree
1381
+ rb_decoder_size, // function.dsize
1382
+ NULL, // function.dcompact
1383
+ {NULL}, // function.reserved
1384
+ },
1385
+ NULL, // parent
1386
+ NULL, // data
1387
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
1388
+ };
1389
+ #else /* RUBY_API_VERSION_CODE > 20600 */
1390
+ static const rb_data_type_t jpeg_decoder_data_type = {
1391
+ "libjpeg-ruby decoder object", // wrap_struct_name
1392
+ {
1393
+ rb_decoder_mark, // function.dmark
1394
+ rb_decoder_free, // function.dfree
1395
+ rb_decoder_size, // function.dsize
1396
+ {NULL, NULL}, // function.reserved
1397
+ },
1398
+ NULL, // parent
1399
+ NULL, // data
1400
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
1401
+ };
1402
+ #endif /* RUBY_API_VERSION_CODE > 20600 */
1403
+
965
1404
  static VALUE
966
1405
  rb_decoder_alloc(VALUE self)
967
1406
  {
@@ -970,59 +1409,40 @@ rb_decoder_alloc(VALUE self)
970
1409
  ptr = ALLOC(jpeg_decode_t);
971
1410
  memset(ptr, 0, sizeof(*ptr));
972
1411
 
973
- ptr->flags = DEFAULT_FLAGS;
974
- ptr->format = FMT_RGB;
1412
+ ptr->flags = DEFAULT_DECODE_FLAGS;
975
1413
 
976
- ptr->out_color_space = JCS_RGB;
977
-
978
- ptr->scale_num = 1;
979
- ptr->scale_denom = 1;
980
-
981
- ptr->out_color_components = 3;
982
- ptr->output_gamma = 0.0;
983
- ptr->buffered_image = FALSE;
984
- ptr->do_fancy_upsampling = FALSE;
985
- ptr->do_block_smoothing = FALSE;
986
- ptr->quantize_colors = FALSE;
987
- ptr->dither_mode = JDITHER_NONE;
988
- ptr->dct_method = JDCT_FASTEST;
989
- ptr->desired_number_of_colors = 0;
990
- ptr->enable_1pass_quant = FALSE;
991
- ptr->enable_external_quant = FALSE;
992
- ptr->enable_2pass_quant = FALSE;
993
-
994
- ptr->orientation.value = 0;
995
- ptr->orientation.buf = Qnil;
996
-
997
- return Data_Wrap_Struct(decoder_klass, rb_decoder_mark, rb_decoder_free, ptr);
1414
+ return TypedData_Wrap_Struct(decoder_klass, &jpeg_decoder_data_type, ptr);
998
1415
  }
999
1416
 
1000
- static void
1001
- eval_decoder_opt_pixel_format(jpeg_decode_t* ptr, VALUE opt)
1417
+ static VALUE
1418
+ eval_decoder_pixel_format_opt(jpeg_decode_t* ptr, VALUE opt)
1002
1419
  {
1420
+ VALUE ret;
1003
1421
  int format;
1004
1422
  int color_space;
1005
1423
  int components;
1006
1424
 
1007
- if (opt != Qundef) {
1425
+ ret = Qnil;
1426
+
1427
+ switch (TYPE(opt)) {
1428
+ case T_UNDEF:
1429
+ format = FMT_RGB;
1430
+ color_space = JCS_RGB;
1431
+ components = 3;
1432
+ break;
1433
+
1434
+ case T_STRING:
1435
+ case T_SYMBOL:
1008
1436
  if(EQ_STR(opt, "RGB") || EQ_STR(opt, "RGB24")) {
1009
1437
  format = FMT_RGB;
1010
1438
  color_space = JCS_RGB;
1011
1439
  components = 3;
1012
1440
 
1013
1441
  } else if (EQ_STR(opt, "YUV422") || EQ_STR(opt, "YUYV")) {
1014
- format = FMT_YUV422;
1015
- color_space = JCS_YCbCr;
1016
- components = 3;
1017
-
1018
- NOT_IMPLEMENTED_ERROR( "not implemented colorspace");
1442
+ ret = create_not_implement_error( "not implemented colorspace");
1019
1443
 
1020
1444
  } else if (EQ_STR(opt, "RGB565")) {
1021
- format = FMT_RGB565;
1022
- color_space = JCS_RGB;
1023
- components = 3;
1024
-
1025
- NOT_IMPLEMENTED_ERROR( "not implemented colorspace");
1445
+ ret = create_not_implement_error( "not implemented colorspace");
1026
1446
 
1027
1447
  } else if (EQ_STR(opt, "GRAYSCALE")) {
1028
1448
  format = FMT_GRAYSCALE;
@@ -1055,277 +1475,479 @@ eval_decoder_opt_pixel_format(jpeg_decode_t* ptr, VALUE opt)
1055
1475
  components = 4;
1056
1476
 
1057
1477
  } else {
1058
- ARGUMENT_ERROR("Unsupportd :pixel_format option value.");
1478
+ ret = create_argument_error("unsupportd :pixel_format option value");
1059
1479
  }
1480
+ break;
1060
1481
 
1061
- ptr->format = format;
1062
- ptr->out_color_space = color_space;
1063
- ptr->out_color_components = components;
1482
+ default:
1483
+ ret = create_type_error("unsupportd :pixel_format option type");
1484
+ break;
1064
1485
  }
1486
+
1487
+ if (!RTEST(ret)) {
1488
+ ptr->format = format;
1489
+ ptr->out_color_space = color_space;
1490
+ ptr->out_color_components = components;
1491
+ }
1492
+
1493
+ return ret;
1065
1494
  }
1066
1495
 
1067
- static void
1068
- eval_decoder_opt_output_gamma(jpeg_decode_t* ptr, VALUE opt)
1496
+ static VALUE
1497
+ eval_decoder_output_gamma_opt(jpeg_decode_t* ptr, VALUE opt)
1069
1498
  {
1499
+ VALUE ret;
1500
+ double gamma;
1501
+
1502
+ ret = Qnil;
1503
+
1070
1504
  switch (TYPE(opt)) {
1071
1505
  case T_UNDEF:
1072
- // Nothing
1506
+ gamma = 0.0;
1073
1507
  break;
1074
1508
 
1075
1509
  case T_FIXNUM:
1076
1510
  case T_FLOAT:
1077
- ptr->output_gamma = NUM2DBL(opt);
1511
+ if (isnan(NUM2DBL(opt)) || isinf(NUM2DBL(opt))) {
1512
+ ret = create_argument_error("unsupported :output_gamma value");
1513
+ } else {
1514
+ gamma = NUM2DBL(opt);
1515
+ }
1078
1516
  break;
1079
1517
 
1080
1518
  default:
1081
- TYPE_ERROR("Unsupportd :output_gamma option value.");
1519
+ ret = create_type_error("unsupported :output_gamma type");
1082
1520
  break;
1083
1521
  }
1522
+
1523
+ if (!RTEST(ret)) ptr->output_gamma = gamma;
1524
+
1525
+ return ret;
1084
1526
  }
1085
1527
 
1086
- static void
1087
- eval_decoder_opt_do_fancy_upsampling(jpeg_decode_t* ptr, VALUE opt)
1528
+ static VALUE
1529
+ eval_decoder_do_fancy_upsampling_opt(jpeg_decode_t* ptr, VALUE opt)
1088
1530
  {
1089
- if (opt != Qundef) {
1090
- ptr->do_fancy_upsampling = (RTEST(opt))? TRUE: FALSE;
1531
+ if (opt != Qundef && RTEST(opt)) {
1532
+ ptr->do_fancy_upsampling = TRUE;
1533
+ } else {
1534
+ ptr->do_fancy_upsampling = FALSE;
1091
1535
  }
1536
+
1537
+ return Qnil;
1092
1538
  }
1093
1539
 
1094
- static void
1095
- eval_decoder_opt_do_smoothing(jpeg_decode_t* ptr, VALUE opt)
1540
+ static VALUE
1541
+ eval_decoder_do_smoothing_opt(jpeg_decode_t* ptr, VALUE opt)
1096
1542
  {
1097
- if (opt != Qundef) {
1098
- ptr->do_block_smoothing = (RTEST(opt))? TRUE: FALSE;
1543
+ if (opt != Qundef && RTEST(opt)) {
1544
+ ptr->do_block_smoothing = TRUE;
1545
+ } else {
1546
+ ptr->do_block_smoothing = FALSE;
1099
1547
  }
1548
+
1549
+ return Qnil;
1100
1550
  }
1101
1551
 
1102
- static void
1103
- eval_decoder_opt_dither( jpeg_decode_t* ptr, VALUE opt)
1552
+ static VALUE
1553
+ eval_decoder_dither_opt( jpeg_decode_t* ptr, VALUE opt)
1104
1554
  {
1105
- VALUE dmode;
1106
- VALUE pass2;
1107
- VALUE n_col;
1555
+ VALUE ret;
1556
+ VALUE tmp;
1557
+ int mode;
1558
+ int quant;
1559
+ int pass2;
1560
+ int ncol;
1108
1561
 
1109
- if (opt != Qundef) {
1110
- if (TYPE(opt) != T_ARRAY) {
1111
- TYPE_ERROR("Unsupportd :dither option value.");
1112
- }
1562
+ ret = Qnil;
1113
1563
 
1564
+ switch (TYPE(opt)) {
1565
+ case T_UNDEF:
1566
+ mode = JDITHER_NONE;
1567
+ quant = FALSE;
1568
+ ncol = 0;
1569
+ pass2 = FALSE;
1570
+ break;
1571
+
1572
+ case T_ARRAY:
1114
1573
  if (RARRAY_LEN(opt) != 3) {
1115
- ARGUMENT_ERROR(":dither is illeagal length (shall be 3 entries).");
1116
- }
1574
+ ret = create_argument_error(":dither invalid size");
1575
+
1576
+ } else do {
1577
+ /*
1578
+ * dither mode
1579
+ */
1580
+ tmp = rb_ary_entry(opt, 0);
1581
+ if (TYPE(tmp) != T_STRING && TYPE(tmp) != T_SYMBOL) {
1582
+ ret = create_type_error("unsupported dither mode type");
1583
+ break;
1117
1584
 
1118
- dmode = RARRAY_AREF(opt, 0);
1119
- pass2 = RARRAY_AREF(opt, 1);
1120
- n_col = RARRAY_AREF(opt, 2);
1121
-
1122
- if (EQ_STR(dmode, "NONE")) {
1123
- ptr->dither_mode = JDITHER_NONE;
1124
- ptr->quantize_colors = FALSE;
1585
+ } else if (EQ_STR(tmp, "NONE")) {
1586
+ mode = JDITHER_NONE;
1587
+ quant = FALSE;
1125
1588
 
1126
- } else if(EQ_STR(dmode, "ORDERED")) {
1127
- ptr->dither_mode = JDITHER_ORDERED;
1128
- ptr->quantize_colors = TRUE;
1589
+ } else if(EQ_STR(tmp, "ORDERED")) {
1590
+ mode = JDITHER_ORDERED;
1591
+ quant = TRUE;
1129
1592
 
1130
- } else if(EQ_STR(dmode, "FS")) {
1131
- ptr->dither_mode = JDITHER_FS;
1132
- ptr->quantize_colors = TRUE;
1593
+ } else if(EQ_STR(tmp, "FS")) {
1594
+ mode = JDITHER_FS;
1595
+ quant = TRUE;
1133
1596
 
1134
- } else {
1135
- ARGUMENT_ERROR("dither mode is illeagal value.");
1136
- }
1597
+ } else {
1598
+ ret = create_argument_error("dither mode is illeagal value.");
1599
+ break;
1600
+ }
1137
1601
 
1138
- ptr->two_pass_quantize = (RTEST(pass2))? TRUE: FALSE;
1602
+ /*
1603
+ * 2 pass flag
1604
+ */
1605
+ pass2 = (RTEST(rb_ary_entry(opt, 1)))? TRUE: FALSE;
1606
+
1607
+ /*
1608
+ * number of color
1609
+ */
1610
+ tmp = rb_ary_entry(opt, 2);
1611
+ if (TYPE(tmp) != T_FIXNUM) {
1612
+ ret = create_type_error("unsupported number of colors type");
1613
+ break;
1139
1614
 
1140
- if (TYPE(n_col) == T_FIXNUM) {
1141
- ptr->desired_number_of_colors = FIX2INT(n_col);
1615
+ } else if (FIX2LONG(tmp) < 8) {
1616
+ ret = create_range_error("number of colors less than 0");
1617
+ break;
1142
1618
 
1143
- if (ptr->desired_number_of_colors < 8 ||
1144
- ptr->desired_number_of_colors > 256) {
1145
- RANGE_ERROR("number of dithered colors shall be from 8 to 256.");
1146
- }
1619
+ } else if (FIX2LONG(tmp) > 256) {
1620
+ ret = create_range_error("number of colors greater than 256");
1621
+ break;
1147
1622
 
1148
- } else {
1149
- TYPE_ERROR("number of dithered colors is illeagal value.");
1150
- }
1623
+ } else {
1624
+ ncol = FIX2INT(tmp);
1625
+ }
1626
+ } while (0);
1627
+ break;
1151
1628
 
1152
- SET_FLAG(ptr, F_DITHER);
1629
+ default:
1630
+ ret = create_type_error("unsupported :dither type");
1631
+ break;
1153
1632
  }
1633
+
1634
+ if (!RTEST(ret)) {
1635
+ ptr->dither_mode = mode;
1636
+ ptr->quantize_colors = quant;
1637
+ ptr->two_pass_quantize = pass2;
1638
+ ptr->desired_number_of_colors = ncol;
1639
+
1640
+ if (mode != JDITHER_NONE) SET_FLAG(ptr, F_DITHER);
1641
+ }
1642
+
1643
+ return ret;
1154
1644
  }
1155
1645
 
1156
1646
  #if 0
1157
1647
  static void
1158
- eval_decoder_opt_use_1pass_quantizer(jpeg_decode_t* ptr, VALUE opt)
1648
+ eval_decoder_use_1pass_quantizer_opt(jpeg_decode_t* ptr, VALUE opt)
1159
1649
  {
1160
- if (opt != Qundef) {
1161
- if (RTEST(opt)) {
1162
- ptr->enable_1pass_quant = TRUE;
1163
- ptr->buffered_image = TRUE;
1164
- } else {
1165
- ptr->enable_1pass_quant = FALSE;
1166
- }
1650
+ if (opt != Qundef && RTEST(opt)) {
1651
+ ptr->enable_1pass_quant = TRUE;
1652
+ } else {
1653
+ ptr->enable_1pass_quant = FALSE;
1167
1654
  }
1655
+
1656
+ return Qnil;
1168
1657
  }
1169
1658
 
1170
- static void
1171
- eval_decoder_opt_use_external_colormap(jpeg_decode_t* ptr, VALUE opt)
1659
+ static VALUE
1660
+ eval_decoder_use_external_colormap_opt(jpeg_decode_t* ptr, VALUE opt)
1172
1661
  {
1173
- if (opt != Qundef) {
1174
- if (RTEST(opt)) {
1662
+ if (opt != Qundef && RTEST(opt)) {
1175
1663
  ptr->enable_external_quant = TRUE;
1176
- ptr->buffered_image = TRUE;
1177
1664
  } else {
1178
1665
  ptr->enable_external_quant = FALSE;
1179
1666
  }
1180
1667
  }
1668
+
1669
+ return Qnil;
1181
1670
  }
1182
1671
 
1183
- static void
1184
- eval_decoder_opt_use_2pass_quantizer(jpeg_decode_t* ptr, VALUE opt)
1672
+ static VALUE
1673
+ eval_decoder_use_2pass_quantizer_opt(jpeg_decode_t* ptr, VALUE opt)
1185
1674
  {
1186
- if (opt != Qundef) {
1187
- if (RTEST(opt)) {
1675
+ if (opt != Qundef && RTEST(opt)) {
1188
1676
  ptr->enable_2pass_quant = TRUE;
1189
- ptr->buffered_image = TRUE;
1190
1677
  } else {
1191
1678
  ptr->enable_2pass_quant = FALSE;
1192
1679
  }
1193
1680
  }
1681
+
1682
+ return Qnil;
1194
1683
  }
1195
1684
  #endif
1196
1685
 
1197
- static void
1198
- eval_decoder_opt_without_meta(jpeg_decode_t* ptr, VALUE opt)
1686
+ static VALUE
1687
+ eval_decoder_without_meta_opt(jpeg_decode_t* ptr, VALUE opt)
1199
1688
  {
1200
- if (opt != Qundef) {
1201
- if (RTEST(opt)) {
1202
- CLR_FLAG(ptr, F_NEED_META);
1203
- } else {
1204
- SET_FLAG(ptr, F_NEED_META);
1205
- }
1689
+ if (opt != Qundef && RTEST(opt)) {
1690
+ CLR_FLAG(ptr, F_NEED_META);
1691
+ } else {
1692
+ SET_FLAG(ptr, F_NEED_META);
1206
1693
  }
1694
+
1695
+ return Qnil;
1207
1696
  }
1208
1697
 
1209
- static void
1210
- eval_decoder_opt_expand_colormap(jpeg_decode_t* ptr, VALUE opt)
1698
+ static VALUE
1699
+ eval_decoder_expand_colormap_opt(jpeg_decode_t* ptr, VALUE opt)
1211
1700
  {
1212
- if (opt != Qundef) {
1213
- if (RTEST(opt)) {
1214
- SET_FLAG(ptr, F_EXPAND_COLORMAP);
1215
- } else {
1216
- CLR_FLAG(ptr, F_EXPAND_COLORMAP);
1217
- }
1701
+ if (opt != Qundef && RTEST(opt)) {
1702
+ SET_FLAG(ptr, F_EXPAND_COLORMAP);
1703
+ } else {
1704
+ CLR_FLAG(ptr, F_EXPAND_COLORMAP);
1218
1705
  }
1706
+
1707
+ return Qnil;
1219
1708
  }
1220
1709
 
1221
- static void
1222
- eval_decoder_opt_scale(jpeg_decode_t* ptr, VALUE opt)
1710
+
1711
+ static VALUE
1712
+ eval_decoder_scale_opt(jpeg_decode_t* ptr, VALUE opt)
1223
1713
  {
1714
+ VALUE ret;
1715
+ int scale_num;
1716
+ int scale_denom;
1717
+
1718
+ ret = Qnil;
1719
+
1224
1720
  switch (TYPE(opt)) {
1225
1721
  case T_UNDEF:
1226
- // Nothing
1722
+ scale_num = 1;
1723
+ scale_denom = 1;
1227
1724
  break;
1228
1725
 
1229
- case T_FLOAT:
1230
- ptr->scale_num = (int)(NUM2DBL(opt) * 1000.0);
1231
- ptr->scale_denom = 1000;
1232
- break;
1726
+ case T_FIXNUM:
1727
+ if (FIX2LONG(opt) <= 0) {
1728
+ ret = create_range_error(":scale less equal 0");
1233
1729
 
1234
- case T_RATIONAL:
1235
- ptr->scale_num = FIX2INT(rb_rational_num(opt));
1236
- ptr->scale_denom = FIX2INT(rb_rational_den(opt));
1730
+ } else {
1731
+ scale_num = FIX2INT(opt) * 1000;
1732
+ scale_denom = 1000;
1733
+ }
1237
1734
  break;
1238
1735
 
1239
- case T_ARRAY:
1240
- if (RARRAY_LEN(opt) != 2) {
1241
- ARGUMENT_ERROR("invalid length");
1736
+ case T_FLOAT:
1737
+ if (isnan(NUM2DBL(opt)) || isinf(NUM2DBL(opt))) {
1738
+ ret = create_argument_error("unsupportd :quality option value");
1739
+
1740
+ } else if (NUM2DBL(opt) <= 0.0) {
1741
+ ret = create_range_error(":scale less equal 0");
1742
+
1743
+ } else {
1744
+ scale_num = (int)(NUM2DBL(opt) * 1000.0);
1745
+ scale_denom = 1000;
1242
1746
  }
1243
- ptr->scale_num = FIX2INT(RARRAY_AREF(opt, 0));
1244
- ptr->scale_denom = FIX2INT(RARRAY_AREF(opt, 1));
1747
+ break;
1748
+
1749
+ case T_RATIONAL:
1750
+ scale_num = (int)FIX2LONG(rb_rational_num(opt));
1751
+ scale_denom = (int)FIX2LONG(rb_rational_den(opt));
1245
1752
  break;
1246
1753
 
1247
1754
  default:
1248
- TYPE_ERROR("Unsupportd :exapnd_colormap option value.");
1755
+ ret = create_type_error("unsupportd :scale option type");
1249
1756
  break;
1250
1757
  }
1758
+
1759
+ if (!RTEST(ret)) {
1760
+ ptr->scale_num = scale_num;
1761
+ ptr->scale_denom = scale_denom;
1762
+ }
1763
+
1764
+ return ret;
1251
1765
  }
1252
1766
 
1253
- static void
1254
- eval_decoder_opt_dct_method(jpeg_decode_t* ptr, VALUE opt)
1767
+ static VALUE
1768
+ eval_decoder_dct_method_opt(jpeg_decode_t* ptr, VALUE opt)
1255
1769
  {
1256
- if (opt != Qundef) {
1257
- if (EQ_STR(opt, "ISLOW")) {
1258
- ptr->dct_method = JDCT_ISLOW;
1770
+ VALUE ret;
1771
+ int dct_method;
1772
+
1773
+ ret = Qnil;
1774
+
1775
+ switch (TYPE(opt)) {
1776
+ case T_UNDEF:
1777
+ dct_method = JDCT_FASTEST;
1778
+ break;
1779
+
1780
+ case T_STRING:
1781
+ case T_SYMBOL:
1782
+ if (EQ_STR(opt, "FASTEST")) {
1783
+ dct_method = JDCT_FASTEST;
1784
+
1785
+ } else if (EQ_STR(opt, "ISLOW")) {
1786
+ dct_method = JDCT_ISLOW;
1259
1787
 
1260
1788
  } else if (EQ_STR(opt, "IFAST")) {
1261
- ptr->dct_method = JDCT_IFAST;
1789
+ dct_method = JDCT_IFAST;
1262
1790
 
1263
1791
  } else if (EQ_STR(opt, "FLOAT")) {
1264
- ptr->dct_method = JDCT_FLOAT;
1265
-
1266
- } else if (EQ_STR(opt, "FASTEST")) {
1267
- ptr->dct_method = JDCT_FASTEST;
1792
+ dct_method = JDCT_FLOAT;
1268
1793
 
1269
1794
  } else {
1270
- ARGUMENT_ERROR("Unsupportd :dct_method option value.");
1795
+ ret = create_argument_error("unsupportd :dct_method option value");
1271
1796
  }
1797
+ break;
1798
+
1799
+ default:
1800
+ ret = create_type_error("unsupportd :dct_method option type");
1801
+ break;
1272
1802
  }
1803
+
1804
+ if (!RTEST(ret)) ptr->dct_method = dct_method;
1805
+
1806
+ return ret;
1273
1807
  }
1274
1808
 
1275
- static void
1276
- eval_decoder_opt_with_exif_tags(jpeg_decode_t* ptr, VALUE opt)
1809
+ static VALUE
1810
+ eval_decoder_with_exif_tags_opt(jpeg_decode_t* ptr, VALUE opt)
1277
1811
  {
1278
- if (opt != Qundef) {
1279
- if (RTEST(opt)) {
1280
- SET_FLAG(ptr, F_PARSE_EXIF);
1281
- } else {
1282
- CLR_FLAG(ptr, F_PARSE_EXIF);
1283
- }
1812
+ if (opt != Qundef && RTEST(opt)) {
1813
+ SET_FLAG(ptr, F_PARSE_EXIF);
1814
+ } else {
1815
+ CLR_FLAG(ptr, F_PARSE_EXIF);
1284
1816
  }
1817
+
1818
+ return Qnil;
1285
1819
  }
1286
1820
 
1287
- static void
1288
- eval_decoder_opt_orientation(jpeg_decode_t* ptr, VALUE opt)
1821
+ static VALUE
1822
+ eval_decoder_orientation_opt(jpeg_decode_t* ptr, VALUE opt)
1289
1823
  {
1290
- if (opt != Qundef) {
1291
- if (RTEST(opt)) {
1292
- SET_FLAG(ptr, F_APPLY_ORIENTATION);
1293
- } else {
1294
- CLR_FLAG(ptr, F_APPLY_ORIENTATION);
1295
- }
1824
+ if (opt != Qundef && RTEST(opt)) {
1825
+ SET_FLAG(ptr, F_APPLY_ORIENTATION);
1826
+ } else {
1827
+ CLR_FLAG(ptr, F_APPLY_ORIENTATION);
1296
1828
  }
1829
+
1830
+ return Qnil;
1297
1831
  }
1298
1832
 
1299
- static void
1833
+ static VALUE
1300
1834
  set_decoder_context( jpeg_decode_t* ptr, VALUE opt)
1301
1835
  {
1836
+ VALUE ret;
1302
1837
  VALUE opts[N(decoder_opts_ids)];
1838
+ JSAMPARRAY ary;
1839
+
1840
+ /*
1841
+ * initialize
1842
+ */
1843
+ ret = Qnil;
1844
+ ary = NULL;
1303
1845
 
1304
1846
  /*
1305
1847
  * parse options
1306
1848
  */
1307
- rb_get_kwargs(opt, decoder_opts_ids, 0, N(decoder_opts_ids), opts);
1849
+ do {
1850
+ rb_get_kwargs(opt, decoder_opts_ids, 0, N(decoder_opts_ids), opts);
1851
+
1852
+ /*
1853
+ * set context
1854
+ */
1855
+ ret = eval_decoder_pixel_format_opt(ptr, opts[0]);
1856
+ if (RTEST(ret)) break;
1857
+
1858
+ ret = eval_decoder_output_gamma_opt(ptr, opts[1]);
1859
+ if (RTEST(ret)) break;
1860
+
1861
+ ret = eval_decoder_do_fancy_upsampling_opt(ptr, opts[2]);
1862
+ if (RTEST(ret)) break;
1863
+
1864
+ ret = eval_decoder_do_smoothing_opt(ptr, opts[3]);
1865
+ if (RTEST(ret)) break;
1866
+
1867
+ ret = eval_decoder_dither_opt(ptr, opts[4]);
1868
+ if (RTEST(ret)) break;
1869
+
1870
+ #if 0
1871
+ ret = eval_decoder_use_1pass_quantizer_opt(ptr, opts[5]);
1872
+ if (RTEST(ret)) break;
1873
+
1874
+ ret = eval_decoder_use_external_colormap_opt(ptr, opts[6]);
1875
+ if (RTEST(ret)) break;
1876
+
1877
+ ret = eval_decoder_use_2pass_quantizer_opt(ptr, opts[7]);
1878
+ if (RTEST(ret)) break;
1879
+ #endif
1880
+
1881
+ ret = eval_decoder_without_meta_opt(ptr, opts[5]);
1882
+ if (RTEST(ret)) break;
1883
+
1884
+ ret = eval_decoder_expand_colormap_opt(ptr, opts[6]);
1885
+ if (RTEST(ret)) break;
1886
+
1887
+ ret = eval_decoder_scale_opt(ptr, opts[7]);
1888
+ if (RTEST(ret)) break;
1889
+
1890
+ ret = eval_decoder_dct_method_opt(ptr, opts[8]);
1891
+ if (RTEST(ret)) break;
1892
+
1893
+ ret = eval_decoder_with_exif_tags_opt(ptr, opts[9]);
1894
+ if (RTEST(ret)) break;
1895
+
1896
+ ret = eval_decoder_orientation_opt(ptr, opts[10]);
1897
+ if (RTEST(ret)) break;
1898
+ } while (0);
1308
1899
 
1309
1900
  /*
1310
- * set context
1901
+ * alloc memory
1902
+ */
1903
+ if (!RTEST(ret)) {
1904
+ ary = ALLOC_ARRAY();
1905
+ if (ary == NULL) ret = create_memory_error();
1906
+ }
1907
+
1908
+ /*
1909
+ * set the rest context parameter
1311
1910
  */
1312
- eval_decoder_opt_pixel_format(ptr, opts[0]);
1313
- eval_decoder_opt_output_gamma(ptr, opts[1]);
1314
- eval_decoder_opt_do_fancy_upsampling(ptr, opts[2]);
1315
- eval_decoder_opt_do_smoothing(ptr, opts[3]);
1316
- eval_decoder_opt_dither(ptr, opts[4]);
1911
+ if (!RTEST(ret)) {
1912
+ ptr->err_mgr.jerr.output_message = output_message;
1913
+ ptr->err_mgr.jerr.emit_message = emit_message;
1914
+ ptr->err_mgr.jerr.error_exit = error_exit;
1915
+
1916
+ // 現時点でオプションでの対応をおこなっていないので
1917
+ // ここで値を設定
1918
+ ptr->enable_1pass_quant = FALSE;
1919
+ ptr->enable_external_quant = FALSE;
1920
+ ptr->enable_2pass_quant = FALSE;
1921
+ ptr->buffered_image = FALSE;
1922
+
1317
1923
  #if 0
1318
- eval_decoder_opt_use_1pass_quantizer(ptr, opts[5]);
1319
- eval_decoder_opt_use_external_colormap(ptr, opts[6]);
1320
- eval_decoder_opt_use_2pass_quantizer(ptr, opts[7]);
1924
+ if (ptr->enable_1pass_quant == TRUE ||
1925
+ ptr->enable_external_quant == TRUE ||
1926
+ ptr->enable_2pass_quant == TRUE) {
1927
+ ptr->buffered_image = TRUE;
1928
+
1929
+ } else {
1930
+ ptr->buffered_image = FALSE;
1931
+ }
1321
1932
  #endif
1322
- eval_decoder_opt_without_meta(ptr, opts[5]);
1323
- eval_decoder_opt_expand_colormap(ptr, opts[6]);
1324
- eval_decoder_opt_scale(ptr, opts[7]);
1325
- eval_decoder_opt_dct_method(ptr, opts[8]);
1326
- eval_decoder_opt_with_exif_tags(ptr, opts[9]);
1327
- eval_decoder_opt_with_exif_tags(ptr, opts[10]);
1328
- eval_decoder_opt_orientation(ptr, opts[11]);
1933
+
1934
+ ptr->array = ary;
1935
+ ptr->data = Qnil;
1936
+ ptr->orientation.value = 0;
1937
+ ptr->orientation.buf = Qnil;
1938
+ }
1939
+
1940
+ /*
1941
+ * setup libjpeg
1942
+ */
1943
+ if (!RTEST(ret)) {
1944
+ jpeg_create_decompress(&ptr->cinfo);
1945
+ SET_FLAG(ptr, F_CREAT);
1946
+
1947
+ ptr->cinfo.err = jpeg_std_error(&ptr->err_mgr.jerr);
1948
+ }
1949
+
1950
+ return ret;
1329
1951
  }
1330
1952
 
1331
1953
  /**
@@ -1380,24 +2002,28 @@ static VALUE
1380
2002
  rb_decoder_initialize( int argc, VALUE *argv, VALUE self)
1381
2003
  {
1382
2004
  jpeg_decode_t* ptr;
2005
+ VALUE exc;
1383
2006
  VALUE opt;
1384
2007
 
1385
2008
  /*
1386
2009
  * initialize
1387
2010
  */
1388
- Data_Get_Struct(self, jpeg_decode_t, ptr);
2011
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
1389
2012
 
1390
2013
  /*
1391
2014
  * parse arguments
1392
2015
  */
1393
- rb_scan_args( argc, argv, "01", &opt);
1394
-
1395
- if (opt != Qnil) Check_Type(opt, T_HASH);
2016
+ rb_scan_args( argc, argv, "0:", &opt);
1396
2017
 
1397
2018
  /*
1398
2019
  * set context
1399
2020
  */
1400
- set_decoder_context(ptr, opt);
2021
+ exc = set_decoder_context(ptr, opt);
2022
+
2023
+ /*
2024
+ * post process
2025
+ */
2026
+ if (RTEST(exc)) rb_exc_raise(exc);
1401
2027
 
1402
2028
  return Qtrue;
1403
2029
  }
@@ -1406,11 +2032,12 @@ static VALUE
1406
2032
  rb_decoder_set(VALUE self, VALUE opt)
1407
2033
  {
1408
2034
  jpeg_decode_t* ptr;
2035
+ VALUE exc;
1409
2036
 
1410
2037
  /*
1411
2038
  * initialize
1412
2039
  */
1413
- Data_Get_Struct(self, jpeg_decode_t, ptr);
2040
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
1414
2041
 
1415
2042
  /*
1416
2043
  * check argument
@@ -1420,7 +2047,12 @@ rb_decoder_set(VALUE self, VALUE opt)
1420
2047
  /*
1421
2048
  * set context
1422
2049
  */
1423
- set_decoder_context(ptr, opt);
2050
+ exc = set_decoder_context(ptr, opt);
2051
+
2052
+ /*
2053
+ * post process
2054
+ */
2055
+ if (RTEST(exc)) rb_exc_raise(exc);
1424
2056
 
1425
2057
  return Qtrue;
1426
2058
  }
@@ -1497,7 +2129,7 @@ get_colorspace_str( J_COLOR_SPACE cs)
1497
2129
  break;
1498
2130
  }
1499
2131
 
1500
- return rb_str_new_cstr(cstr);
2132
+ return rb_str_freeze(rb_str_new_cstr(cstr));
1501
2133
  }
1502
2134
 
1503
2135
  typedef struct {
@@ -1693,6 +2325,8 @@ exif_fetch_byte_data(exif_t* ptr, VALUE* dst)
1693
2325
  for (i = 0; i < (int)n; i++) {
1694
2326
  rb_ary_push(obj, INT2FIX(p[i]));
1695
2327
  }
2328
+
2329
+ rb_ary_freeze(obj);
1696
2330
  break;
1697
2331
  }
1698
2332
 
@@ -1716,6 +2350,7 @@ exif_fetch_ascii_data(exif_t* ptr, VALUE* dst)
1716
2350
 
1717
2351
  obj = rb_utf8_str_new((char*)p, n);
1718
2352
  rb_funcall(obj, rb_intern("strip!"), 0);
2353
+ rb_str_freeze(obj);
1719
2354
 
1720
2355
  *dst = obj;
1721
2356
  }
@@ -1750,6 +2385,8 @@ exif_fetch_short_data(exif_t* ptr, VALUE* dst)
1750
2385
  rb_ary_push(obj, INT2FIX(get_u16(p, ptr->be)));
1751
2386
  p += 2;
1752
2387
  }
2388
+
2389
+ rb_ary_freeze(obj);
1753
2390
  break;
1754
2391
  }
1755
2392
 
@@ -1784,6 +2421,8 @@ exif_fetch_long_data(exif_t* ptr, VALUE* dst)
1784
2421
  rb_ary_push(obj, INT2FIX(get_u32(p, ptr->be)));
1785
2422
  p += 4;
1786
2423
  }
2424
+
2425
+ rb_ary_freeze(obj);
1787
2426
  break;
1788
2427
  }
1789
2428
 
@@ -1794,6 +2433,7 @@ static void
1794
2433
  exif_fetch_rational_data(exif_t* ptr, VALUE* dst)
1795
2434
  {
1796
2435
  VALUE obj;
2436
+ VALUE val;
1797
2437
 
1798
2438
  int i;
1799
2439
  uint32_t n;
@@ -1816,6 +2456,7 @@ exif_fetch_rational_data(exif_t* ptr, VALUE* dst)
1816
2456
  deno = 1;
1817
2457
  }
1818
2458
  obj = rb_rational_new(INT2FIX(num), INT2FIX(deno));
2459
+ rb_obj_freeze(obj);
1819
2460
  break;
1820
2461
 
1821
2462
  default:
@@ -1826,9 +2467,15 @@ exif_fetch_rational_data(exif_t* ptr, VALUE* dst)
1826
2467
  if (num == 0 && deno == 0) {
1827
2468
  deno = 1;
1828
2469
  }
1829
- rb_ary_push(obj, rb_rational_new(INT2FIX(num), INT2FIX(deno)));
2470
+
2471
+ val = rb_rational_new(INT2FIX(num), INT2FIX(deno));
2472
+ rb_obj_freeze(val);
2473
+
2474
+ rb_ary_push(obj, val);
1830
2475
  p += 8;
1831
2476
  }
2477
+
2478
+ rb_ary_freeze(obj);
1832
2479
  break;
1833
2480
  }
1834
2481
 
@@ -1851,6 +2498,7 @@ exif_fetch_undefined_data(exif_t* ptr, VALUE* dst)
1851
2498
  }
1852
2499
 
1853
2500
  obj = rb_enc_str_new((char*)p, n, rb_ascii8bit_encoding());
2501
+ rb_str_freeze(obj);
1854
2502
 
1855
2503
  *dst = obj;
1856
2504
  }
@@ -1883,6 +2531,8 @@ exif_fetch_slong_data(exif_t* ptr, VALUE* dst)
1883
2531
  rb_ary_push(obj, INT2FIX(get_s32(p, ptr->be)));
1884
2532
  p += 4;
1885
2533
  }
2534
+
2535
+ rb_ary_freeze(obj);
1886
2536
  break;
1887
2537
  }
1888
2538
 
@@ -1893,6 +2543,7 @@ static void
1893
2543
  exif_fetch_srational_data(exif_t* ptr, VALUE* dst)
1894
2544
  {
1895
2545
  VALUE obj;
2546
+ VALUE val;
1896
2547
 
1897
2548
  int i;
1898
2549
  uint32_t n;
@@ -1925,9 +2576,15 @@ exif_fetch_srational_data(exif_t* ptr, VALUE* dst)
1925
2576
  if (num == 0 && deno == 0) {
1926
2577
  deno = 1;
1927
2578
  }
1928
- rb_ary_push(obj, rb_rational_new(INT2FIX(num), INT2FIX(deno)));
2579
+
2580
+ val = rb_rational_new(INT2FIX(num), INT2FIX(deno));
2581
+ rb_obj_freeze(val);
2582
+
2583
+ rb_ary_push(obj, val);
1929
2584
  p += 8;
1930
2585
  }
2586
+
2587
+ rb_ary_freeze(obj);
1931
2588
  break;
1932
2589
  }
1933
2590
 
@@ -2088,7 +2745,10 @@ create_exif_tags_hash(jpeg_decode_t* ptr)
2088
2745
 
2089
2746
  if (TYPE(off) == T_FIXNUM && TYPE(size) == T_FIXNUM) {
2090
2747
  data = rb_enc_str_new((char*)exif.head + FIX2INT(off),
2091
- FIX2INT(size), rb_ascii8bit_encoding());
2748
+ FIX2INT(size),
2749
+ rb_ascii8bit_encoding());
2750
+
2751
+ rb_str_freeze(data);
2092
2752
 
2093
2753
  rb_hash_lookup(info, THUMBNAIL_OFFSET);
2094
2754
  rb_hash_lookup(info, THUMBNAIL_SIZE);
@@ -2099,6 +2759,8 @@ create_exif_tags_hash(jpeg_decode_t* ptr)
2099
2759
  break;
2100
2760
  }
2101
2761
 
2762
+ rb_hash_freeze(ret);
2763
+
2102
2764
  return ret;
2103
2765
  }
2104
2766
 
@@ -2229,6 +2891,8 @@ create_colormap(jpeg_decode_t* ptr)
2229
2891
  RUNTIME_ERROR("this number of components is not implemented yet");
2230
2892
  }
2231
2893
 
2894
+ rb_ary_freeze(ret);
2895
+
2232
2896
  return ret;
2233
2897
  }
2234
2898
 
@@ -2267,7 +2931,7 @@ create_meta(jpeg_decode_t* ptr)
2267
2931
  rb_ivar_set(ret, id_orig_cs, get_colorspace_str(cinfo->jpeg_color_space));
2268
2932
 
2269
2933
  if (ptr->format == FMT_YVU) {
2270
- rb_ivar_set(ret, id_out_cs, rb_str_new_cstr("YCrCb"));
2934
+ rb_ivar_set(ret, id_out_cs, rb_str_freeze(rb_str_new_cstr("YCrCb")));
2271
2935
  } else {
2272
2936
  rb_ivar_set(ret, id_out_cs, get_colorspace_str(cinfo->out_color_space));
2273
2937
  }
@@ -2287,37 +2951,45 @@ create_meta(jpeg_decode_t* ptr)
2287
2951
  if (TEST_FLAG(ptr, F_DITHER)) {
2288
2952
  rb_ivar_set(ret, id_colormap, create_colormap(ptr));
2289
2953
  }
2954
+
2955
+ rb_obj_freeze(ret);
2290
2956
 
2291
2957
  return ret;
2292
2958
  }
2293
2959
 
2294
2960
  static VALUE
2295
- do_read_header(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
2961
+ do_read_header(VALUE _ptr)
2296
2962
  {
2297
2963
  VALUE ret;
2964
+ jpeg_decode_t* ptr;
2965
+ uint8_t* data;
2966
+ size_t size;
2298
2967
 
2299
- switch (ptr->format) {
2300
- case FMT_YUV422:
2301
- case FMT_RGB565:
2302
- NOT_IMPLEMENTED_ERROR( "not implemented colorspace");
2303
- break;
2304
- }
2305
-
2306
- jpeg_create_decompress(&ptr->cinfo);
2307
-
2308
- ptr->cinfo.err = jpeg_std_error(&ptr->err_mgr.jerr);
2309
- ptr->err_mgr.jerr.output_message = decode_output_message;
2310
- ptr->err_mgr.jerr.emit_message = decode_emit_message;
2311
- ptr->err_mgr.jerr.error_exit = decode_error_exit;
2968
+ /*
2969
+ * initialize
2970
+ */
2971
+ ret = Qnil;
2972
+ ptr = (jpeg_decode_t*)_ptr;
2973
+ data = (uint8_t*)RSTRING_PTR(ptr->data);
2974
+ size = RSTRING_LEN(ptr->data);
2312
2975
 
2313
- ptr->cinfo.raw_data_out = FALSE;
2314
- ptr->cinfo.dct_method = JDCT_FLOAT;
2976
+ /*
2977
+ * process body
2978
+ */
2979
+ ptr->cinfo.raw_data_out = FALSE;
2980
+ ptr->cinfo.dct_method = JDCT_FLOAT;
2315
2981
 
2316
2982
  if (setjmp(ptr->err_mgr.jmpbuf)) {
2317
- jpeg_destroy_decompress(&ptr->cinfo);
2983
+ /*
2984
+ * when error occurred
2985
+ */
2318
2986
  rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
2987
+
2319
2988
  } else {
2320
- jpeg_mem_src(&ptr->cinfo, jpg, jpg_sz);
2989
+ /*
2990
+ * normal path
2991
+ */
2992
+ jpeg_mem_src(&ptr->cinfo, data, size);
2321
2993
 
2322
2994
  if (TEST_FLAG(ptr, F_PARSE_EXIF | F_APPLY_ORIENTATION)) {
2323
2995
  jpeg_save_markers(&ptr->cinfo, JPEG_APP1, 0xFFFF);
@@ -2331,8 +3003,6 @@ do_read_header(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
2331
3003
  }
2332
3004
 
2333
3005
  ret = create_meta(ptr);
2334
-
2335
- jpeg_destroy_decompress(&ptr->cinfo);
2336
3006
  }
2337
3007
 
2338
3008
  return ret;
@@ -2352,21 +3022,37 @@ rb_decoder_read_header(VALUE self, VALUE data)
2352
3022
  {
2353
3023
  VALUE ret;
2354
3024
  jpeg_decode_t* ptr;
3025
+ int state;
2355
3026
 
2356
3027
  /*
2357
3028
  * initialize
2358
3029
  */
2359
- Data_Get_Struct(self, jpeg_decode_t, ptr);
3030
+ ret = Qnil;
3031
+ state = 0;
3032
+
3033
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
2360
3034
 
2361
3035
  /*
2362
3036
  * argument check
2363
3037
  */
2364
3038
  Check_Type(data, T_STRING);
2365
3039
 
3040
+ /*
3041
+ * prepare
3042
+ */
3043
+ SET_DATA(ptr, data);
3044
+
2366
3045
  /*
2367
3046
  * do encode
2368
3047
  */
2369
- ret = do_read_header(ptr, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
3048
+ ret = rb_protect(do_read_header, (VALUE)ptr, &state);
3049
+
3050
+ /*
3051
+ * post process
3052
+ */
3053
+ CLR_DATA(ptr);
3054
+
3055
+ if (state != 0) rb_jump_tag(state);
2370
3056
 
2371
3057
  return ret;
2372
3058
  }
@@ -2858,9 +3544,14 @@ apply_orientation(jpeg_decode_t* ptr, VALUE img)
2858
3544
  }
2859
3545
 
2860
3546
  static VALUE
2861
- do_decode(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
3547
+ do_decode(VALUE _ptr)
2862
3548
  {
2863
3549
  VALUE ret;
3550
+
3551
+ jpeg_decode_t* ptr;
3552
+ uint8_t* data;
3553
+ size_t size;
3554
+
2864
3555
  struct jpeg_decompress_struct* cinfo;
2865
3556
  JSAMPARRAY array;
2866
3557
 
@@ -2870,102 +3561,98 @@ do_decode(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
2870
3561
  int i;
2871
3562
  int j;
2872
3563
 
2873
- ret = Qundef; // warning対策
3564
+ /*
3565
+ * initialize
3566
+ */
3567
+ ret = Qnil; // warning対策
3568
+ ptr = (jpeg_decode_t*)_ptr;
3569
+ data = (uint8_t*)RSTRING_PTR(ptr->data);
3570
+ size = RSTRING_LEN(ptr->data);
2874
3571
  cinfo = &ptr->cinfo;
2875
- array = ALLOC_ARRAY();
2876
-
2877
- switch (ptr->format) {
2878
- case FMT_YUV422:
2879
- case FMT_RGB565:
2880
- NOT_IMPLEMENTED_ERROR( "not implemented colorspace");
2881
- break;
3572
+ array = ptr->array;
2882
3573
 
2883
- case FMT_GRAYSCALE:
2884
- case FMT_YUV:
2885
- case FMT_RGB:
2886
- case FMT_BGR:
2887
- case FMT_YVU:
2888
- case FMT_RGB32:
2889
- case FMT_BGR32:
2890
- jpeg_create_decompress(cinfo);
3574
+ /*
3575
+ * do decode
3576
+ */
3577
+ if (setjmp(ptr->err_mgr.jmpbuf)) {
3578
+ /*
3579
+ * when error occurred
3580
+ */
3581
+ jpeg_abort_decompress(&ptr->cinfo);
3582
+ rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
2891
3583
 
2892
- cinfo->err = jpeg_std_error(&ptr->err_mgr.jerr);
2893
- ptr->err_mgr.jerr.output_message = decode_output_message;
2894
- ptr->err_mgr.jerr.emit_message = decode_emit_message;
2895
- ptr->err_mgr.jerr.error_exit = decode_error_exit;
3584
+ } else {
3585
+ /*
3586
+ * initialize
3587
+ */
3588
+ jpeg_mem_src(cinfo, data, size);
2896
3589
 
2897
- if (setjmp(ptr->err_mgr.jmpbuf)) {
2898
- jpeg_abort_decompress(cinfo);
2899
- jpeg_destroy_decompress(&ptr->cinfo);
3590
+ if (TEST_FLAG(ptr, F_PARSE_EXIF | F_APPLY_ORIENTATION)) {
3591
+ jpeg_save_markers(&ptr->cinfo, JPEG_APP1, 0xFFFF);
3592
+ }
2900
3593
 
2901
- free(array);
2902
- rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
3594
+ jpeg_read_header(cinfo, TRUE);
3595
+ jpeg_calc_output_dimensions(cinfo);
2903
3596
 
2904
- } else {
2905
- jpeg_mem_src(cinfo, jpg, jpg_sz);
3597
+ /*
3598
+ * configuration
3599
+ */
3600
+ cinfo->raw_data_out = FALSE;
3601
+ cinfo->dct_method = ptr->dct_method;
3602
+
3603
+ cinfo->out_color_space = ptr->out_color_space;
3604
+ cinfo->out_color_components = ptr->out_color_components;
3605
+ cinfo->scale_num = ptr->scale_num;
3606
+ cinfo->scale_denom = ptr->scale_denom;
3607
+ cinfo->output_gamma = ptr->output_gamma;
3608
+ cinfo->do_fancy_upsampling = ptr->do_fancy_upsampling;
3609
+ cinfo->do_block_smoothing = ptr->do_block_smoothing;
3610
+ cinfo->quantize_colors = ptr->quantize_colors;
3611
+ cinfo->dither_mode = ptr->dither_mode;
3612
+ cinfo->two_pass_quantize = ptr->two_pass_quantize;
3613
+ cinfo->desired_number_of_colors = ptr->desired_number_of_colors;
3614
+ cinfo->enable_1pass_quant = ptr->enable_1pass_quant;
3615
+ cinfo->enable_external_quant = ptr->enable_external_quant;
3616
+ cinfo->enable_2pass_quant = ptr->enable_2pass_quant;
2906
3617
 
2907
- if (TEST_FLAG(ptr, F_PARSE_EXIF | F_APPLY_ORIENTATION)) {
2908
- jpeg_save_markers(&ptr->cinfo, JPEG_APP1, 0xFFFF);
2909
- }
3618
+ /*
3619
+ * decode process
3620
+ */
3621
+ jpeg_start_decompress(cinfo);
2910
3622
 
2911
- jpeg_read_header(cinfo, TRUE);
2912
-
2913
- cinfo->raw_data_out = FALSE;
2914
- cinfo->dct_method = ptr->dct_method;
2915
-
2916
- cinfo->out_color_space = ptr->out_color_space;
2917
- cinfo->out_color_components = ptr->out_color_components;
2918
- cinfo->scale_num = ptr->scale_num;
2919
- cinfo->scale_denom = ptr->scale_denom;
2920
- cinfo->output_gamma = ptr->output_gamma;
2921
- cinfo->do_fancy_upsampling = ptr->do_fancy_upsampling;
2922
- cinfo->do_block_smoothing = ptr->do_block_smoothing;
2923
- cinfo->quantize_colors = ptr->quantize_colors;
2924
- cinfo->dither_mode = ptr->dither_mode;
2925
- cinfo->two_pass_quantize = ptr->two_pass_quantize;
2926
- cinfo->desired_number_of_colors = ptr->desired_number_of_colors;
2927
- cinfo->enable_1pass_quant = ptr->enable_1pass_quant;
2928
- cinfo->enable_external_quant = ptr->enable_external_quant;
2929
- cinfo->enable_2pass_quant = ptr->enable_2pass_quant;
2930
-
2931
- jpeg_calc_output_dimensions(cinfo);
2932
- jpeg_start_decompress(cinfo);
2933
-
2934
- stride = cinfo->output_components * cinfo->output_width;
2935
- raw_sz = stride * cinfo->output_height;
2936
- ret = rb_str_buf_new(raw_sz);
2937
- raw = (uint8_t*)RSTRING_PTR(ret);
2938
-
2939
- while (cinfo->output_scanline < cinfo->output_height) {
2940
- for (i = 0, j = cinfo->output_scanline; i < UNIT_LINES; i++, j++) {
2941
- array[i] = raw + (j * stride);
2942
- }
3623
+ stride = cinfo->output_components * cinfo->output_width;
3624
+ raw_sz = stride * cinfo->output_height;
3625
+ ret = rb_str_buf_new(raw_sz);
3626
+ raw = (uint8_t*)RSTRING_PTR(ret);
2943
3627
 
2944
- jpeg_read_scanlines(cinfo, array, UNIT_LINES);
3628
+ while (cinfo->output_scanline < cinfo->output_height) {
3629
+ for (i = 0, j = cinfo->output_scanline; i < UNIT_LINES; i++, j++) {
3630
+ array[i] = raw + (j * stride);
2945
3631
  }
2946
3632
 
2947
- if (TEST_FLAG(ptr, F_EXPAND_COLORMAP) && IS_COLORMAPPED(cinfo)) {
2948
- ret = expand_colormap(cinfo, raw);
2949
- } else {
2950
- rb_str_set_len(ret, raw_sz);
2951
- }
3633
+ jpeg_read_scanlines(cinfo, array, UNIT_LINES);
3634
+ }
2952
3635
 
2953
- if (ptr->format == FMT_YVU) swap_cbcr(raw, raw_sz);
3636
+ jpeg_finish_decompress(&ptr->cinfo);
2954
3637
 
2955
- if (TEST_FLAG(ptr, F_APPLY_ORIENTATION)) {
2956
- pick_exif_orientation(ptr);
2957
- ret = apply_orientation(ptr, ret);
2958
- }
3638
+ /*
3639
+ * build return data
3640
+ */
3641
+ if (TEST_FLAG(ptr, F_EXPAND_COLORMAP) && IS_COLORMAPPED(cinfo)) {
3642
+ ret = expand_colormap(cinfo, raw);
3643
+ } else {
3644
+ rb_str_set_len(ret, raw_sz);
3645
+ }
2959
3646
 
2960
- if (TEST_FLAG(ptr, F_NEED_META)) add_meta(ret, ptr);
3647
+ if (ptr->format == FMT_YVU) swap_cbcr(raw, raw_sz);
2961
3648
 
2962
- jpeg_finish_decompress(cinfo);
2963
- jpeg_destroy_decompress(&ptr->cinfo);
3649
+ if (TEST_FLAG(ptr, F_APPLY_ORIENTATION)) {
3650
+ pick_exif_orientation(ptr);
3651
+ ret = apply_orientation(ptr, ret);
2964
3652
  }
2965
- break;
2966
- }
2967
3653
 
2968
- free(array);
3654
+ if (TEST_FLAG(ptr, F_NEED_META)) add_meta(ret, ptr);
3655
+ }
2969
3656
 
2970
3657
  return ret;
2971
3658
  }
@@ -2982,25 +3669,41 @@ do_decode(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
2982
3669
  static VALUE
2983
3670
  rb_decoder_decode(VALUE self, VALUE data)
2984
3671
  {
2985
- VALUE ret;
2986
- jpeg_decode_t* ptr;
3672
+ VALUE ret;
3673
+ jpeg_decode_t* ptr;
3674
+ int state;
2987
3675
 
2988
- /*
2989
- * initialize
2990
- */
2991
- Data_Get_Struct(self, jpeg_decode_t, ptr);
3676
+ /*
3677
+ * initialize
3678
+ */
3679
+ ret = Qnil;
3680
+ state = 0;
2992
3681
 
2993
- /*
2994
- * argument check
2995
- */
2996
- Check_Type(data, T_STRING);
3682
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
2997
3683
 
2998
- /*
2999
- * do encode
3000
- */
3001
- ret = do_decode(ptr, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
3684
+ /*
3685
+ * argument check
3686
+ */
3687
+ Check_Type(data, T_STRING);
3688
+
3689
+ /*
3690
+ * prepare
3691
+ */
3692
+ SET_DATA(ptr, data);
3693
+
3694
+ /*
3695
+ * do decode
3696
+ */
3697
+ ret = rb_protect(do_decode, (VALUE)ptr, &state);
3002
3698
 
3003
- return ret;
3699
+ /*
3700
+ * post process
3701
+ */
3702
+ CLR_DATA(ptr);
3703
+
3704
+ if (state != 0) rb_jump_tag(state);
3705
+
3706
+ return ret;
3004
3707
  }
3005
3708
 
3006
3709
  static VALUE
@@ -3010,28 +3713,19 @@ rb_test_image(VALUE self, VALUE data)
3010
3713
  struct jpeg_decompress_struct cinfo;
3011
3714
  ext_error_t err_mgr;
3012
3715
 
3013
- jpeg_create_decompress(&cinfo);
3014
-
3015
- cinfo.err = jpeg_std_error(&err_mgr.jerr);
3016
-
3017
- err_mgr.jerr.output_message = decode_output_message;
3018
- err_mgr.jerr.emit_message = decode_emit_message;
3019
- err_mgr.jerr.error_exit = decode_error_exit;
3020
-
3021
- cinfo.raw_data_out = FALSE;
3022
- cinfo.dct_method = JDCT_FLOAT;
3716
+ cinfo.raw_data_out = FALSE;
3717
+ cinfo.dct_method = JDCT_FLOAT;
3023
3718
 
3024
3719
  if (setjmp(err_mgr.jmpbuf)) {
3025
- ret = Qtrue;
3026
- } else {
3027
3720
  ret = Qfalse;
3028
3721
 
3722
+ } else {
3029
3723
  jpeg_mem_src(&cinfo, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
3030
3724
  jpeg_read_header(&cinfo, TRUE);
3031
3725
  jpeg_calc_output_dimensions(&cinfo);
3032
- }
3033
3726
 
3034
- jpeg_destroy_decompress(&cinfo);
3727
+ ret = Qtrue;
3728
+ }
3035
3729
 
3036
3730
  return ret;
3037
3731
  }
@@ -3041,6 +3735,10 @@ Init_jpeg()
3041
3735
  {
3042
3736
  int i;
3043
3737
 
3738
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
3739
+ rb_ext_ractor_safe(true);
3740
+ #endif /* defined(HAVE_RB_EXT_RACTOR_SAFE) */
3741
+
3044
3742
  module = rb_define_module("JPEG");
3045
3743
  rb_define_singleton_method(module, "broken?", rb_test_image, 1);
3046
3744