libjpeg-ruby 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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
  }