libjpeg-ruby 0.8.0 → 0.9.0

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