libjpeg-ruby 0.7.0 → 0.9.1

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: 7117f5dece9f78e847213078d1cba56591a30c01ea4b9de58cb4886647d5c530
4
- data.tar.gz: 7bb5c400d519e4958fb9522c8a3af313931dc033a45c404a288d0d5020f02b7c
3
+ metadata.gz: 3523da7ee57f41d57b81fe97558564e0b0459c5977321ba88a298a450cd9273a
4
+ data.tar.gz: 103f379375f273f0f9a77109cc3dff8018779ce94837d2182e1e0ce50bb78213
5
5
  SHA512:
6
- metadata.gz: 457f1b3f55ba6c164a40e66303a9c34df6e9ec590137d161c98cee69bbac1385aa4b309c60feb853637c0c392afabdb356996b6809adefd0ed5827051eb318f6
7
- data.tar.gz: 9427246e376ff7a9464b0e4c8cf22b0dff47e9036649f13a49a213b769f7ceab7d3e76dbbd258d65c6c65e5c03bda362cf06acc1b921c83bde74bd49d0c8c85f
6
+ metadata.gz: fd38c818582812ce2ef404ade310846a5af944e2b05c2b16df4df66bf62dd3404c9c68c6508e65e8a603041ab6f0d21484d911680e967f7e11aa9ad94a7d2782
7
+ data.tar.gz: a05940b338d1660f90345c7eebdeea897629ac37c33949720cde9d4c4d5794eb73dcb0f1be568d078110185ffe223425e4f5cb61da10f3075dd63a6c1a1fe185
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .rbenv-gemsets
3
+ .ruby-version
4
+ /.config
5
+ /pkg/
6
+ /doc/
7
+ /tmp/
8
+ /.yardoc/
data/README.md CHANGED
@@ -50,7 +50,8 @@ 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
+ | :orientation | Boolean | Specify whether to parse Exif orientation. When set to true, apply orientation for decode result. |
54
55
 
55
56
  #### supported output format
56
57
  RGB RGB24 YUV422 YUYV RGB565 YUV444 YCbCr BGR BGR24 RGBX RGB32 BGRX BGR32
@@ -75,4 +76,5 @@ IO.binwrite("test.jpg", enc << IO.binread("test.raw"))
75
76
  | :quality | Integer | encode quality (0-100) |
76
77
  | :scale | Rational or Float | |
77
78
  | :dct_method | String or Symbol | T.B.D |
79
+ | :orientation | Integer | Specify Exif orientation value (1-8). |
78
80
 
data/ext/jpeg/extconf.rb CHANGED
@@ -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")
data/ext/jpeg/jpeg.c CHANGED
@@ -4,16 +4,6 @@
4
4
  * Copyright (C) 2015 Hiroshi Kuwagata <kgt9221@gmail.com>
5
5
  */
6
6
 
7
- /*
8
- * $Id: jpeg.c 159 2017-12-17 18:40:28Z pi $
9
- */
10
-
11
- /*
12
- * TODO
13
- * libjpegのエラーハンドリングを全くやっていないので
14
- * いずれ修正する事
15
- */
16
-
17
7
  #include <stdio.h>
18
8
  #include <stdint.h>
19
9
  #include <strings.h>
@@ -22,6 +12,7 @@
22
12
  #include <jpeglib.h>
23
13
 
24
14
  #include "ruby.h"
15
+ #include "ruby/version.h"
25
16
  #include "ruby/encoding.h"
26
17
 
27
18
  #define UNIT_LINES 10
@@ -33,6 +24,23 @@
33
24
  #define DEFAULT_QUALITY 75
34
25
  #define DEFAULT_INPUT_COLOR_SPACE JCS_YCbCr
35
26
  #define DEFAULT_INPUT_COMPONENTS 2
27
+ #define DEFAULT_ENCODE_FLAGS (0)
28
+ #define DEFAULT_DECODE_FLAGS (F_NEED_META)
29
+
30
+ #define F_NEED_META 0x00000001
31
+ #define F_EXPAND_COLORMAP 0x00000002
32
+ #define F_PARSE_EXIF 0x00000004
33
+ #define F_APPLY_ORIENTATION 0x00000008
34
+ #define F_DITHER 0x00000010
35
+ #define F_CREAT 0x00010000
36
+
37
+ #define SET_FLAG(ptr, msk) ((ptr)->flags |= (msk))
38
+ #define CLR_FLAG(ptr, msk) ((ptr)->flags &= ~(msk))
39
+ #define TEST_FLAG(ptr, msk) ((ptr)->flags & (msk))
40
+ #define TEST_FLAG_ALL(ptr, msk) (((ptr)->flags & (msk)) == (msk))
41
+
42
+ #define SET_DATA(ptr, dat) ((ptr)->data = (dat))
43
+ #define CLR_DATA(ptr) ((ptr)->data = Qnil)
36
44
 
37
45
  #define FMT_YUV422 1
38
46
  #define FMT_RGB565 2
@@ -48,20 +56,25 @@
48
56
  #define JPEG_APP1 0xe1 /* Exif marker */
49
57
 
50
58
  #define N(x) (sizeof(x)/sizeof(*x))
59
+ #define SWAP(a,b,t) \
60
+ do {t c; c = (a); (a) = (b); (b) = c;} while (0)
51
61
 
52
62
  #define RUNTIME_ERROR(msg) rb_raise(rb_eRuntimeError, (msg))
53
63
  #define ARGUMENT_ERROR(msg) rb_raise(rb_eArgError, (msg))
64
+ #define TYPE_ERROR(msg) rb_raise(rb_eTypeError, (msg))
65
+ #define RANGE_ERROR(msg) rb_raise(rb_eRangeError, (msg))
66
+ #define NOT_IMPLEMENTED_ERROR(msg) rb_raise(rb_eNotImpError, (msg))
54
67
 
55
68
  #define IS_COLORMAPPED(ci) (((ci)->actual_number_of_colors > 0) &&\
56
69
  ((ci)->colormap != NULL) && \
57
70
  ((ci)->output_components == 1) && \
58
- (((ci)->out_color_components == 1) || \
59
- ((ci)->out_color_components == 3)))
71
+ (((ci)->out_color_components == 1) || \
72
+ ((ci)->out_color_components == 3)))
60
73
 
61
74
  #define ALLOC_ARRAY() \
62
- ((JSAMPARRAY)xmalloc(sizeof(JSAMPROW) * UNIT_LINES))
75
+ ((JSAMPARRAY)malloc(sizeof(JSAMPROW) * UNIT_LINES))
63
76
  #define ALLOC_ROWS(w,c) \
64
- ((JSAMPROW)xmalloc(sizeof(JSAMPLE) * (w) * (c) * UNIT_LINES))
77
+ ((JSAMPROW)malloc(sizeof(JSAMPLE) * (w) * (c) * UNIT_LINES))
65
78
 
66
79
  #define EQ_STR(val,str) (rb_to_id(val) == rb_intern(str))
67
80
  #define EQ_INT(val,n) (FIX2INT(val) == n)
@@ -76,11 +89,13 @@ static VALUE decerr_klass;
76
89
 
77
90
  static ID id_meta;
78
91
  static ID id_width;
92
+ static ID id_stride;
79
93
  static ID id_height;
80
94
  static ID id_orig_cs;
81
95
  static ID id_out_cs;
82
96
  static ID id_ncompo;
83
- static ID id_exif;
97
+ static ID id_exif_tags;
98
+ static ID id_colormap;
84
99
 
85
100
  typedef struct {
86
101
  int tag;
@@ -246,25 +261,47 @@ tag_entry_t tag_i14y[] = {
246
261
  static const char* encoder_opts_keys[] = {
247
262
  "pixel_format", // {str}
248
263
  "quality", // {integer}
249
- "scale", // {rational} or {float}
250
- "dct_method" // {str}
264
+ "dct_method", // {str}
265
+ "orientation", // {integer}
266
+ "stride", // {integer}
251
267
  };
252
268
 
253
269
  static ID encoder_opts_ids[N(encoder_opts_keys)];
254
270
 
255
271
  typedef struct {
256
- int format;
272
+ struct jpeg_error_mgr jerr;
273
+
274
+ char msg[JMSG_LENGTH_MAX+10];
275
+ jmp_buf jmpbuf;
276
+ } ext_error_t;
277
+
278
+ typedef struct {
279
+ int flags;
257
280
  int width;
281
+ int stride;
258
282
  int height;
259
-
260
283
  int data_size;
284
+
285
+ int format;
286
+ int color_space;
287
+ int components;
288
+ int quality;
261
289
  J_DCT_METHOD dct_method;
262
290
 
263
291
  struct jpeg_compress_struct cinfo;
264
- struct jpeg_error_mgr jerr;
292
+ ext_error_t err_mgr;
265
293
 
266
294
  JSAMPARRAY array;
267
295
  JSAMPROW rows;
296
+
297
+ VALUE data;
298
+
299
+ struct {
300
+ unsigned char* mem;
301
+ unsigned long size;
302
+ } buf;
303
+
304
+ int orientation;
268
305
  } jpeg_encode_t;
269
306
 
270
307
  static const char* decoder_opts_keys[] = {
@@ -273,30 +310,24 @@ static const char* decoder_opts_keys[] = {
273
310
  "do_fancy_upsampling", // {bool}
274
311
  "do_smoothing", // {bool}
275
312
  "dither", // [{str}MODE, {bool}2PASS, {int}NUM_COLORS]
313
+ #if 0
276
314
  "use_1pass_quantizer", // {bool}
277
315
  "use_external_colormap", // {bool}
278
316
  "use_2pass_quantizer", // {bool}
317
+ #endif
279
318
  "without_meta", // {bool}
280
319
  "expand_colormap", // {bool}
281
320
  "scale", // {rational} or {float}
282
321
  "dct_method", // {str}
283
- "with_exif" // {bool}
322
+ "with_exif_tags", // {bool}
323
+ "orientation" // {bool}
284
324
  };
285
325
 
286
326
  static ID decoder_opts_ids[N(decoder_opts_keys)];
287
327
 
288
328
  typedef struct {
289
- struct jpeg_error_mgr jerr;
290
-
291
- char msg[JMSG_LENGTH_MAX+10];
292
- jmp_buf jmpbuf;
293
- } ext_error_t;
294
-
295
- typedef struct {
329
+ int flags;
296
330
  int format;
297
- int need_meta;
298
- int expand_colormap;
299
- int parse_exif;
300
331
 
301
332
  J_COLOR_SPACE out_color_space;
302
333
  int scale_num;
@@ -317,8 +348,131 @@ typedef struct {
317
348
 
318
349
  struct jpeg_decompress_struct cinfo;
319
350
  ext_error_t err_mgr;
351
+
352
+ JSAMPARRAY array;
353
+
354
+ VALUE data;
355
+
356
+ struct {
357
+ int value;
358
+ VALUE buf;
359
+ } orientation;
320
360
  } jpeg_decode_t;
321
361
 
362
+ #if 0
363
+ static VALUE
364
+ create_runtime_error(const char* fmt, ...)
365
+ {
366
+ VALUE ret;
367
+ va_list ap;
368
+
369
+ va_start(ap, fmt);
370
+ ret = rb_exc_new_str(rb_eRuntimeError, rb_vsprintf(fmt, ap));
371
+ va_end(ap);
372
+
373
+ return ret;
374
+ }
375
+ #endif
376
+
377
+ static VALUE
378
+ create_argument_error(const char* fmt, ...)
379
+ {
380
+ VALUE ret;
381
+ va_list ap;
382
+
383
+ va_start(ap, fmt);
384
+ ret = rb_exc_new_str(rb_eArgError, rb_vsprintf(fmt, ap));
385
+ va_end(ap);
386
+
387
+ return ret;
388
+ }
389
+
390
+ static VALUE
391
+ create_type_error(const char* fmt, ...)
392
+ {
393
+ VALUE ret;
394
+ va_list ap;
395
+
396
+ va_start(ap, fmt);
397
+ ret = rb_exc_new_str(rb_eTypeError, rb_vsprintf(fmt, ap));
398
+ va_end(ap);
399
+
400
+ return ret;
401
+ }
402
+
403
+ static VALUE
404
+ create_range_error(const char* fmt, ...)
405
+ {
406
+ VALUE ret;
407
+ va_list ap;
408
+
409
+ va_start(ap, fmt);
410
+ ret = rb_exc_new_str(rb_eRangeError, rb_vsprintf(fmt, ap));
411
+ va_end(ap);
412
+
413
+ return ret;
414
+ }
415
+
416
+ static VALUE
417
+ create_not_implement_error(const char* fmt, ...)
418
+ {
419
+ VALUE ret;
420
+ va_list ap;
421
+
422
+ va_start(ap, fmt);
423
+ ret = rb_exc_new_str(rb_eNotImpError, rb_vsprintf(fmt, ap));
424
+ va_end(ap);
425
+
426
+ return ret;
427
+ }
428
+
429
+ static VALUE
430
+ create_memory_error()
431
+ {
432
+ return rb_exc_new_str(rb_eRangeError, rb_str_new_cstr("no memory"));
433
+ }
434
+
435
+ static void
436
+ output_message(j_common_ptr cinfo)
437
+ {
438
+ ext_error_t* err;
439
+
440
+ err = (ext_error_t*)cinfo->err;
441
+
442
+ (*err->jerr.format_message)(cinfo, err->msg);
443
+ }
444
+
445
+ static void
446
+ emit_message(j_common_ptr cinfo, int msg_level)
447
+ {
448
+ ext_error_t* err;
449
+
450
+ if (msg_level < 0) {
451
+ err = (ext_error_t*)cinfo->err;
452
+ (*err->jerr.format_message)(cinfo, err->msg);
453
+ /*
454
+ * 以前はemit_messageが呼ばれるとエラー扱いしていたが、
455
+ * Logicoolの一部のモデルなどで問題が出るので無視する
456
+ * ようにした。
457
+ * また本来であれば、警告表示を行うべきでもあるが一部
458
+ * のモデルで大量にemitされる場合があるので表示しない
459
+ * ようにしている。
460
+ * 問題が発生した際は、最後のメッセージをオブジェクト
461
+ * のインスタンスとして持たすべき。
462
+ */
463
+ // longjmp(err->jmpbuf, 1);
464
+ }
465
+ }
466
+
467
+ static void
468
+ error_exit(j_common_ptr cinfo)
469
+ {
470
+ ext_error_t* err;
471
+
472
+ err = (ext_error_t*)cinfo->err;
473
+ (*err->jerr.format_message)(cinfo, err->msg);
474
+ longjmp(err->jmpbuf, 1);
475
+ }
322
476
 
323
477
  static VALUE
324
478
  lookup_tag_symbol(tag_entry_t* tbl, size_t n, int tag)
@@ -361,40 +515,87 @@ lookup_tag_symbol(tag_entry_t* tbl, size_t n, int tag)
361
515
  }
362
516
 
363
517
  static void
364
- encode_output_message(j_common_ptr cinfo)
518
+ rb_encoder_mark(void* _ptr)
365
519
  {
366
- char msg[JMSG_LENGTH_MAX];
520
+ jpeg_encode_t* ptr;
521
+
522
+ ptr = (jpeg_encode_t*)_ptr;
367
523
 
368
- (*cinfo->err->format_message)(cinfo, msg);
524
+ if (ptr->data != Qnil) {
525
+ rb_gc_mark(ptr->data);
526
+ }
369
527
  }
370
528
 
371
529
  static void
372
- encode_error_exit(j_common_ptr cinfo)
530
+ rb_encoder_free(void* _ptr)
373
531
  {
374
- char msg[JMSG_LENGTH_MAX];
532
+ jpeg_encode_t* ptr;
375
533
 
376
- (*cinfo->err->format_message)(cinfo, msg);
534
+ ptr = (jpeg_encode_t*)_ptr;
377
535
 
378
- jpeg_destroy_compress((j_compress_ptr)cinfo);
379
- rb_raise(encerr_klass, "%s", msg);
380
- }
536
+ if (ptr->array != NULL) {
537
+ free(ptr->array);
538
+ }
381
539
 
540
+ if (ptr->rows != NULL) {
541
+ free(ptr->rows);
542
+ }
382
543
 
383
- static void
384
- rb_encoder_free( void* _ptr)
544
+ if (ptr->buf.mem != NULL) {
545
+ free(ptr->buf.mem);
546
+ }
547
+
548
+ if (TEST_FLAG(ptr, F_CREAT)) {
549
+ jpeg_destroy_compress(&ptr->cinfo);
550
+ }
551
+
552
+ free(ptr);
553
+ }
554
+
555
+ static size_t
556
+ rb_encoder_size(const void* _ptr)
385
557
  {
558
+ size_t ret;
386
559
  jpeg_encode_t* ptr;
387
560
 
388
- ptr = (jpeg_encode_t*)_ptr;
389
-
390
- if (ptr->array != NULL) xfree(ptr->array);
391
- if (ptr->rows != NULL) xfree(ptr->rows);
561
+ ptr = (jpeg_encode_t*)_ptr;
392
562
 
393
- jpeg_destroy_compress(&ptr->cinfo);
563
+ ret = sizeof(jpeg_encode_t);
564
+ ret += sizeof(JSAMPROW) * UNIT_LINES;
565
+ ret += sizeof(JSAMPLE) * ptr->stride * UNIT_LINES;
394
566
 
395
- free(_ptr);
567
+ return ret;
396
568
  }
397
569
 
570
+ #if RUBY_API_VERSION_CODE > 20600
571
+ static const rb_data_type_t jpeg_encoder_data_type = {
572
+ "libjpeg-ruby encoder object", // wrap_struct_name
573
+ {
574
+ rb_encoder_mark, // function.dmark
575
+ rb_encoder_free, // function.dfree
576
+ rb_encoder_size, // function.dsize
577
+ NULL, // function.dcompact
578
+ {NULL}, // function.reserved
579
+ },
580
+ NULL, // parent
581
+ NULL, // data
582
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
583
+ };
584
+ #else /* RUBY_API_VERSION_CODE > 20600 */
585
+ static const rb_data_type_t jpeg_encoder_data_type = {
586
+ "libjpeg-ruby encoder object", // wrap_struct_name
587
+ {
588
+ rb_encoder_mark, // function.dmark
589
+ rb_encoder_free, // function.dfree
590
+ rb_encoder_size, // function.dsize
591
+ {NULL, NULL}, // function.reserved
592
+ },
593
+ NULL, // parent
594
+ NULL, // data
595
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
596
+ };
597
+ #endif /* RUBY_API_VERSION_CODE > 20600 */
598
+
398
599
  static VALUE
399
600
  rb_encoder_alloc(VALUE self)
400
601
  {
@@ -403,192 +604,396 @@ rb_encoder_alloc(VALUE self)
403
604
  ptr = ALLOC(jpeg_encode_t);
404
605
  memset(ptr, 0, sizeof(*ptr));
405
606
 
406
- ptr->dct_method = JDCT_FASTEST;
607
+ ptr->flags = DEFAULT_ENCODE_FLAGS;
407
608
 
408
- return Data_Wrap_Struct(encoder_klass, 0, rb_encoder_free, ptr);
609
+ return TypedData_Wrap_Struct(encoder_klass, &jpeg_encoder_data_type, ptr);
409
610
  }
410
611
 
411
- static void
412
- set_encoder_context(jpeg_encode_t* ptr, int wd, int ht, VALUE opt)
612
+ static VALUE
613
+ eval_encoder_pixel_format_opt(jpeg_encode_t* ptr, VALUE opt)
413
614
  {
414
- VALUE opts[N(encoder_opts_ids)];
615
+ VALUE ret;
415
616
  int format;
416
617
  int color_space;
417
618
  int components;
418
- int data_size;
419
- int quality;
420
- int scale_num;
421
- int scale_denom;
422
- int i;
423
619
 
424
- /*
425
- * parse options
426
- */
427
- rb_get_kwargs(opt, encoder_opts_ids, 0, N(encoder_opts_ids), opts);
620
+ ret = Qnil;
428
621
 
429
- /*
430
- * eval :pixel_format option
431
- */
432
- if (opts[0] == Qundef||EQ_STR(opts[0], "YUV422")||EQ_STR(opts[0], "YUYV")) {
622
+ switch (TYPE(opt)) {
623
+ case T_UNDEF:
433
624
  format = FMT_YUV422;
434
625
  color_space = JCS_YCbCr;
435
626
  components = 3;
436
- data_size = (wd * ht * 2);
627
+ break;
437
628
 
438
- } else if (EQ_STR(opts[0], "RGB565")) {
439
- format = FMT_RGB565;
440
- color_space = JCS_RGB;
441
- components = 3;
442
- data_size = (wd * ht * 2);
629
+ case T_STRING:
630
+ case T_SYMBOL:
631
+ if (EQ_STR(opt, "YUV422") || EQ_STR(opt, "YUYV")) {
632
+ format = FMT_YUV422;
633
+ color_space = JCS_YCbCr;
634
+ components = 3;
443
635
 
444
- } else if (EQ_STR(opts[0], "RGB") || EQ_STR(opts[0], "RGB24")) {
445
- format = FMT_RGB;
446
- color_space = JCS_RGB;
447
- components = 3;
448
- data_size = (wd * ht * 3);
636
+ } else if (EQ_STR(opt, "RGB565")) {
637
+ format = FMT_RGB565;
638
+ color_space = JCS_RGB;
639
+ components = 3;
449
640
 
450
- } else if (EQ_STR(opts[0], "BGR") || EQ_STR(opts[0], "BGR24")) {
451
- format = FMT_BGR;
452
- color_space = JCS_EXT_BGR;
453
- components = 3;
454
- data_size = (wd * ht * 3);
641
+ } else if (EQ_STR(opt, "RGB") || EQ_STR(opt, "RGB24")) {
642
+ format = FMT_RGB;
643
+ color_space = JCS_RGB;
644
+ components = 3;
455
645
 
456
- } else if (EQ_STR(opts[0], "YUV444") || EQ_STR(opts[0], "YCbCr")) {
457
- format = FMT_YUV;
458
- color_space = JCS_YCbCr;
459
- components = 3;
460
- data_size = (wd * ht * 3);
646
+ } else if (EQ_STR(opt, "BGR") || EQ_STR(opt, "BGR24")) {
647
+ format = FMT_BGR;
648
+ color_space = JCS_EXT_BGR;
649
+ components = 3;
461
650
 
462
- } else if (EQ_STR(opts[0], "RGBX") || EQ_STR(opts[0], "RGB32")) {
463
- format = FMT_RGB32;
464
- color_space = JCS_EXT_RGBX;
465
- components = 4;
466
- data_size = (wd * ht * 4);
651
+ } else if (EQ_STR(opt, "YUV444") || EQ_STR(opt, "YCbCr")) {
652
+ format = FMT_YUV;
653
+ color_space = JCS_YCbCr;
654
+ components = 3;
467
655
 
656
+ } else if (EQ_STR(opt, "RGBX") || EQ_STR(opt, "RGB32")) {
657
+ format = FMT_RGB32;
658
+ color_space = JCS_EXT_RGBX;
659
+ components = 4;
468
660
 
469
- } else if (EQ_STR(opts[0], "BGRX") || EQ_STR(opts[0], "BGR32")) {
470
- format = FMT_BGR32;
471
- color_space = JCS_EXT_BGRX;
472
- components = 4;
473
- data_size = (wd * ht * 4);
661
+ } else if (EQ_STR(opt, "BGRX") || EQ_STR(opt, "BGR32")) {
662
+ format = FMT_BGR32;
663
+ color_space = JCS_EXT_BGRX;
664
+ components = 4;
474
665
 
666
+ } else if (EQ_STR(opt, "GRAYSCALE")) {
667
+ format = FMT_GRAYSCALE;
668
+ color_space = JCS_GRAYSCALE;
669
+ components = 1;
475
670
 
476
- } else if (EQ_STR(opts[0], "GRAYSCALE")) {
477
- format = FMT_GRAYSCALE;
478
- color_space = JCS_GRAYSCALE;
479
- components = 1;
480
- data_size = (wd * ht);
671
+ } else {
672
+ ret = create_argument_error("unsupportd :pixel_format option value");
673
+ }
674
+ break;
481
675
 
482
- } else {
483
- ARGUMENT_ERROR("Unsupportd :pixel_format option value.");
676
+ default:
677
+ ret = create_type_error("unsupportd :pixel_format option type");
678
+ break;
484
679
  }
485
680
 
486
- /*
487
- * eval :quality option
488
- */
489
- if (opts[1] == Qundef) {
490
- quality = DEFAULT_QUALITY;
491
-
492
- } else {
493
- if (TYPE(opts[1]) != T_FIXNUM) {
494
- ARGUMENT_ERROR("Unsupportd :quality option value.");
681
+ if (!RTEST(ret)) {
682
+ ptr->format = format;
683
+ ptr->color_space = color_space;
684
+ ptr->components = components;
685
+ }
495
686
 
496
- } else {
497
- quality = FIX2INT(opts[1]);
498
- }
687
+ return ret;
688
+ }
499
689
 
500
- if (quality < 0) {
501
- ARGUMENT_ERROR(":quality value is to little.");
690
+ static VALUE
691
+ eval_encoder_quality_opt(jpeg_encode_t* ptr, VALUE opt)
692
+ {
693
+ VALUE ret;
694
+ long quality;
502
695
 
503
- } else if (quality > 100) {
504
- ARGUMENT_ERROR(":quality value is to big.");
505
- }
506
- }
507
-
508
- /*
509
- * eval scale option
510
- */
511
- (void)scale_num;
512
- (void)scale_denom;
696
+ ret = Qnil;
513
697
 
514
- switch (TYPE(opts[2])) {
698
+ switch (TYPE(opt)) {
515
699
  case T_UNDEF:
516
- // Nothing
700
+ quality = DEFAULT_QUALITY;
517
701
  break;
518
702
 
519
703
  case T_FLOAT:
520
- scale_num = 1000;
521
- scale_denom = (int)(NUM2DBL(opts[2]) * 1000.0);
704
+ if (isnan(NUM2DBL(opt)) || isinf(NUM2DBL(opt))) {
705
+ ret = create_argument_error("unsupportd :quality option value");
706
+
707
+ } else if (NUM2DBL(opt) < 0.0) {
708
+ ret = create_range_error(":quality less than 0");
709
+
710
+ } else if (NUM2DBL(opt) > 100.0) {
711
+ ret = create_range_error(":quality greater than 100");
712
+
713
+ } else {
714
+ quality = NUM2INT(opt);
715
+ }
522
716
  break;
523
717
 
524
- case T_RATIONAL:
525
- scale_num = FIX2INT(rb_rational_num(opts[2]));
526
- scale_denom = FIX2INT(rb_rational_den(opts[2]));
718
+ case T_FIXNUM:
719
+ if (FIX2LONG(opt) < 0) {
720
+ ret = create_range_error(":quality less than 0");
721
+
722
+ } if (FIX2LONG(opt) > 100) {
723
+ ret = create_range_error(":quality greater than 100");
724
+
725
+ } else {
726
+ quality = FIX2INT(opt);
727
+ }
527
728
  break;
528
729
 
529
730
  default:
530
- ARGUMENT_ERROR("Unsupportd :scale option value.");
731
+ ret = create_type_error("unsupportd :quality option type");
531
732
  break;
532
733
  }
533
734
 
534
- /*
535
- * eval dct_method option
536
- */
537
- if (opts[3] == Qundef || EQ_STR(opts[3], "FASTEST")) {
538
- ptr->dct_method = JDCT_FASTEST;
735
+ if (!RTEST(ret)) ptr->quality = quality;
539
736
 
540
- } else if (EQ_STR(opts[3], "ISLOW")) {
541
- ptr->dct_method = JDCT_ISLOW;
737
+ return ret;
738
+ }
542
739
 
543
- } else if (EQ_STR(opts[3], "IFAST")) {
544
- ptr->dct_method = JDCT_IFAST;
740
+ static VALUE
741
+ eval_encoder_dct_method_opt(jpeg_encode_t* ptr, VALUE opt)
742
+ {
743
+ VALUE ret;
744
+ int dct_method;
545
745
 
546
- } else if (EQ_STR(opts[3], "FLOAT")) {
547
- ptr->dct_method = JDCT_FLOAT;
746
+ ret = Qnil;
548
747
 
549
- } else {
550
- ARGUMENT_ERROR("Unsupportd :dct_method option value.");
551
- }
748
+ switch (TYPE(opt)) {
749
+ case T_UNDEF:
750
+ dct_method = JDCT_FASTEST;
751
+ break;
552
752
 
553
- /*
554
- * set context
555
- */
556
- ptr->format = format;
557
- ptr->width = wd;
558
- ptr->height = ht;
559
- ptr->data_size = data_size;
560
- ptr->array = ALLOC_ARRAY();
561
- ptr->rows = ALLOC_ROWS(wd, components);
753
+ case T_STRING:
754
+ case T_SYMBOL:
755
+ if (EQ_STR(opt, "FASTEST")) {
756
+ dct_method = JDCT_FASTEST;
562
757
 
563
- for (i = 0; i < UNIT_LINES; i++) {
564
- ptr->array[i] = ptr->rows + (i * components * wd);
565
- }
758
+ } else if (EQ_STR(opt, "ISLOW")) {
759
+ dct_method = JDCT_ISLOW;
566
760
 
567
- jpeg_create_compress(&ptr->cinfo);
761
+ } else if (EQ_STR(opt, "IFAST")) {
762
+ dct_method = JDCT_IFAST;
763
+
764
+ } else if (EQ_STR(opt, "FLOAT")) {
765
+ dct_method = JDCT_FLOAT;
766
+
767
+ } else {
768
+ ret = create_argument_error("unsupportd :dct_method option value");
769
+ }
770
+ break;
771
+
772
+ default:
773
+ ret = create_type_error("unsupportd :dct_method option type");
774
+ break;
775
+ }
776
+
777
+ if (!RTEST(ret)) ptr->dct_method = dct_method;
778
+
779
+ return ret;
780
+ }
781
+
782
+ static VALUE
783
+ eval_encoder_orientation_opt(jpeg_encode_t* ptr, VALUE opt)
784
+ {
785
+ VALUE ret;
786
+ int orientation;
787
+
788
+ ret = Qnil;
789
+
790
+ switch (TYPE(opt)) {
791
+ case T_UNDEF:
792
+ orientation = 0;
793
+ break;
794
+
795
+ case T_FIXNUM:
796
+ orientation = FIX2INT(opt);
797
+ if (orientation < 1 || orientation > 8) {
798
+ ret = create_range_error(":orientation option ouf range");
799
+ }
800
+ break;
801
+
802
+ default:
803
+ ret = create_type_error("Unsupportd :orientation option type.");
804
+ break;
805
+ }
806
+
807
+ if (!RTEST(ret)) ptr->orientation = orientation;
808
+
809
+ return ret;
810
+ }
811
+
812
+ static VALUE
813
+ eval_encoder_stride_opt(jpeg_encode_t* ptr, VALUE opt)
814
+ {
815
+ VALUE ret;
816
+ int stride;
817
+
818
+ ret = Qnil;
819
+
820
+ switch (TYPE(opt)) {
821
+ case T_UNDEF:
822
+ stride = ptr->width * ptr->components;
823
+ break;
824
+
825
+ case T_FIXNUM:
826
+ stride = FIX2INT(opt);
827
+ if (stride < (ptr->width * ptr->components)) {
828
+ ret = create_range_error(":stride too little");
829
+ }
830
+ break;
831
+
832
+ default:
833
+ ret = create_type_error("unsupportd :stride option type");
834
+ }
835
+
836
+ if (!RTEST(ret)) ptr->stride = stride;
837
+
838
+ return ret;
839
+ }
840
+
841
+ static VALUE
842
+ set_encoder_context(jpeg_encode_t* ptr, int wd, int ht, VALUE opt)
843
+ {
844
+ VALUE ret;
845
+ VALUE opts[N(encoder_opts_ids)];
846
+ JSAMPARRAY ary;
847
+ JSAMPROW rows;
848
+
849
+ int i;
850
+
851
+ /*
852
+ * initialize
853
+ */
854
+ ret = Qnil;
855
+ ary = NULL;
856
+ rows = NULL;
857
+
858
+ /*
859
+ * argument check
860
+ */
861
+ do {
862
+ if (wd <= 0) {
863
+ ret = create_range_error("image width less equal zero");
864
+ break;
865
+ }
866
+
867
+ if (ht <= 0) {
868
+ ret = create_range_error("image height less equal zero");
869
+ break;
870
+ }
871
+ } while (0);
872
+
873
+ /*
874
+ * parse options
875
+ */
876
+ if (!RTEST(ret)) do {
877
+ rb_get_kwargs(opt, encoder_opts_ids, 0, N(encoder_opts_ids), opts);
878
+
879
+ // オプション評価で使用するので前もって設定しておく
880
+ ptr->width = wd;
881
+ ptr->height = ht;
882
+
883
+ ret = eval_encoder_pixel_format_opt(ptr, opts[0]);
884
+ if (RTEST(ret)) break;
885
+
886
+ ret = eval_encoder_quality_opt(ptr, opts[1]);
887
+ if (RTEST(ret)) break;
888
+
889
+ ret = eval_encoder_dct_method_opt(ptr, opts[2]);
890
+ if (RTEST(ret)) break;
891
+
892
+ ret = eval_encoder_orientation_opt(ptr, opts[3]);
893
+ if (RTEST(ret)) break;
894
+
895
+ ret = eval_encoder_stride_opt(ptr, opts[4]);
896
+ if (RTEST(ret)) break;
897
+ } while (0);
898
+
899
+ /*
900
+ * alloc memory
901
+ */
902
+ if (!RTEST(ret)) do {
903
+ ary = ALLOC_ARRAY();
904
+ if (ary == NULL) {
905
+ ret = create_memory_error();
906
+ break;
907
+ }
908
+
909
+ rows = ALLOC_ROWS(ptr->width, ptr->components);
910
+ if (rows == NULL) {
911
+ ret = create_memory_error();
912
+ break;
913
+ }
914
+ } while (0);
568
915
 
569
- ptr->cinfo.err = jpeg_std_error(&ptr->jerr);
570
- ptr->jerr.output_message = encode_output_message;
571
- ptr->jerr.error_exit = encode_error_exit;
916
+ /*
917
+ * set the rest context parameter
918
+ */
919
+ if (!RTEST(ret)) {
920
+ ptr->err_mgr.jerr.output_message = output_message;
921
+ ptr->err_mgr.jerr.emit_message = emit_message;
922
+ ptr->err_mgr.jerr.error_exit = error_exit;
923
+
924
+ ptr->data_size = ptr->stride * ptr->height;
925
+ ptr->buf.mem = NULL;
926
+ ptr->buf.size = 0;
927
+ ptr->array = ary;
928
+ ptr->rows = rows;
929
+ ptr->data = Qnil;
930
+
931
+ for (i = 0; i < UNIT_LINES; i++) {
932
+ ptr->array[i] = ptr->rows + (i * ptr->width * ptr->components);
933
+ }
934
+ }
572
935
 
573
- ptr->cinfo.image_width = wd;
574
- ptr->cinfo.image_height = ht;
575
- ptr->cinfo.in_color_space = color_space;
576
- ptr->cinfo.input_components = components;
936
+ /*
937
+ * setup libjpeg
938
+ */
939
+ if (!RTEST(ret)) {
940
+ jpeg_create_compress(&ptr->cinfo);
941
+ SET_FLAG(ptr, F_CREAT);
942
+
943
+ ptr->cinfo.err = jpeg_std_error(&ptr->err_mgr.jerr);
944
+ ptr->cinfo.image_width = ptr->width;
945
+ ptr->cinfo.image_height = ptr->height;
946
+ ptr->cinfo.in_color_space = ptr->color_space;
947
+ ptr->cinfo.input_components = ptr->components;
948
+
949
+ ptr->cinfo.optimize_coding = TRUE;
950
+ ptr->cinfo.arith_code = TRUE;
951
+ ptr->cinfo.raw_data_in = FALSE;
952
+ ptr->cinfo.dct_method = ptr->dct_method;
953
+
954
+ jpeg_set_defaults(&ptr->cinfo);
955
+ jpeg_set_quality(&ptr->cinfo, ptr->quality, TRUE);
956
+ jpeg_suppress_tables(&ptr->cinfo, TRUE);
957
+ }
577
958
 
578
- ptr->cinfo.optimize_coding = TRUE;
579
- ptr->cinfo.arith_code = TRUE;
580
- ptr->cinfo.raw_data_in = FALSE;
581
- ptr->cinfo.dct_method = ptr->dct_method;
959
+ /*
960
+ * post process
961
+ */
962
+ if (RTEST(ret)) {
963
+ if (ary != NULL) free(ary);
964
+ if (rows != NULL) free(rows);
965
+ }
582
966
 
583
- jpeg_set_defaults(&ptr->cinfo);
584
- jpeg_set_quality(&ptr->cinfo, quality, TRUE);
585
- jpeg_suppress_tables(&ptr->cinfo, TRUE);
967
+ return ret;
586
968
  }
587
969
 
970
+ /**
971
+ * initialize encoder object
972
+ *
973
+ * @overload initialize(width, height, opts)
974
+ *
975
+ * @param width [Integer] width of input image (px)
976
+ * @param height [Integer] height of input image (px)
977
+ * @param opts [Hash] options to initialize object
978
+ *
979
+ * @option opts [Symbol] :pixel_format
980
+ * specifies the format of the input image. possible values are:
981
+ * YUV422 YUYV RGB565 RGB RGB24 BGR BGR24 YUV444 YCbCr
982
+ * RGBX RGB32 BGRX BGR32 GRAYSCALE
983
+ *
984
+ * @option opts [Integer] :quality
985
+ * specifies the quality of the compressed image.
986
+ * You can specify from 0 (lowest) to 100 (best).
987
+ *
988
+ * @option opts [Symbol] :dct_method
989
+ * specifies how encoding is handled. possible values are:
990
+ * FASTEST ISLOW IFAST FLOAT
991
+ */
588
992
  static VALUE
589
993
  rb_encoder_initialize(int argc, VALUE *argv, VALUE self)
590
994
  {
591
995
  jpeg_encode_t* ptr;
996
+ VALUE exc;
592
997
  VALUE wd;
593
998
  VALUE ht;
594
999
  VALUE opt;
@@ -596,191 +1001,281 @@ rb_encoder_initialize(int argc, VALUE *argv, VALUE self)
596
1001
  /*
597
1002
  * initialize
598
1003
  */
599
- Data_Get_Struct(self, jpeg_encode_t, ptr);
1004
+ exc = Qnil;
1005
+
1006
+ TypedData_Get_Struct(self, jpeg_encode_t, &jpeg_encoder_data_type, ptr);
600
1007
 
601
1008
  /*
602
1009
  * parse arguments
603
1010
  */
604
- rb_scan_args(argc, argv, "21", &wd, &ht, &opt);
1011
+ rb_scan_args(argc, argv, "2:", &wd, &ht, &opt);
1012
+
1013
+ /*
1014
+ * argument check
1015
+ */
1016
+ do {
1017
+ if (TYPE(wd) != T_FIXNUM) {
1018
+ exc = create_argument_error("invalid width");
1019
+ break;
1020
+ }
605
1021
 
606
- Check_Type(wd, T_FIXNUM);
607
- Check_Type(ht, T_FIXNUM);
608
- if (opt != Qnil) Check_Type(opt, T_HASH);
1022
+ if (TYPE(ht) != T_FIXNUM) {
1023
+ exc = create_argument_error("invalid height");
1024
+ break;
1025
+ }
1026
+ } while (0);
609
1027
 
610
1028
  /*
611
1029
  * set context
612
1030
  */
613
- set_encoder_context(ptr, FIX2INT(wd), FIX2INT(ht), opt);
1031
+ if (!RTEST(exc)) {
1032
+ exc = set_encoder_context(ptr, FIX2INT(wd), FIX2INT(ht), opt);
1033
+ }
1034
+
1035
+ /*
1036
+ * post process
1037
+ */
1038
+ if (RTEST(exc)) rb_exc_raise(exc);
614
1039
 
615
1040
  return Qtrue;
616
1041
  }
617
1042
 
618
- static int
619
- push_rows_yuv422(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1043
+ static void
1044
+ push_rows_yuv422(JSAMPROW dst, int wd, int st, uint8_t* data, int nrow)
620
1045
  {
621
- int size;
1046
+ uint8_t* src;
622
1047
  int i;
1048
+ int j;
623
1049
 
624
- size = wd * nrow;
1050
+ for (i = 0; i < nrow; i++) {
1051
+ src = data;
625
1052
 
626
- for (i = 0; i < size; i += 2) {
627
- rows[0] = data[0];
628
- rows[1] = data[1];
629
- rows[2] = data[3];
630
- rows[3] = data[2];
631
- rows[4] = data[1];
632
- rows[5] = data[3];
1053
+ for (j = 0; j < wd; j += 2) {
1054
+ dst[0] = src[0];
1055
+ dst[1] = src[1];
1056
+ dst[2] = src[3];
1057
+ dst[3] = src[2];
1058
+ dst[4] = src[1];
1059
+ dst[5] = src[3];
633
1060
 
634
- rows += 6;
635
- data += 4;
636
- }
1061
+ dst += 6;
1062
+ src += 4;
1063
+ }
637
1064
 
638
- return (size * 2);
1065
+ data += st;
1066
+ }
639
1067
  }
640
1068
 
641
- static int
642
- push_rows_rgb565(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1069
+ static void
1070
+ push_rows_rgb565(JSAMPROW dst, int wd, int st, uint8_t* data, int nrow)
643
1071
  {
644
- int size;
1072
+ uint8_t* src;
645
1073
  int i;
1074
+ int j;
646
1075
 
647
- size = wd * nrow;
1076
+ for (i = 0; i < nrow; i++) {
1077
+ src = data;
648
1078
 
649
- for (i = 0; i < size; i += 1) {
650
- rows[0] = data[1] & 0xf8;
651
- rows[1] = ((data[1] << 5) & 0xe0) | ((data[0] >> 3) & 0x1c);
652
- rows[2] = (data[0] << 3) & 0xf8;
1079
+ for (j = 0; j < wd; j++) {
1080
+ dst[0] = src[1] & 0xf8;
1081
+ dst[1] = ((src[1] << 5) & 0xe0) | ((src[0] >> 3) & 0x1c);
1082
+ dst[2] = (src[0] << 3) & 0xf8;
653
1083
 
654
- rows += 3;
655
- data += 2;
656
- }
1084
+ dst += 3;
1085
+ src += 2;
1086
+ }
657
1087
 
658
- return (size * 2);
1088
+ data += st;
1089
+ }
659
1090
  }
660
1091
 
661
- static int
662
- push_rows_comp3(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1092
+ static void
1093
+ push_rows_comp3(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
663
1094
  {
664
1095
  int size;
1096
+ int i;
1097
+
1098
+ size = wd * 3;
665
1099
 
666
- size = wd * nrow * 3;
667
- memcpy(rows, data, size);
1100
+ for (i = 0; i < nrow; i++) {
1101
+ memcpy(rows, data, size);
668
1102
 
669
- return size;
1103
+ rows += size;
1104
+ data += st;
1105
+ }
670
1106
  }
671
1107
 
672
- static int
673
- push_rows_comp4(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1108
+ static void
1109
+ push_rows_comp4(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
674
1110
  {
675
1111
  int size;
1112
+ int i;
676
1113
 
677
- size = wd * nrow * 4;
678
- memcpy(rows, data, size);
679
-
680
- return size;
681
- }
1114
+ size = wd * 4;
682
1115
 
1116
+ for (i = 0; i < nrow; i++) {
1117
+ memcpy(rows, data, size);
683
1118
 
1119
+ rows += size;
1120
+ data += st;
1121
+ }
1122
+ }
684
1123
 
685
- static int
686
- push_rows_grayscale(JSAMPROW rows, int wd, uint8_t* data, int nrow)
1124
+ static void
1125
+ push_rows_grayscale(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
687
1126
  {
688
- int size;
1127
+ int i;
689
1128
 
690
- size = wd * nrow;
691
- memcpy(rows, data, size);
1129
+ for (i = 0; i < nrow; i++) {
1130
+ memcpy(rows, data, wd);
692
1131
 
693
- return size;
1132
+ rows += wd;
1133
+ data += st;
1134
+ }
694
1135
  }
695
1136
 
696
- static int
1137
+ static void
697
1138
  push_rows(jpeg_encode_t* ptr, uint8_t* data, int nrow)
698
1139
  {
699
- int ret;
700
-
701
1140
  switch (ptr->format) {
702
1141
  case FMT_YUV422:
703
- ret = push_rows_yuv422(ptr->rows, ptr->width, data, nrow);
1142
+ push_rows_yuv422(ptr->rows, ptr->width, ptr->stride, data, nrow);
704
1143
  break;
705
1144
 
706
1145
  case FMT_RGB565:
707
- ret = push_rows_rgb565(ptr->rows, ptr->width, data, nrow);
1146
+ push_rows_rgb565(ptr->rows, ptr->width, ptr->stride, data, nrow);
708
1147
  break;
709
1148
 
710
1149
  case FMT_YUV:
711
1150
  case FMT_RGB:
712
1151
  case FMT_BGR:
713
- ret = push_rows_comp3(ptr->rows, ptr->width, data, nrow);
1152
+ push_rows_comp3(ptr->rows, ptr->width, ptr->stride, data, nrow);
714
1153
  break;
715
1154
 
716
1155
  case FMT_RGB32:
717
1156
  case FMT_BGR32:
718
- ret = push_rows_comp4(ptr->rows, ptr->width, data, nrow);
1157
+ push_rows_comp4(ptr->rows, ptr->width, ptr->stride, data, nrow);
719
1158
  break;
720
1159
 
721
1160
  case FMT_GRAYSCALE:
722
- ret = push_rows_grayscale(ptr->rows, ptr->width, data, nrow);
1161
+ push_rows_grayscale(ptr->rows, ptr->width, ptr->stride, data, nrow);
723
1162
  break;
724
1163
 
725
1164
  default:
726
1165
  RUNTIME_ERROR("Really?");
727
1166
  }
1167
+ }
728
1168
 
729
- return ret;
1169
+ static void
1170
+ put_exif_tags(jpeg_encode_t* ptr)
1171
+ {
1172
+ uint8_t data[] = {
1173
+ /* Exif header */
1174
+ 'E', 'x', 'i', 'f', 0x00, 0x00,
1175
+ 'M', 'M',
1176
+ 0x00, 0x2a,
1177
+ 0x00, 0x00, 0x00, 0x08,
1178
+ 0x00, 0x01,
1179
+
1180
+ /* orieatation */
1181
+ 0x01, 0x12,
1182
+ 0x00, 0x03,
1183
+ 0x00, 0x00, 0x00, 0x01,
1184
+ 0x00, 0x00,
1185
+ 0x00, 0x00,
1186
+
1187
+ /* end mark */
1188
+ 0x00, 0x00, 0x00, 0x00,
1189
+ };
1190
+
1191
+ data[24] = (ptr->orientation >> 8) & 0xff;
1192
+ data[25] = (ptr->orientation >> 0) & 0xff;
1193
+
1194
+ jpeg_write_marker(&ptr->cinfo, JPEG_APP1, data, sizeof(data));
730
1195
  }
731
1196
 
732
1197
  static VALUE
733
- do_encode(jpeg_encode_t* ptr, uint8_t* data)
1198
+ do_encode(VALUE _ptr)
734
1199
  {
735
1200
  VALUE ret;
736
-
737
- unsigned char* buf;
738
- unsigned long buf_size;
1201
+ jpeg_encode_t* ptr;
1202
+ uint8_t* data;
739
1203
  int nrow;
740
1204
 
741
- buf = NULL;
1205
+ /*
1206
+ * initialize
1207
+ */
1208
+ ret = Qnil;
1209
+ ptr = (jpeg_encode_t*)_ptr;
1210
+ data = (uint8_t*)RSTRING_PTR(ptr->data);
742
1211
 
1212
+ /*
1213
+ * do encode
1214
+ */
1215
+ if (setjmp(ptr->err_mgr.jmpbuf)) {
1216
+ /*
1217
+ * when error occurred
1218
+ */
1219
+ jpeg_abort_compress(&ptr->cinfo);
1220
+ rb_raise(encerr_klass, "%s", ptr->err_mgr.msg);
743
1221
 
744
- jpeg_mem_dest(&ptr->cinfo, &buf, &buf_size);
1222
+ } else {
1223
+ /*
1224
+ * normal path
1225
+ */
1226
+ jpeg_start_compress(&ptr->cinfo, TRUE);
745
1227
 
746
- jpeg_start_compress(&ptr->cinfo, TRUE);
1228
+ if (ptr->orientation != 0) {
1229
+ put_exif_tags(ptr);
1230
+ }
747
1231
 
748
- while (ptr->cinfo.next_scanline < ptr->cinfo.image_height) {
749
- nrow = ptr->cinfo.image_height - ptr->cinfo.next_scanline;
750
- if (nrow > UNIT_LINES) nrow = UNIT_LINES;
1232
+ while (ptr->cinfo.next_scanline < ptr->cinfo.image_height) {
1233
+ nrow = ptr->cinfo.image_height - ptr->cinfo.next_scanline;
1234
+ if (nrow > UNIT_LINES) nrow = UNIT_LINES;
751
1235
 
752
- data += push_rows(ptr, data, nrow);
753
- jpeg_write_scanlines(&ptr->cinfo, ptr->array, nrow);
754
- }
1236
+ push_rows(ptr, data, nrow);
755
1237
 
756
- jpeg_finish_compress(&ptr->cinfo);
1238
+ jpeg_write_scanlines(&ptr->cinfo, ptr->array, nrow);
1239
+ data += (ptr->stride * nrow);
1240
+ }
757
1241
 
758
- /*
759
- * create return data
760
- */
761
- ret = rb_str_buf_new(buf_size);
762
- rb_str_set_len(ret, buf_size);
1242
+ jpeg_finish_compress(&ptr->cinfo);
763
1243
 
764
- memcpy(RSTRING_PTR(ret), buf, buf_size);
1244
+ /*
1245
+ * build return data
1246
+ */
1247
+ ret = rb_str_buf_new(ptr->buf.size);
1248
+ rb_str_set_len(ret, ptr->buf.size);
765
1249
 
766
- /*
767
- * post process
768
- */
769
- free(buf);
1250
+ memcpy(RSTRING_PTR(ret), ptr->buf.mem, ptr->buf.size);
1251
+ }
770
1252
 
771
1253
  return ret;
772
1254
  }
773
1255
 
1256
+ /**
1257
+ * encode data
1258
+ *
1259
+ * @overload encode(raw)
1260
+ *
1261
+ * @param raw [String] raw image data to encode.
1262
+ *
1263
+ * @return [String] encoded JPEG data.
1264
+ */
774
1265
  static VALUE
775
1266
  rb_encoder_encode(VALUE self, VALUE data)
776
1267
  {
777
1268
  VALUE ret;
1269
+ int state;
778
1270
  jpeg_encode_t* ptr;
779
1271
 
780
1272
  /*
781
1273
  * initialize
782
1274
  */
783
- Data_Get_Struct(self, jpeg_encode_t, ptr);
1275
+ ret = Qnil;
1276
+ state = 0;
1277
+
1278
+ TypedData_Get_Struct(self, jpeg_encode_t, &jpeg_encoder_data_type, ptr);
784
1279
 
785
1280
  /*
786
1281
  * argument check
@@ -788,70 +1283,123 @@ rb_encoder_encode(VALUE self, VALUE data)
788
1283
  Check_Type(data, T_STRING);
789
1284
 
790
1285
  if (RSTRING_LEN(data) < ptr->data_size) {
791
- ARGUMENT_ERROR("raw image data is too short.");
1286
+ ARGUMENT_ERROR("image data is too short");
792
1287
  }
793
1288
 
794
1289
  if (RSTRING_LEN(data) > ptr->data_size) {
795
- ARGUMENT_ERROR("raw image data is too large.");
1290
+ ARGUMENT_ERROR("image data is too large");
1291
+ }
1292
+
1293
+ /*
1294
+ * alloc memory
1295
+ */
1296
+ jpeg_mem_dest(&ptr->cinfo, &ptr->buf.mem, &ptr->buf.size);
1297
+ if (ptr->buf.mem == NULL) {
1298
+ RUNTIME_ERROR("jpeg_mem_dest() failed");
796
1299
  }
797
1300
 
1301
+ /*
1302
+ * prepare
1303
+ */
1304
+ SET_DATA(ptr, data);
1305
+
798
1306
  /*
799
1307
  * do encode
800
1308
  */
801
- ret = do_encode(ptr, (uint8_t*)RSTRING_PTR(data));
1309
+ ret = rb_protect(do_encode, (VALUE)ptr, &state);
1310
+
1311
+ /*
1312
+ * post process
1313
+ */
1314
+ CLR_DATA(ptr);
1315
+
1316
+ if (ptr->buf.mem != NULL) {
1317
+ free(ptr->buf.mem);
1318
+
1319
+ ptr->buf.mem = NULL;
1320
+ ptr->buf.size = 0;
1321
+ }
1322
+
1323
+ if (state != 0) rb_jump_tag(state);
802
1324
 
803
1325
  return ret;
804
1326
  }
805
1327
 
806
1328
  static void
807
- rb_decoder_free(void* ptr)
1329
+ rb_decoder_mark(void* _ptr)
808
1330
  {
809
- //jpeg_destroy_decompress(&(((jpeg_decode_t*)ptr)->cinfo));
1331
+ jpeg_decode_t* ptr;
810
1332
 
811
- free(ptr);
1333
+ ptr = (jpeg_decode_t*)_ptr;
1334
+
1335
+ if (ptr->orientation.buf != Qnil) {
1336
+ rb_gc_mark(ptr->orientation.buf);
1337
+ }
1338
+
1339
+ if (ptr->data != Qnil) {
1340
+ rb_gc_mark(ptr->data);
1341
+ }
812
1342
  }
813
1343
 
814
1344
  static void
815
- decode_output_message(j_common_ptr cinfo)
1345
+ rb_decoder_free(void* _ptr)
816
1346
  {
817
- ext_error_t* err;
1347
+ jpeg_decode_t* ptr;
818
1348
 
819
- err = (ext_error_t*)cinfo->err;
1349
+ ptr = (jpeg_decode_t*)_ptr;
820
1350
 
821
- (*err->jerr.format_message)(cinfo, err->msg);
822
- }
1351
+ if (ptr->array != NULL) {
1352
+ free(ptr->array);
1353
+ }
823
1354
 
824
- static void
825
- decode_emit_message(j_common_ptr cinfo, int msg_level)
826
- {
827
- ext_error_t* err;
1355
+ ptr->orientation.buf = Qnil;
1356
+ ptr->data = Qnil;
828
1357
 
829
- if (msg_level < 0) {
830
- err = (ext_error_t*)cinfo->err;
831
- (*err->jerr.format_message)(cinfo, err->msg);
832
- /*
833
- * 以前はemit_messageが呼ばれるとエラー扱いしていたが、
834
- * Logicoolの一部のモデルなどで問題が出るので無視する
835
- * ようにした。
836
- * また本来であれば、警告表示を行うべきでもあるが一部
837
- * のモデルで大量にemitされる場合があるので表示しない
838
- * ようにしている。
839
- * 問題が発生した際は、最後のメッセージをオブジェクト
840
- * のインスタンスとして持たすべき。
841
- */
842
- // longjmp(err->jmpbuf, 1);
1358
+ if (TEST_FLAG(ptr, F_CREAT)) {
1359
+ jpeg_destroy_decompress(&ptr->cinfo);
843
1360
  }
1361
+
1362
+ free(ptr);
844
1363
  }
845
1364
 
846
- static void
847
- decode_error_exit(j_common_ptr cinfo)
1365
+ static size_t
1366
+ rb_decoder_size(const void* ptr)
848
1367
  {
849
- ext_error_t* err;
1368
+ size_t ret;
850
1369
 
851
- err = (ext_error_t*)cinfo->err;
852
- (*err->jerr.format_message)(cinfo, err->msg);
853
- longjmp(err->jmpbuf, 1);
854
- }
1370
+ ret = sizeof(jpeg_decode_t);
1371
+
1372
+ return ret;
1373
+ }
1374
+
1375
+ #if RUBY_API_VERSION_CODE > 20600
1376
+ static const rb_data_type_t jpeg_decoder_data_type = {
1377
+ "libjpeg-ruby decoder object", // wrap_struct_name
1378
+ {
1379
+ rb_decoder_mark, // function.dmark
1380
+ rb_decoder_free, // function.dfree
1381
+ rb_decoder_size, // function.dsize
1382
+ NULL, // function.dcompact
1383
+ {NULL}, // function.reserved
1384
+ },
1385
+ NULL, // parent
1386
+ NULL, // data
1387
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
1388
+ };
1389
+ #else /* RUBY_API_VERSION_CODE > 20600 */
1390
+ static const rb_data_type_t jpeg_decoder_data_type = {
1391
+ "libjpeg-ruby decoder object", // wrap_struct_name
1392
+ {
1393
+ rb_decoder_mark, // function.dmark
1394
+ rb_decoder_free, // function.dfree
1395
+ rb_decoder_size, // function.dsize
1396
+ {NULL, NULL}, // function.reserved
1397
+ },
1398
+ NULL, // parent
1399
+ NULL, // data
1400
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
1401
+ };
1402
+ #endif /* RUBY_API_VERSION_CODE > 20600 */
855
1403
 
856
1404
  static VALUE
857
1405
  rb_decoder_alloc(VALUE self)
@@ -861,54 +1409,40 @@ rb_decoder_alloc(VALUE self)
861
1409
  ptr = ALLOC(jpeg_decode_t);
862
1410
  memset(ptr, 0, sizeof(*ptr));
863
1411
 
864
- ptr->format = FMT_RGB;
865
- ptr->need_meta = !0;
866
- ptr->expand_colormap = 0;
867
- ptr->parse_exif = 0;
868
-
869
- ptr->out_color_space = JCS_RGB;
870
-
871
- ptr->scale_num = 1;
872
- ptr->scale_denom = 1;
1412
+ ptr->flags = DEFAULT_DECODE_FLAGS;
873
1413
 
874
- ptr->out_color_components = 3;
875
- ptr->output_gamma = 0.0;
876
- ptr->buffered_image = FALSE;
877
- ptr->do_fancy_upsampling = FALSE;
878
- ptr->do_block_smoothing = FALSE;
879
- ptr->quantize_colors = FALSE;
880
- ptr->dither_mode = JDITHER_NONE;
881
- ptr->dct_method = JDCT_FASTEST;
882
- ptr->desired_number_of_colors = 0;
883
- ptr->enable_1pass_quant = FALSE;
884
- ptr->enable_external_quant = FALSE;
885
- ptr->enable_2pass_quant = FALSE;
886
-
887
- return Data_Wrap_Struct(decoder_klass, 0, rb_decoder_free, ptr);
1414
+ return TypedData_Wrap_Struct(decoder_klass, &jpeg_decoder_data_type, ptr);
888
1415
  }
889
1416
 
890
- static void
891
- eval_decoder_opt_pixel_format(jpeg_decode_t* ptr, VALUE opt)
1417
+ static VALUE
1418
+ eval_decoder_pixel_format_opt(jpeg_decode_t* ptr, VALUE opt)
892
1419
  {
1420
+ VALUE ret;
893
1421
  int format;
894
1422
  int color_space;
895
1423
  int components;
896
1424
 
897
- if (opt != Qundef) {
1425
+ ret = Qnil;
1426
+
1427
+ switch (TYPE(opt)) {
1428
+ case T_UNDEF:
1429
+ format = FMT_RGB;
1430
+ color_space = JCS_RGB;
1431
+ components = 3;
1432
+ break;
1433
+
1434
+ case T_STRING:
1435
+ case T_SYMBOL:
898
1436
  if(EQ_STR(opt, "RGB") || EQ_STR(opt, "RGB24")) {
899
1437
  format = FMT_RGB;
900
1438
  color_space = JCS_RGB;
901
1439
  components = 3;
902
1440
 
903
1441
  } else if (EQ_STR(opt, "YUV422") || EQ_STR(opt, "YUYV")) {
904
- format = FMT_YUV422;
905
- color_space = JCS_YCbCr;
906
- components = 3;
1442
+ ret = create_not_implement_error( "not implemented colorspace");
907
1443
 
908
1444
  } else if (EQ_STR(opt, "RGB565")) {
909
- format = FMT_RGB565;
910
- color_space = JCS_RGB;
911
- components = 3;
1445
+ ret = create_not_implement_error( "not implemented colorspace");
912
1446
 
913
1447
  } else if (EQ_STR(opt, "GRAYSCALE")) {
914
1448
  format = FMT_GRAYSCALE;
@@ -941,254 +1475,555 @@ eval_decoder_opt_pixel_format(jpeg_decode_t* ptr, VALUE opt)
941
1475
  components = 4;
942
1476
 
943
1477
  } else {
944
- ARGUMENT_ERROR("Unsupportd :pixel_format option value.");
1478
+ ret = create_argument_error("unsupportd :pixel_format option value");
945
1479
  }
1480
+ break;
1481
+
1482
+ default:
1483
+ ret = create_type_error("unsupportd :pixel_format option type");
1484
+ break;
1485
+ }
946
1486
 
947
- ptr->format = format;
948
- ptr->out_color_space = color_space;
949
- ptr->out_color_components = components;
1487
+ if (!RTEST(ret)) {
1488
+ ptr->format = format;
1489
+ ptr->out_color_space = color_space;
1490
+ ptr->out_color_components = components;
950
1491
  }
1492
+
1493
+ return ret;
951
1494
  }
952
1495
 
953
- static void
954
- eval_decoder_opt_output_gamma(jpeg_decode_t* ptr, VALUE opt)
1496
+ static VALUE
1497
+ eval_decoder_output_gamma_opt(jpeg_decode_t* ptr, VALUE opt)
955
1498
  {
1499
+ VALUE ret;
1500
+ double gamma;
1501
+
1502
+ ret = Qnil;
1503
+
956
1504
  switch (TYPE(opt)) {
957
1505
  case T_UNDEF:
958
- // Nothing
1506
+ gamma = 0.0;
959
1507
  break;
960
1508
 
1509
+ case T_FIXNUM:
961
1510
  case T_FLOAT:
962
- ptr->output_gamma = NUM2DBL(opt);
1511
+ if (isnan(NUM2DBL(opt)) || isinf(NUM2DBL(opt))) {
1512
+ ret = create_argument_error("unsupported :output_gamma value");
1513
+ } else {
1514
+ gamma = NUM2DBL(opt);
1515
+ }
963
1516
  break;
964
1517
 
965
1518
  default:
966
- ARGUMENT_ERROR("Unsupportd :output_gamma option value.");
1519
+ ret = create_type_error("unsupported :output_gamma type");
967
1520
  break;
968
1521
  }
1522
+
1523
+ if (!RTEST(ret)) ptr->output_gamma = gamma;
1524
+
1525
+ return ret;
969
1526
  }
970
1527
 
971
- static void
972
- eval_decoder_opt_do_fancy_upsampling(jpeg_decode_t* ptr, VALUE opt)
1528
+ static VALUE
1529
+ eval_decoder_do_fancy_upsampling_opt(jpeg_decode_t* ptr, VALUE opt)
973
1530
  {
974
- if (opt != Qundef) {
975
- ptr->do_fancy_upsampling = (RTEST(opt))? TRUE: FALSE;
1531
+ if (opt != Qundef && RTEST(opt)) {
1532
+ ptr->do_fancy_upsampling = TRUE;
1533
+ } else {
1534
+ ptr->do_fancy_upsampling = FALSE;
976
1535
  }
1536
+
1537
+ return Qnil;
977
1538
  }
978
1539
 
979
- static void
980
- eval_decoder_opt_do_smoothing(jpeg_decode_t* ptr, VALUE opt)
1540
+ static VALUE
1541
+ eval_decoder_do_smoothing_opt(jpeg_decode_t* ptr, VALUE opt)
981
1542
  {
982
- if (opt != Qundef) {
983
- ptr->do_block_smoothing = (RTEST(opt))? TRUE: FALSE;
1543
+ if (opt != Qundef && RTEST(opt)) {
1544
+ ptr->do_block_smoothing = TRUE;
1545
+ } else {
1546
+ ptr->do_block_smoothing = FALSE;
984
1547
  }
1548
+
1549
+ return Qnil;
985
1550
  }
986
1551
 
987
- static void
988
- eval_decoder_opt_dither( jpeg_decode_t* ptr, VALUE opt)
1552
+ static VALUE
1553
+ eval_decoder_dither_opt( jpeg_decode_t* ptr, VALUE opt)
989
1554
  {
990
- VALUE dmode;
991
- VALUE pass2;
992
- VALUE n_col;
1555
+ VALUE ret;
1556
+ VALUE tmp;
1557
+ int mode;
1558
+ int quant;
1559
+ int pass2;
1560
+ int ncol;
993
1561
 
994
- if (opt != Qundef) {
995
- if (TYPE(opt) != T_ARRAY) {
996
- ARGUMENT_ERROR("Unsupportd :dither option value.");
997
- }
1562
+ ret = Qnil;
1563
+
1564
+ switch (TYPE(opt)) {
1565
+ case T_UNDEF:
1566
+ mode = JDITHER_NONE;
1567
+ quant = FALSE;
1568
+ ncol = 0;
1569
+ pass2 = FALSE;
1570
+ break;
998
1571
 
1572
+ case T_ARRAY:
999
1573
  if (RARRAY_LEN(opt) != 3) {
1000
- ARGUMENT_ERROR(":dither is illeagal length (shall be 3 entries).");
1001
- }
1574
+ ret = create_argument_error(":dither invalid size");
1575
+
1576
+ } else do {
1577
+ /*
1578
+ * dither mode
1579
+ */
1580
+ tmp = rb_ary_entry(opt, 0);
1581
+ if (TYPE(tmp) != T_STRING && TYPE(tmp) != T_SYMBOL) {
1582
+ ret = create_type_error("unsupported dither mode type");
1583
+ break;
1002
1584
 
1003
- dmode = RARRAY_AREF(opt, 0);
1004
- pass2 = RARRAY_AREF(opt, 1);
1005
- n_col = RARRAY_AREF(opt, 2);
1006
-
1007
- if (EQ_STR(dmode, "NONE")) {
1008
- ptr->dither_mode = JDITHER_NONE;
1009
- ptr->quantize_colors = FALSE;
1585
+ } else if (EQ_STR(tmp, "NONE")) {
1586
+ mode = JDITHER_NONE;
1587
+ quant = FALSE;
1010
1588
 
1011
- } else if(EQ_STR(dmode, "ORDERED")) {
1012
- ptr->dither_mode = JDITHER_ORDERED;
1013
- ptr->quantize_colors = TRUE;
1589
+ } else if(EQ_STR(tmp, "ORDERED")) {
1590
+ mode = JDITHER_ORDERED;
1591
+ quant = TRUE;
1014
1592
 
1015
- } else if(EQ_STR(dmode, "FS")) {
1016
- ptr->dither_mode = JDITHER_FS;
1017
- ptr->quantize_colors = TRUE;
1593
+ } else if(EQ_STR(tmp, "FS")) {
1594
+ mode = JDITHER_FS;
1595
+ quant = TRUE;
1018
1596
 
1019
- } else {
1020
- ARGUMENT_ERROR("dither mode is illeagal value.");
1021
- }
1597
+ } else {
1598
+ ret = create_argument_error("dither mode is illeagal value.");
1599
+ break;
1600
+ }
1022
1601
 
1023
- ptr->two_pass_quantize = (RTEST(pass2))? TRUE: FALSE;
1602
+ /*
1603
+ * 2 pass flag
1604
+ */
1605
+ pass2 = (RTEST(rb_ary_entry(opt, 1)))? TRUE: FALSE;
1606
+
1607
+ /*
1608
+ * number of color
1609
+ */
1610
+ tmp = rb_ary_entry(opt, 2);
1611
+ if (TYPE(tmp) != T_FIXNUM) {
1612
+ ret = create_type_error("unsupported number of colors type");
1613
+ break;
1024
1614
 
1025
- if (TYPE(n_col) == T_FIXNUM) {
1026
- ptr->desired_number_of_colors = FIX2INT(n_col);
1027
- } else {
1028
- ARGUMENT_ERROR( "number of dithered colors is illeagal value.");
1029
- }
1615
+ } else if (FIX2LONG(tmp) < 8) {
1616
+ ret = create_range_error("number of colors less than 0");
1617
+ break;
1618
+
1619
+ } else if (FIX2LONG(tmp) > 256) {
1620
+ ret = create_range_error("number of colors greater than 256");
1621
+ break;
1622
+
1623
+ } else {
1624
+ ncol = FIX2INT(tmp);
1625
+ }
1626
+ } while (0);
1627
+ break;
1628
+
1629
+ default:
1630
+ ret = create_type_error("unsupported :dither type");
1631
+ break;
1632
+ }
1633
+
1634
+ if (!RTEST(ret)) {
1635
+ ptr->dither_mode = mode;
1636
+ ptr->quantize_colors = quant;
1637
+ ptr->two_pass_quantize = pass2;
1638
+ ptr->desired_number_of_colors = ncol;
1639
+
1640
+ if (mode != JDITHER_NONE) SET_FLAG(ptr, F_DITHER);
1030
1641
  }
1642
+
1643
+ return ret;
1031
1644
  }
1032
1645
 
1646
+ #if 0
1033
1647
  static void
1034
- eval_decoder_opt_use_1pass_quantizer(jpeg_decode_t* ptr, VALUE opt)
1648
+ eval_decoder_use_1pass_quantizer_opt(jpeg_decode_t* ptr, VALUE opt)
1035
1649
  {
1036
- if (opt != Qundef) {
1037
- if (RTEST(opt)) {
1038
- ptr->enable_1pass_quant = TRUE;
1039
- ptr->buffered_image = TRUE;
1040
- } else {
1041
- ptr->enable_1pass_quant = FALSE;
1042
- }
1650
+ if (opt != Qundef && RTEST(opt)) {
1651
+ ptr->enable_1pass_quant = TRUE;
1652
+ } else {
1653
+ ptr->enable_1pass_quant = FALSE;
1043
1654
  }
1655
+
1656
+ return Qnil;
1044
1657
  }
1045
1658
 
1046
- static void
1047
- eval_decoder_opt_use_external_colormap(jpeg_decode_t* ptr, VALUE opt)
1659
+ static VALUE
1660
+ eval_decoder_use_external_colormap_opt(jpeg_decode_t* ptr, VALUE opt)
1048
1661
  {
1049
- if (opt != Qundef) {
1050
- if (RTEST(opt)) {
1662
+ if (opt != Qundef && RTEST(opt)) {
1051
1663
  ptr->enable_external_quant = TRUE;
1052
- ptr->buffered_image = TRUE;
1053
1664
  } else {
1054
1665
  ptr->enable_external_quant = FALSE;
1055
1666
  }
1056
1667
  }
1668
+
1669
+ return Qnil;
1057
1670
  }
1058
1671
 
1059
- static void
1060
- eval_decoder_opt_use_2pass_quantizer(jpeg_decode_t* ptr, VALUE opt)
1672
+ static VALUE
1673
+ eval_decoder_use_2pass_quantizer_opt(jpeg_decode_t* ptr, VALUE opt)
1061
1674
  {
1062
- if (opt != Qundef) {
1063
- if (RTEST(opt)) {
1675
+ if (opt != Qundef && RTEST(opt)) {
1064
1676
  ptr->enable_2pass_quant = TRUE;
1065
- ptr->buffered_image = TRUE;
1066
1677
  } else {
1067
1678
  ptr->enable_2pass_quant = FALSE;
1068
1679
  }
1069
1680
  }
1681
+
1682
+ return Qnil;
1070
1683
  }
1684
+ #endif
1071
1685
 
1072
- static void
1073
- eval_decoder_opt_without_meta(jpeg_decode_t* ptr, VALUE opt)
1686
+ static VALUE
1687
+ eval_decoder_without_meta_opt(jpeg_decode_t* ptr, VALUE opt)
1074
1688
  {
1075
- if (opt != Qundef) {
1076
- ptr->need_meta = RTEST(opt);
1689
+ if (opt != Qundef && RTEST(opt)) {
1690
+ CLR_FLAG(ptr, F_NEED_META);
1691
+ } else {
1692
+ SET_FLAG(ptr, F_NEED_META);
1077
1693
  }
1694
+
1695
+ return Qnil;
1078
1696
  }
1079
1697
 
1080
- static void
1081
- eval_decoder_opt_expand_colormap(jpeg_decode_t* ptr, VALUE opt)
1698
+ static VALUE
1699
+ eval_decoder_expand_colormap_opt(jpeg_decode_t* ptr, VALUE opt)
1082
1700
  {
1083
- if (opt != Qundef) {
1084
- ptr->expand_colormap = RTEST(opt);
1701
+ if (opt != Qundef && RTEST(opt)) {
1702
+ SET_FLAG(ptr, F_EXPAND_COLORMAP);
1703
+ } else {
1704
+ CLR_FLAG(ptr, F_EXPAND_COLORMAP);
1085
1705
  }
1706
+
1707
+ return Qnil;
1086
1708
  }
1087
1709
 
1088
- static void
1089
- eval_decoder_opt_scale(jpeg_decode_t* ptr, VALUE opt)
1710
+
1711
+ static VALUE
1712
+ eval_decoder_scale_opt(jpeg_decode_t* ptr, VALUE opt)
1090
1713
  {
1714
+ VALUE ret;
1715
+ int scale_num;
1716
+ int scale_denom;
1717
+
1718
+ ret = Qnil;
1719
+
1091
1720
  switch (TYPE(opt)) {
1092
1721
  case T_UNDEF:
1093
- // Nothing
1722
+ scale_num = 1;
1723
+ scale_denom = 1;
1724
+ break;
1725
+
1726
+ case T_FIXNUM:
1727
+ if (FIX2LONG(opt) <= 0) {
1728
+ ret = create_range_error(":scale less equal 0");
1729
+
1730
+ } else {
1731
+ scale_num = FIX2INT(opt) * 1000;
1732
+ scale_denom = 1000;
1733
+ }
1094
1734
  break;
1095
1735
 
1096
1736
  case T_FLOAT:
1097
- ptr->scale_num = 1000;
1098
- ptr->scale_denom = (int)(NUM2DBL(opt) * 1000.0);
1737
+ if (isnan(NUM2DBL(opt)) || isinf(NUM2DBL(opt))) {
1738
+ ret = create_argument_error("unsupportd :quality option value");
1739
+
1740
+ } else if (NUM2DBL(opt) <= 0.0) {
1741
+ ret = create_range_error(":scale less equal 0");
1742
+
1743
+ } else {
1744
+ scale_num = (int)(NUM2DBL(opt) * 1000.0);
1745
+ scale_denom = 1000;
1746
+ }
1099
1747
  break;
1100
1748
 
1101
1749
  case T_RATIONAL:
1102
- ptr->scale_num = FIX2INT(rb_rational_num(opt));
1103
- ptr->scale_denom = FIX2INT(rb_rational_den(opt));
1750
+ scale_num = (int)FIX2LONG(rb_rational_num(opt));
1751
+ scale_denom = (int)FIX2LONG(rb_rational_den(opt));
1104
1752
  break;
1105
1753
 
1106
1754
  default:
1107
- ARGUMENT_ERROR("Unsupportd :exapnd_colormap option value.");
1755
+ ret = create_type_error("unsupportd :scale option type");
1108
1756
  break;
1109
1757
  }
1758
+
1759
+ if (!RTEST(ret)) {
1760
+ ptr->scale_num = scale_num;
1761
+ ptr->scale_denom = scale_denom;
1762
+ }
1763
+
1764
+ return ret;
1110
1765
  }
1111
1766
 
1112
- static void
1113
- eval_decoder_opt_dct_method(jpeg_decode_t* ptr, VALUE opt)
1767
+ static VALUE
1768
+ eval_decoder_dct_method_opt(jpeg_decode_t* ptr, VALUE opt)
1114
1769
  {
1115
- if (opt != Qundef) {
1116
- if (EQ_STR(opt, "ISLOW")) {
1117
- ptr->dct_method = JDCT_ISLOW;
1770
+ VALUE ret;
1771
+ int dct_method;
1772
+
1773
+ ret = Qnil;
1774
+
1775
+ switch (TYPE(opt)) {
1776
+ case T_UNDEF:
1777
+ dct_method = JDCT_FASTEST;
1778
+ break;
1779
+
1780
+ case T_STRING:
1781
+ case T_SYMBOL:
1782
+ if (EQ_STR(opt, "FASTEST")) {
1783
+ dct_method = JDCT_FASTEST;
1784
+
1785
+ } else if (EQ_STR(opt, "ISLOW")) {
1786
+ dct_method = JDCT_ISLOW;
1118
1787
 
1119
1788
  } else if (EQ_STR(opt, "IFAST")) {
1120
- ptr->dct_method = JDCT_IFAST;
1789
+ dct_method = JDCT_IFAST;
1121
1790
 
1122
1791
  } else if (EQ_STR(opt, "FLOAT")) {
1123
- ptr->dct_method = JDCT_FLOAT;
1124
-
1125
- } else if (EQ_STR(opt, "FASTEST")) {
1126
- ptr->dct_method = JDCT_FASTEST;
1792
+ dct_method = JDCT_FLOAT;
1127
1793
 
1128
1794
  } else {
1129
- ARGUMENT_ERROR("Unsupportd :dct_method option value.");
1795
+ ret = create_argument_error("unsupportd :dct_method option value");
1130
1796
  }
1797
+ break;
1798
+
1799
+ default:
1800
+ ret = create_type_error("unsupportd :dct_method option type");
1801
+ break;
1131
1802
  }
1803
+
1804
+ if (!RTEST(ret)) ptr->dct_method = dct_method;
1805
+
1806
+ return ret;
1132
1807
  }
1133
1808
 
1134
- static void
1135
- eval_decoder_opt_with_exif(jpeg_decode_t* ptr, VALUE opt)
1809
+ static VALUE
1810
+ eval_decoder_with_exif_tags_opt(jpeg_decode_t* ptr, VALUE opt)
1811
+ {
1812
+ if (opt != Qundef && RTEST(opt)) {
1813
+ SET_FLAG(ptr, F_PARSE_EXIF);
1814
+ } else {
1815
+ CLR_FLAG(ptr, F_PARSE_EXIF);
1816
+ }
1817
+
1818
+ return Qnil;
1819
+ }
1820
+
1821
+ static VALUE
1822
+ eval_decoder_orientation_opt(jpeg_decode_t* ptr, VALUE opt)
1136
1823
  {
1137
- if (opt != Qundef) {
1138
- ptr->parse_exif = RTEST(opt);
1824
+ if (opt != Qundef && RTEST(opt)) {
1825
+ SET_FLAG(ptr, F_APPLY_ORIENTATION);
1826
+ } else {
1827
+ CLR_FLAG(ptr, F_APPLY_ORIENTATION);
1139
1828
  }
1829
+
1830
+ return Qnil;
1140
1831
  }
1141
1832
 
1142
- static void
1833
+ static VALUE
1143
1834
  set_decoder_context( jpeg_decode_t* ptr, VALUE opt)
1144
1835
  {
1836
+ VALUE ret;
1145
1837
  VALUE opts[N(decoder_opts_ids)];
1838
+ JSAMPARRAY ary;
1839
+
1840
+ /*
1841
+ * initialize
1842
+ */
1843
+ ret = Qnil;
1844
+ ary = NULL;
1146
1845
 
1147
1846
  /*
1148
1847
  * parse options
1149
1848
  */
1150
- rb_get_kwargs(opt, decoder_opts_ids, 0, N(decoder_opts_ids), opts);
1849
+ do {
1850
+ rb_get_kwargs(opt, decoder_opts_ids, 0, N(decoder_opts_ids), opts);
1851
+
1852
+ /*
1853
+ * set context
1854
+ */
1855
+ ret = eval_decoder_pixel_format_opt(ptr, opts[0]);
1856
+ if (RTEST(ret)) break;
1857
+
1858
+ ret = eval_decoder_output_gamma_opt(ptr, opts[1]);
1859
+ if (RTEST(ret)) break;
1860
+
1861
+ ret = eval_decoder_do_fancy_upsampling_opt(ptr, opts[2]);
1862
+ if (RTEST(ret)) break;
1863
+
1864
+ ret = eval_decoder_do_smoothing_opt(ptr, opts[3]);
1865
+ if (RTEST(ret)) break;
1866
+
1867
+ ret = eval_decoder_dither_opt(ptr, opts[4]);
1868
+ if (RTEST(ret)) break;
1869
+
1870
+ #if 0
1871
+ ret = eval_decoder_use_1pass_quantizer_opt(ptr, opts[5]);
1872
+ if (RTEST(ret)) break;
1873
+
1874
+ ret = eval_decoder_use_external_colormap_opt(ptr, opts[6]);
1875
+ if (RTEST(ret)) break;
1876
+
1877
+ ret = eval_decoder_use_2pass_quantizer_opt(ptr, opts[7]);
1878
+ if (RTEST(ret)) break;
1879
+ #endif
1880
+
1881
+ ret = eval_decoder_without_meta_opt(ptr, opts[5]);
1882
+ if (RTEST(ret)) break;
1883
+
1884
+ ret = eval_decoder_expand_colormap_opt(ptr, opts[6]);
1885
+ if (RTEST(ret)) break;
1886
+
1887
+ ret = eval_decoder_scale_opt(ptr, opts[7]);
1888
+ if (RTEST(ret)) break;
1889
+
1890
+ ret = eval_decoder_dct_method_opt(ptr, opts[8]);
1891
+ if (RTEST(ret)) break;
1892
+
1893
+ ret = eval_decoder_with_exif_tags_opt(ptr, opts[9]);
1894
+ if (RTEST(ret)) break;
1895
+
1896
+ ret = eval_decoder_orientation_opt(ptr, opts[10]);
1897
+ if (RTEST(ret)) break;
1898
+ } while (0);
1899
+
1900
+ /*
1901
+ * alloc memory
1902
+ */
1903
+ if (!RTEST(ret)) {
1904
+ ary = ALLOC_ARRAY();
1905
+ if (ary == NULL) ret = create_memory_error();
1906
+ }
1151
1907
 
1152
1908
  /*
1153
- * set context
1909
+ * set the rest context parameter
1910
+ */
1911
+ if (!RTEST(ret)) {
1912
+ ptr->err_mgr.jerr.output_message = output_message;
1913
+ ptr->err_mgr.jerr.emit_message = emit_message;
1914
+ ptr->err_mgr.jerr.error_exit = error_exit;
1915
+
1916
+ // 現時点でオプションでの対応をおこなっていないので
1917
+ // ここで値を設定
1918
+ ptr->enable_1pass_quant = FALSE;
1919
+ ptr->enable_external_quant = FALSE;
1920
+ ptr->enable_2pass_quant = FALSE;
1921
+ ptr->buffered_image = FALSE;
1922
+
1923
+ #if 0
1924
+ if (ptr->enable_1pass_quant == TRUE ||
1925
+ ptr->enable_external_quant == TRUE ||
1926
+ ptr->enable_2pass_quant == TRUE) {
1927
+ ptr->buffered_image = TRUE;
1928
+
1929
+ } else {
1930
+ ptr->buffered_image = FALSE;
1931
+ }
1932
+ #endif
1933
+
1934
+ ptr->array = ary;
1935
+ ptr->data = Qnil;
1936
+ ptr->orientation.value = 0;
1937
+ ptr->orientation.buf = Qnil;
1938
+ }
1939
+
1940
+ /*
1941
+ * setup libjpeg
1154
1942
  */
1155
- eval_decoder_opt_pixel_format(ptr, opts[0]);
1156
- eval_decoder_opt_output_gamma(ptr, opts[1]);
1157
- eval_decoder_opt_do_fancy_upsampling(ptr, opts[2]);
1158
- eval_decoder_opt_do_smoothing(ptr, opts[3]);
1159
- eval_decoder_opt_dither(ptr, opts[4]);
1160
- eval_decoder_opt_use_1pass_quantizer(ptr, opts[5]);
1161
- eval_decoder_opt_use_external_colormap(ptr, opts[6]);
1162
- eval_decoder_opt_use_2pass_quantizer(ptr, opts[7]);
1163
- eval_decoder_opt_without_meta(ptr, opts[8]);
1164
- eval_decoder_opt_expand_colormap(ptr, opts[9]);
1165
- eval_decoder_opt_scale(ptr, opts[10]);
1166
- eval_decoder_opt_dct_method(ptr, opts[11]);
1167
- eval_decoder_opt_with_exif(ptr, opts[12]);
1943
+ if (!RTEST(ret)) {
1944
+ jpeg_create_decompress(&ptr->cinfo);
1945
+ SET_FLAG(ptr, F_CREAT);
1946
+
1947
+ ptr->cinfo.err = jpeg_std_error(&ptr->err_mgr.jerr);
1948
+ }
1949
+
1950
+ return ret;
1168
1951
  }
1169
1952
 
1953
+ /**
1954
+ * initialize decoder object
1955
+ *
1956
+ * @overload initialize(opts)
1957
+ *
1958
+ * @param opts [Hash] options to initialize object
1959
+ *
1960
+ * @option opts [Symbol] :pixel_format
1961
+ * specifies the format of the output image. possible values are:
1962
+ * YUV422 YUYV RGB565 RGB RGB24 BGR BGR24 YUV444 YCbCr
1963
+ * RGBX RGB32 BGRX BGR32 GRAYSCALE
1964
+ *
1965
+ * @option opts [Float] :output_gamma
1966
+ *
1967
+ * @option opts [Boolean] :fancy_upsampling
1968
+ *
1969
+ * @option opts [Boolean] :do_smoothing
1970
+ *
1971
+ * @option opts [Array] :dither
1972
+ * specifies dithering parameters. A 3-elements array.
1973
+ * specify the dither type as a string for the 1st element,
1974
+ * whether to use 2-pass quantize for the 2nd element as a boolean,
1975
+ * and the number of colors used for the 3rd element as an integer
1976
+ * from 16 to 256.
1977
+ *
1978
+ * @option opts [Boolean] :without_meta
1979
+ * specifies whether or not to include meta information in the
1980
+ * output data. If true, no meta-information is output.
1981
+ *
1982
+ * @option opts [Boolean] :expand_colormap
1983
+ * specifies whether to expand the color map. If dither is specified,
1984
+ * the output will be a color number of 1 byte per pixel, but if this
1985
+ * option is set to true, the output will be expanded to color information.
1986
+ *
1987
+ * @option opts [Ratioanl] :scale
1988
+ *
1989
+ * @option opts [Symbol] :dct_method
1990
+ * specifies how decoding is handled. possible values are:
1991
+ * FASTEST ISLOW IFAST FLOAT
1992
+ *
1993
+ * @option opts [Boolean] :with_exif_tags
1994
+ * specifies whether to include Exif tag information in the output data.
1995
+ * set this option to true to parse the Exif tag information and include
1996
+ * it in the meta information output.
1997
+ *
1998
+ * @option opts [Boolean] :with_exif
1999
+ * alias to :with_exif_tags option.
2000
+ */
1170
2001
  static VALUE
1171
2002
  rb_decoder_initialize( int argc, VALUE *argv, VALUE self)
1172
2003
  {
1173
2004
  jpeg_decode_t* ptr;
2005
+ VALUE exc;
1174
2006
  VALUE opt;
1175
2007
 
1176
2008
  /*
1177
2009
  * initialize
1178
2010
  */
1179
- Data_Get_Struct(self, jpeg_decode_t, ptr);
2011
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
1180
2012
 
1181
2013
  /*
1182
2014
  * parse arguments
1183
2015
  */
1184
- rb_scan_args( argc, argv, "01", &opt);
1185
-
1186
- if (opt != Qnil) Check_Type(opt, T_HASH);
2016
+ rb_scan_args( argc, argv, "0:", &opt);
1187
2017
 
1188
2018
  /*
1189
2019
  * set context
1190
2020
  */
1191
- set_decoder_context(ptr, opt);
2021
+ exc = set_decoder_context(ptr, opt);
2022
+
2023
+ /*
2024
+ * post process
2025
+ */
2026
+ if (RTEST(exc)) rb_exc_raise(exc);
1192
2027
 
1193
2028
  return Qtrue;
1194
2029
  }
@@ -1197,11 +2032,12 @@ static VALUE
1197
2032
  rb_decoder_set(VALUE self, VALUE opt)
1198
2033
  {
1199
2034
  jpeg_decode_t* ptr;
2035
+ VALUE exc;
1200
2036
 
1201
2037
  /*
1202
2038
  * initialize
1203
2039
  */
1204
- Data_Get_Struct(self, jpeg_decode_t, ptr);
2040
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
1205
2041
 
1206
2042
  /*
1207
2043
  * check argument
@@ -1211,13 +2047,16 @@ rb_decoder_set(VALUE self, VALUE opt)
1211
2047
  /*
1212
2048
  * set context
1213
2049
  */
1214
- set_decoder_context(ptr, opt);
2050
+ exc = set_decoder_context(ptr, opt);
2051
+
2052
+ /*
2053
+ * post process
2054
+ */
2055
+ if (RTEST(exc)) rb_exc_raise(exc);
1215
2056
 
1216
2057
  return Qtrue;
1217
2058
  }
1218
2059
 
1219
-
1220
-
1221
2060
  static VALUE
1222
2061
  get_colorspace_str( J_COLOR_SPACE cs)
1223
2062
  {
@@ -1396,7 +2235,7 @@ exif_init(exif_t* ptr, uint8_t* src, size_t size)
1396
2235
  uint32_t off;
1397
2236
 
1398
2237
  /*
1399
- * Check Exif idntifier
2238
+ * Check Exif identifier
1400
2239
  */
1401
2240
  if (memcmp(src, "Exif\0\0", 6)) {
1402
2241
  rb_raise(decerr_klass, "invalid exif identifier");
@@ -1847,7 +2686,7 @@ exif_read(exif_t* ptr, VALUE dst)
1847
2686
  #define THUMBNAIL_SIZE ID2SYM(rb_intern("jpeg_interchange_format_length"))
1848
2687
 
1849
2688
  static VALUE
1850
- create_exif_hash(jpeg_decode_t* ptr)
2689
+ create_exif_tags_hash(jpeg_decode_t* ptr)
1851
2690
  {
1852
2691
  VALUE ret;
1853
2692
  jpeg_saved_marker_ptr marker;
@@ -1895,99 +2734,291 @@ create_exif_hash(jpeg_decode_t* ptr)
1895
2734
  return ret;
1896
2735
  }
1897
2736
 
1898
- static VALUE
1899
- create_meta(jpeg_decode_t* ptr)
2737
+ static void
2738
+ pick_exif_orientation(jpeg_decode_t* ptr)
1900
2739
  {
1901
- VALUE ret;
1902
- struct jpeg_decompress_struct* cinfo;
2740
+ jpeg_saved_marker_ptr marker;
2741
+ int o9n;
2742
+ uint8_t* p;
2743
+ int be;
2744
+ uint32_t off;
2745
+ int i;
2746
+ int n;
1903
2747
 
1904
- /* TODO: そのうちディザをかけた場合のカラーマップをメタで返すようにする */
2748
+ o9n = 0;
1905
2749
 
1906
- ret = rb_obj_alloc(meta_klass);
1907
- cinfo = &ptr->cinfo;
2750
+ for (marker = ptr->cinfo.marker_list;
2751
+ marker != NULL; marker = marker->next) {
1908
2752
 
1909
- rb_ivar_set(ret, id_width, INT2FIX(cinfo->output_width));
1910
- rb_ivar_set(ret, id_height, INT2FIX(cinfo->output_height));
1911
- rb_ivar_set(ret, id_orig_cs, get_colorspace_str(cinfo->jpeg_color_space));
2753
+ if (marker->data_length < 14) continue;
1912
2754
 
1913
- if (ptr->format == FMT_YVU) {
1914
- rb_ivar_set(ret, id_out_cs, rb_str_new_cstr("YCrCb"));
1915
- } else {
1916
- rb_ivar_set(ret, id_out_cs, get_colorspace_str(cinfo->out_color_space));
1917
- }
2755
+ p = marker->data;
1918
2756
 
1919
- rb_ivar_set(ret, id_ncompo, INT2FIX(cinfo->output_components));
2757
+ /*
2758
+ * check Exif identifier
2759
+ */
2760
+ if (memcmp(p, "Exif\0\0", 6)) continue;
1920
2761
 
1921
- if (ptr->parse_exif) {
1922
- rb_ivar_set(ret, id_exif, create_exif_hash(ptr));
1923
- }
2762
+ /*
2763
+ * check endian marker
2764
+ */
2765
+ if (!memcmp(p + 6, "MM", 2)) {
2766
+ be = !0;
1924
2767
 
1925
- return ret;
1926
- }
2768
+ } else if (!memcmp(p + 6, "II", 2)) {
2769
+ be = 0;
1927
2770
 
1928
- static VALUE
1929
- do_read_header(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
1930
- {
1931
- VALUE ret;
2771
+ } else {
2772
+ continue;
2773
+ }
1932
2774
 
1933
- switch (ptr->format) {
1934
- case FMT_YUV422:
1935
- case FMT_RGB565:
1936
- RUNTIME_ERROR( "Not implement");
2775
+ /*
2776
+ * check TIFF identifier
2777
+ */
2778
+ if (get_u16(p + 8, be) != 0x002a) continue;
2779
+
2780
+ /*
2781
+ * set 0th IFD address
2782
+ */
2783
+ off = get_u32(p + 10, be);
2784
+ if (off < 8 || off >= marker->data_length - 6) continue;
2785
+
2786
+ p += (6 + off);
2787
+
2788
+ /* ここまでくればAPP1がExifタグなので
2789
+ * 0th IFDをなめてOrientationタグを探す */
2790
+
2791
+ n = get_u16(p, be);
2792
+ p += 2;
2793
+
2794
+ for (i = 0; i < n; i++) {
2795
+ int tag;
2796
+ int type;
2797
+ int num;
2798
+
2799
+ tag = get_u16(p + 0, be);
2800
+ type = get_u16(p + 2, be);
2801
+ num = get_u32(p + 4, be);
2802
+
2803
+ if (tag == 0x0112) {
2804
+ if (type == 3 && num == 1) {
2805
+ o9n = get_u16(p + 8, be);
2806
+ goto loop_out;
2807
+
2808
+ } else {
2809
+ fprintf(stderr,
2810
+ "Illeagal orientation tag found [type:%d, num:%d]\n",
2811
+ type,
2812
+ num);
2813
+ }
2814
+ }
2815
+
2816
+ p += 12;
2817
+ }
2818
+ }
2819
+ loop_out:
2820
+
2821
+ ptr->orientation.value = (o9n >= 1 && o9n <= 8)? (o9n - 1): 0;
2822
+ }
2823
+
2824
+ static VALUE
2825
+ create_colormap(jpeg_decode_t* ptr)
2826
+ {
2827
+ VALUE ret;
2828
+ struct jpeg_decompress_struct* cinfo;
2829
+ JSAMPARRAY map;
2830
+ int i; // volatileを外すとaarch64のgcc6でクラッシュする場合がある
2831
+ uint32_t c;
2832
+
2833
+ cinfo = &ptr->cinfo;
2834
+ ret = rb_ary_new_capa(cinfo->actual_number_of_colors);
2835
+ map = cinfo->colormap;
2836
+
2837
+ switch (cinfo->out_color_components) {
2838
+ case 1:
2839
+ for (i = 0; i < cinfo->actual_number_of_colors; i++) {
2840
+ c = map[0][i];
2841
+ rb_ary_push(ret, INT2FIX(c));
2842
+ }
2843
+ break;
2844
+
2845
+ case 2:
2846
+ for (i = 0; i < cinfo->actual_number_of_colors; i++) {
2847
+ c = (map[0][i] << 8) | (map[1][i] << 0);
2848
+ rb_ary_push(ret, INT2FIX(c));
2849
+ }
2850
+ break;
2851
+
2852
+ case 3:
2853
+ for (i = 0; i < cinfo->actual_number_of_colors; i++) {
2854
+ c = (map[0][i] << 16) | (map[1][i] << 8) | (map[2][i] << 0);
2855
+
2856
+ rb_ary_push(ret, INT2FIX(c));
2857
+ }
1937
2858
  break;
2859
+
2860
+ default:
2861
+ RUNTIME_ERROR("this number of components is not implemented yet");
1938
2862
  }
1939
2863
 
1940
- jpeg_create_decompress(&ptr->cinfo);
2864
+ return ret;
2865
+ }
1941
2866
 
1942
- ptr->cinfo.err = jpeg_std_error(&ptr->err_mgr.jerr);
1943
- ptr->err_mgr.jerr.output_message = decode_output_message;
1944
- ptr->err_mgr.jerr.emit_message = decode_emit_message;
1945
- ptr->err_mgr.jerr.error_exit = decode_error_exit;
2867
+ static VALUE
2868
+ rb_meta_exif_tags(VALUE self)
2869
+ {
2870
+ return rb_ivar_get(self, id_exif_tags);
2871
+ }
1946
2872
 
1947
- ptr->cinfo.raw_data_out = FALSE;
1948
- ptr->cinfo.dct_method = JDCT_FLOAT;
2873
+ static VALUE
2874
+ create_meta(jpeg_decode_t* ptr)
2875
+ {
2876
+ VALUE ret;
2877
+ struct jpeg_decompress_struct* cinfo;
2878
+ int width;
2879
+ int height;
2880
+ int stride;
2881
+
2882
+ ret = rb_obj_alloc(meta_klass);
2883
+ cinfo = &ptr->cinfo;
2884
+
2885
+ if (TEST_FLAG(ptr, F_APPLY_ORIENTATION) && (ptr->orientation.value & 4)) {
2886
+ width = cinfo->output_height;
2887
+ height = cinfo->output_width;
2888
+ } else {
2889
+ width = cinfo->output_width;
2890
+ height = cinfo->output_height;
2891
+ }
2892
+
2893
+ stride = cinfo->output_width * cinfo->output_components;
2894
+
2895
+ rb_ivar_set(ret, id_width, INT2FIX(width));
2896
+ rb_ivar_set(ret, id_stride, INT2FIX(stride));
2897
+ rb_ivar_set(ret, id_height, INT2FIX(height));
2898
+
2899
+ rb_ivar_set(ret, id_orig_cs, get_colorspace_str(cinfo->jpeg_color_space));
2900
+
2901
+ if (ptr->format == FMT_YVU) {
2902
+ rb_ivar_set(ret, id_out_cs, rb_str_new_cstr("YCrCb"));
2903
+ } else {
2904
+ rb_ivar_set(ret, id_out_cs, get_colorspace_str(cinfo->out_color_space));
2905
+ }
2906
+
2907
+ if (TEST_FLAG_ALL(ptr, F_DITHER | F_EXPAND_COLORMAP)) {
2908
+ rb_ivar_set(ret, id_ncompo, INT2FIX(cinfo->out_color_components));
2909
+ } else {
2910
+ rb_ivar_set(ret, id_ncompo, INT2FIX(cinfo->output_components));
2911
+ }
2912
+
2913
+ if (TEST_FLAG(ptr, F_PARSE_EXIF)) {
2914
+ rb_ivar_set(ret, id_exif_tags, create_exif_tags_hash(ptr));
2915
+ rb_define_singleton_method(ret, "exif_tags", rb_meta_exif_tags, 0);
2916
+ rb_define_singleton_method(ret, "exif", rb_meta_exif_tags, 0);
2917
+ }
2918
+
2919
+ if (TEST_FLAG(ptr, F_DITHER)) {
2920
+ rb_ivar_set(ret, id_colormap, create_colormap(ptr));
2921
+ }
2922
+
2923
+ return ret;
2924
+ }
2925
+
2926
+ static VALUE
2927
+ do_read_header(VALUE _ptr)
2928
+ {
2929
+ VALUE ret;
2930
+ jpeg_decode_t* ptr;
2931
+ uint8_t* data;
2932
+ size_t size;
2933
+
2934
+ /*
2935
+ * initialize
2936
+ */
2937
+ ret = Qnil;
2938
+ ptr = (jpeg_decode_t*)_ptr;
2939
+ data = (uint8_t*)RSTRING_PTR(ptr->data);
2940
+ size = RSTRING_LEN(ptr->data);
2941
+
2942
+ /*
2943
+ * process body
2944
+ */
2945
+ ptr->cinfo.raw_data_out = FALSE;
2946
+ ptr->cinfo.dct_method = JDCT_FLOAT;
1949
2947
 
1950
2948
  if (setjmp(ptr->err_mgr.jmpbuf)) {
1951
- jpeg_destroy_decompress(&ptr->cinfo);
2949
+ /*
2950
+ * when error occurred
2951
+ */
1952
2952
  rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
2953
+
1953
2954
  } else {
1954
- jpeg_mem_src(&ptr->cinfo, jpg, jpg_sz);
2955
+ /*
2956
+ * normal path
2957
+ */
2958
+ jpeg_mem_src(&ptr->cinfo, data, size);
1955
2959
 
1956
- if (ptr->parse_exif) {
2960
+ if (TEST_FLAG(ptr, F_PARSE_EXIF | F_APPLY_ORIENTATION)) {
1957
2961
  jpeg_save_markers(&ptr->cinfo, JPEG_APP1, 0xFFFF);
1958
2962
  }
1959
2963
 
1960
2964
  jpeg_read_header(&ptr->cinfo, TRUE);
1961
2965
  jpeg_calc_output_dimensions(&ptr->cinfo);
1962
2966
 
1963
- ret = create_meta(ptr);
2967
+ if (TEST_FLAG(ptr, F_APPLY_ORIENTATION)) {
2968
+ pick_exif_orientation(ptr);
2969
+ }
1964
2970
 
1965
- jpeg_destroy_decompress(&ptr->cinfo);
2971
+ ret = create_meta(ptr);
1966
2972
  }
1967
2973
 
1968
2974
  return ret;
1969
2975
  }
1970
2976
 
2977
+ /**
2978
+ * read meta data
2979
+ *
2980
+ * @overload read_header(jpeg)
2981
+ *
2982
+ * @param jpeg [String] input data.
2983
+ *
2984
+ * @return [JPEG::Meta] metadata.
2985
+ */
1971
2986
  static VALUE
1972
2987
  rb_decoder_read_header(VALUE self, VALUE data)
1973
2988
  {
1974
2989
  VALUE ret;
1975
2990
  jpeg_decode_t* ptr;
2991
+ int state;
1976
2992
 
1977
2993
  /*
1978
2994
  * initialize
1979
2995
  */
1980
- Data_Get_Struct(self, jpeg_decode_t, ptr);
2996
+ ret = Qnil;
2997
+ state = 0;
2998
+
2999
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
1981
3000
 
1982
3001
  /*
1983
3002
  * argument check
1984
3003
  */
1985
3004
  Check_Type(data, T_STRING);
1986
3005
 
3006
+ /*
3007
+ * prepare
3008
+ */
3009
+ SET_DATA(ptr, data);
3010
+
1987
3011
  /*
1988
3012
  * do encode
1989
3013
  */
1990
- ret = do_read_header(ptr, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
3014
+ ret = rb_protect(do_read_header, (VALUE)ptr, &state);
3015
+
3016
+ /*
3017
+ * post process
3018
+ */
3019
+ CLR_DATA(ptr);
3020
+
3021
+ if (state != 0) rb_jump_tag(state);
1991
3022
 
1992
3023
  return ret;
1993
3024
  }
@@ -2018,7 +3049,7 @@ expand_colormap(struct jpeg_decompress_struct* cinfo, uint8_t* src)
2018
3049
  */
2019
3050
 
2020
3051
  VALUE ret;
2021
- int i;
3052
+ volatile int i; // volatileを外すとaarch64のgcc6でクラッシュする場合がある
2022
3053
  int n;
2023
3054
  uint8_t* dst;
2024
3055
  JSAMPARRAY map;
@@ -2035,6 +3066,15 @@ expand_colormap(struct jpeg_decompress_struct* cinfo, uint8_t* src)
2035
3066
  }
2036
3067
  break;
2037
3068
 
3069
+ case 2:
3070
+ for (i = 0; i < n; i++) {
3071
+ dst[0] = map[0][src[i]];
3072
+ dst[1] = map[1][src[i]];
3073
+
3074
+ dst += 2;
3075
+ }
3076
+ break;
3077
+
2038
3078
  case 3:
2039
3079
  for (i = 0; i < n; i++) {
2040
3080
  dst[0] = map[0][src[i]];
@@ -2046,7 +3086,7 @@ expand_colormap(struct jpeg_decompress_struct* cinfo, uint8_t* src)
2046
3086
  break;
2047
3087
 
2048
3088
  default:
2049
- RUNTIME_ERROR("Really?");
3089
+ RUNTIME_ERROR("this number of components is not implemented yet");
2050
3090
  }
2051
3091
 
2052
3092
  rb_str_set_len(ret, n * cinfo->out_color_components);
@@ -2067,10 +3107,417 @@ swap_cbcr(uint8_t* p, size_t size)
2067
3107
  }
2068
3108
  }
2069
3109
 
3110
+ static void
3111
+ do_transpose8(uint8_t* img, int wd, int ht, void* dst)
3112
+ {
3113
+ int x;
3114
+ int y;
3115
+
3116
+ uint8_t* sp;
3117
+ uint8_t* dp;
3118
+
3119
+ sp = (uint8_t*)img;
3120
+
3121
+ for (y = 0; y < ht; y++) {
3122
+ dp = (uint8_t*)dst + y;
3123
+
3124
+ for (x = 0; x < wd; x++) {
3125
+ *dp = *sp;
3126
+
3127
+ sp++;
3128
+ dp += ht;
3129
+ }
3130
+ }
3131
+ }
3132
+
3133
+ static void
3134
+ do_transpose16(void* img, int wd, int ht, void* dst)
3135
+ {
3136
+ int x;
3137
+ int y;
3138
+
3139
+ uint16_t* sp;
3140
+ uint16_t* dp;
3141
+
3142
+ sp = (uint16_t*)img;
3143
+
3144
+ for (y = 0; y < ht; y++) {
3145
+ dp = (uint16_t*)dst + y;
3146
+
3147
+ for (x = 0; x < wd; x++) {
3148
+ *dp = *sp;
3149
+
3150
+ sp++;
3151
+ dp += ht;
3152
+ }
3153
+ }
3154
+ }
3155
+
3156
+ static void
3157
+ do_transpose24(void* img, int wd, int ht, void* dst)
3158
+ {
3159
+ int x;
3160
+ int y;
3161
+ int st;
3162
+
3163
+ uint8_t* sp;
3164
+ uint8_t* dp;
3165
+
3166
+ sp = (uint8_t*)img;
3167
+ st = ht * 3;
3168
+
3169
+ for (y = 0; y < ht; y++) {
3170
+ dp = (uint8_t*)dst + (y * 3);
3171
+
3172
+ for (x = 0; x < wd; x++) {
3173
+ dp[0] = sp[0];
3174
+ dp[1] = sp[1];
3175
+ dp[2] = sp[2];
3176
+
3177
+ sp += 3;
3178
+ dp += st;
3179
+ }
3180
+ }
3181
+ }
3182
+
3183
+ static void
3184
+ do_transpose32(void* img, int wd, int ht, void* dst)
3185
+ {
3186
+ int x;
3187
+ int y;
3188
+
3189
+ uint32_t* sp;
3190
+ uint32_t* dp;
3191
+
3192
+ sp = (uint32_t*)img;
3193
+
3194
+ for (y = 0; y < ht; y++) {
3195
+ dp = (uint32_t*)dst + y;
3196
+
3197
+ for (x = 0; x < wd; x++) {
3198
+ *dp = *sp;
3199
+
3200
+ sp++;
3201
+ dp += ht;
3202
+ }
3203
+ }
3204
+ }
3205
+
3206
+ static void
3207
+ do_transpose(void* img, int wd, int ht, int nc, void* dst)
3208
+ {
3209
+ switch (nc) {
3210
+ case 1:
3211
+ do_transpose8(img, wd, ht, dst);
3212
+ break;
3213
+
3214
+ case 2:
3215
+ do_transpose16(img, wd, ht, dst);
3216
+ break;
3217
+
3218
+ case 3:
3219
+ do_transpose24(img, wd, ht, dst);
3220
+ break;
3221
+
3222
+ case 4:
3223
+ do_transpose32(img, wd, ht, dst);
3224
+ break;
3225
+ }
3226
+ }
3227
+
3228
+ static void
3229
+ do_upside_down8(void* img, int wd, int ht)
3230
+ {
3231
+ uint8_t* sp;
3232
+ uint8_t* dp;
3233
+
3234
+ sp = (uint8_t*)img;
3235
+ dp = (uint8_t*)img + ((wd * ht) - 1);
3236
+
3237
+ while (sp < dp) {
3238
+ SWAP(*sp, *dp, uint8_t);
3239
+
3240
+ sp++;
3241
+ dp--;
3242
+ }
3243
+ }
3244
+
3245
+ static void
3246
+ do_upside_down16(void* img, int wd, int ht)
3247
+ {
3248
+ uint16_t* sp;
3249
+ uint16_t* dp;
3250
+
3251
+ sp = (uint16_t*)img;
3252
+ dp = (uint16_t*)img + ((wd * ht) - 1);
3253
+
3254
+ while (sp < dp) {
3255
+ SWAP(*sp, *dp, uint8_t);
3256
+
3257
+ sp++;
3258
+ dp--;
3259
+ }
3260
+ }
3261
+
3262
+ static void
3263
+ do_upside_down24(void* img, int wd, int ht)
3264
+ {
3265
+ uint8_t* sp;
3266
+ uint8_t* dp;
3267
+
3268
+ sp = (uint8_t*)img;
3269
+ dp = (uint8_t*)img + ((wd * ht * 3) - 3);
3270
+
3271
+ while (sp < dp) {
3272
+ SWAP(sp[0], dp[0], uint8_t);
3273
+ SWAP(sp[1], dp[1], uint8_t);
3274
+ SWAP(sp[2], dp[2], uint8_t);
3275
+
3276
+ sp += 3;
3277
+ dp -= 3;
3278
+ }
3279
+ }
3280
+
3281
+ static void
3282
+ do_upside_down32(void* img, int wd, int ht)
3283
+ {
3284
+ uint32_t* sp;
3285
+ uint32_t* dp;
3286
+
3287
+ sp = (uint32_t*)img;
3288
+ dp = (uint32_t*)img + ((wd * ht) - 1);
3289
+
3290
+ ht /= 2;
3291
+
3292
+ while (sp < dp) {
3293
+ SWAP(*sp, *dp, uint32_t);
3294
+
3295
+ sp++;
3296
+ dp--;
3297
+ }
3298
+ }
3299
+
3300
+ static void
3301
+ do_upside_down(void* img, int wd, int ht, int nc)
3302
+ {
3303
+ switch (nc) {
3304
+ case 1:
3305
+ do_upside_down8(img, wd, ht);
3306
+ break;
3307
+
3308
+ case 2:
3309
+ do_upside_down16(img, wd, ht);
3310
+ break;
3311
+
3312
+ case 3:
3313
+ do_upside_down24(img, wd, ht);
3314
+ break;
3315
+
3316
+ case 4:
3317
+ do_upside_down32(img, wd, ht);
3318
+ break;
3319
+ }
3320
+ }
3321
+
3322
+ static void
3323
+ do_flip_horizon8(void* img, int wd, int ht)
3324
+ {
3325
+ int y;
3326
+ int st;
3327
+
3328
+ uint8_t* sp;
3329
+ uint8_t* dp;
3330
+
3331
+ st = wd;
3332
+ wd /= 2;
3333
+
3334
+ sp = (uint8_t*)img;
3335
+ dp = (uint8_t*)img + (st - 1);
3336
+
3337
+ for (y = 0; y < ht; y++) {
3338
+ while (sp < dp) {
3339
+ SWAP(*sp, *dp, uint8_t);
3340
+
3341
+ sp++;
3342
+ dp--;
3343
+ }
3344
+
3345
+ sp = sp - wd + st;
3346
+ dp = sp + (st - 1);
3347
+ }
3348
+ }
3349
+
3350
+ static void
3351
+ do_flip_horizon16(void* img, int wd, int ht)
3352
+ {
3353
+ int y;
3354
+ int st;
3355
+
3356
+ uint16_t* sp;
3357
+ uint16_t* dp;
3358
+
3359
+ st = wd;
3360
+ wd /= 2;
3361
+
3362
+ sp = (uint16_t*)img;
3363
+ dp = (uint16_t*)img + (st - 1);
3364
+
3365
+ for (y = 0; y < ht; y++) {
3366
+ while (sp < dp) {
3367
+ SWAP(*sp, *dp, uint16_t);
3368
+
3369
+ sp++;
3370
+ dp--;
3371
+ }
3372
+
3373
+ sp = sp - wd + st;
3374
+ dp = sp + (st - 1);
3375
+ }
3376
+ }
3377
+
3378
+ static void
3379
+ do_flip_horizon24(void* img, int wd, int ht)
3380
+ {
3381
+ int y;
3382
+ int st;
3383
+
3384
+ uint8_t* sp;
3385
+ uint8_t* dp;
3386
+
3387
+ st = wd * 3;
3388
+ wd /= 2;
3389
+
3390
+ sp = (uint8_t*)img;
3391
+ dp = (uint8_t*)img + (st - 3);
3392
+
3393
+ for (y = 0; y < ht; y++) {
3394
+ while (sp < dp) {
3395
+ SWAP(sp[0], dp[0], uint8_t);
3396
+ SWAP(sp[1], dp[1], uint8_t);
3397
+ SWAP(sp[2], dp[2], uint8_t);
3398
+
3399
+ sp += 3;
3400
+ dp -= 3;
3401
+ }
3402
+
3403
+ sp = (sp - (wd * 3)) + st;
3404
+ dp = sp + (st - 3);
3405
+ }
3406
+ }
3407
+
3408
+ static void
3409
+ do_flip_horizon32(void* img, int wd, int ht)
3410
+ {
3411
+ int y;
3412
+ int st;
3413
+
3414
+ uint32_t* sp;
3415
+ uint32_t* dp;
3416
+
3417
+ st = wd;
3418
+ wd /= 2;
3419
+
3420
+ sp = (uint32_t*)img;
3421
+ dp = (uint32_t*)img + (st - 1);
3422
+
3423
+ for (y = 0; y < ht; y++) {
3424
+ while (sp < dp) {
3425
+ SWAP(*sp, *dp, uint32_t);
3426
+
3427
+ sp++;
3428
+ dp--;
3429
+ }
3430
+
3431
+ sp = sp - wd + st;
3432
+ dp = sp + (st - 1);
3433
+ }
3434
+ }
3435
+
3436
+ static void
3437
+ do_flip_horizon(void* img, int wd, int ht, int nc)
3438
+ {
3439
+ switch (nc) {
3440
+ case 1:
3441
+ do_flip_horizon8(img, wd, ht);
3442
+ break;
3443
+
3444
+ case 2:
3445
+ do_flip_horizon16(img, wd, ht);
3446
+ break;
3447
+
3448
+ case 3:
3449
+ do_flip_horizon24(img, wd, ht);
3450
+ break;
3451
+
3452
+ case 4:
3453
+ do_flip_horizon32(img, wd, ht);
3454
+ break;
3455
+ }
3456
+ }
3457
+
3458
+ static VALUE
3459
+ shift_orientation_buffer(jpeg_decode_t* ptr, VALUE img)
3460
+ {
3461
+ VALUE ret;
3462
+ int len;
3463
+
3464
+ ret = ptr->orientation.buf;
3465
+ len = RSTRING_LEN(img);
3466
+
3467
+ if (ret == Qnil || RSTRING_LEN(ret) != len) {
3468
+ ret = rb_str_buf_new(len);
3469
+ rb_str_set_len(ret, len);
3470
+ }
3471
+
3472
+ ptr->orientation.buf = img;
3473
+
3474
+ return ret;
3475
+ }
3476
+
3477
+ static VALUE
3478
+ apply_orientation(jpeg_decode_t* ptr, VALUE img)
3479
+ {
3480
+ struct jpeg_decompress_struct* cinfo;
3481
+ int wd;
3482
+ int ht;
3483
+ int nc;
3484
+ VALUE tmp;
3485
+
3486
+ cinfo = &ptr->cinfo;
3487
+ wd = cinfo->output_width;
3488
+ ht = cinfo->output_height;
3489
+ nc = cinfo->output_components;
3490
+
3491
+ if (ptr->orientation.value & 4) {
3492
+ /* 転置は交換アルゴリズムでは実装できないので新規バッファを
3493
+ 用意する */
3494
+ tmp = img;
3495
+ img = shift_orientation_buffer(ptr, tmp);
3496
+ SWAP(wd, ht, int);
3497
+
3498
+ do_transpose(RSTRING_PTR(tmp), ht, wd, nc, RSTRING_PTR(img));
3499
+ }
3500
+
3501
+ if (ptr->orientation.value & 2) {
3502
+ do_upside_down(RSTRING_PTR(img), wd, ht, nc);
3503
+ }
3504
+
3505
+ if (ptr->orientation.value & 1) {
3506
+ do_flip_horizon(RSTRING_PTR(img), wd, ht, nc);
3507
+ }
3508
+
3509
+ return img;
3510
+ }
3511
+
2070
3512
  static VALUE
2071
- do_decode(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
3513
+ do_decode(VALUE _ptr)
2072
3514
  {
2073
3515
  VALUE ret;
3516
+
3517
+ jpeg_decode_t* ptr;
3518
+ uint8_t* data;
3519
+ size_t size;
3520
+
2074
3521
  struct jpeg_decompress_struct* cinfo;
2075
3522
  JSAMPARRAY array;
2076
3523
 
@@ -2080,118 +3527,149 @@ do_decode(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
2080
3527
  int i;
2081
3528
  int j;
2082
3529
 
2083
- ret = Qundef; // warning対策
3530
+ /*
3531
+ * initialize
3532
+ */
3533
+ ret = Qnil; // warning対策
3534
+ ptr = (jpeg_decode_t*)_ptr;
3535
+ data = (uint8_t*)RSTRING_PTR(ptr->data);
3536
+ size = RSTRING_LEN(ptr->data);
2084
3537
  cinfo = &ptr->cinfo;
2085
- array = ALLOC_ARRAY();
2086
-
2087
- switch (ptr->format) {
2088
- case FMT_YUV422:
2089
- case FMT_RGB565:
2090
- RUNTIME_ERROR( "Not implement");
2091
- break;
3538
+ array = ptr->array;
2092
3539
 
2093
- case FMT_GRAYSCALE:
2094
- case FMT_YUV:
2095
- case FMT_RGB:
2096
- case FMT_BGR:
2097
- case FMT_YVU:
2098
- case FMT_RGB32:
2099
- case FMT_BGR32:
2100
- jpeg_create_decompress(cinfo);
3540
+ /*
3541
+ * do decode
3542
+ */
3543
+ if (setjmp(ptr->err_mgr.jmpbuf)) {
3544
+ /*
3545
+ * when error occurred
3546
+ */
3547
+ jpeg_abort_decompress(&ptr->cinfo);
3548
+ rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
2101
3549
 
2102
- cinfo->err = jpeg_std_error(&ptr->err_mgr.jerr);
2103
- ptr->err_mgr.jerr.output_message = decode_output_message;
2104
- ptr->err_mgr.jerr.emit_message = decode_emit_message;
2105
- ptr->err_mgr.jerr.error_exit = decode_error_exit;
3550
+ } else {
3551
+ /*
3552
+ * initialize
3553
+ */
3554
+ jpeg_mem_src(cinfo, data, size);
2106
3555
 
2107
- if (setjmp(ptr->err_mgr.jmpbuf)) {
2108
- jpeg_abort_decompress(cinfo);
2109
- jpeg_destroy_decompress(&ptr->cinfo);
3556
+ if (TEST_FLAG(ptr, F_PARSE_EXIF | F_APPLY_ORIENTATION)) {
3557
+ jpeg_save_markers(&ptr->cinfo, JPEG_APP1, 0xFFFF);
3558
+ }
2110
3559
 
2111
- free(array);
2112
- rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
3560
+ jpeg_read_header(cinfo, TRUE);
3561
+ jpeg_calc_output_dimensions(cinfo);
2113
3562
 
2114
- } else {
2115
- jpeg_mem_src(cinfo, jpg, jpg_sz);
2116
- jpeg_read_header(cinfo, TRUE);
2117
-
2118
- cinfo->raw_data_out = FALSE;
2119
- cinfo->dct_method = ptr->dct_method;
2120
-
2121
- cinfo->out_color_space = ptr->out_color_space;
2122
- cinfo->out_color_components = ptr->out_color_components;
2123
- cinfo->scale_num = ptr->scale_num;
2124
- cinfo->scale_denom = ptr->scale_denom;
2125
- cinfo->output_gamma = ptr->output_gamma;
2126
- cinfo->do_fancy_upsampling = ptr->do_fancy_upsampling;
2127
- cinfo->do_block_smoothing = ptr->do_block_smoothing;
2128
- cinfo->quantize_colors = ptr->quantize_colors;
2129
- cinfo->dither_mode = ptr->dither_mode;
2130
- cinfo->two_pass_quantize = ptr->two_pass_quantize;
2131
- cinfo->desired_number_of_colors = ptr->desired_number_of_colors;
2132
- cinfo->enable_1pass_quant = ptr->enable_1pass_quant;
2133
- cinfo->enable_external_quant = ptr->enable_external_quant;
2134
- cinfo->enable_2pass_quant = ptr->enable_2pass_quant;
2135
-
2136
- jpeg_calc_output_dimensions(cinfo);
2137
- jpeg_start_decompress(cinfo);
2138
-
2139
- stride = cinfo->output_components * cinfo->output_width;
2140
- raw_sz = stride * cinfo->output_height;
2141
- ret = rb_str_buf_new(raw_sz);
2142
- raw = (uint8_t*)RSTRING_PTR(ret);
2143
-
2144
-
2145
- while (cinfo->output_scanline < cinfo->output_height) {
2146
- for (i = 0, j = cinfo->output_scanline; i < UNIT_LINES; i++, j++) {
2147
- array[i] = raw + (j * stride);
2148
- }
3563
+ /*
3564
+ * configuration
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;
2149
3583
 
2150
- jpeg_read_scanlines(cinfo, array, UNIT_LINES);
2151
- }
3584
+ /*
3585
+ * decode process
3586
+ */
3587
+ jpeg_start_decompress(cinfo);
2152
3588
 
2153
- if (ptr->expand_colormap && IS_COLORMAPPED( cinfo)) {
2154
- ret = expand_colormap(cinfo, raw);
2155
- } else {
2156
- rb_str_set_len( ret, raw_sz);
3589
+ stride = cinfo->output_components * cinfo->output_width;
3590
+ raw_sz = stride * cinfo->output_height;
3591
+ ret = rb_str_buf_new(raw_sz);
3592
+ raw = (uint8_t*)RSTRING_PTR(ret);
3593
+
3594
+ while (cinfo->output_scanline < cinfo->output_height) {
3595
+ for (i = 0, j = cinfo->output_scanline; i < UNIT_LINES; i++, j++) {
3596
+ array[i] = raw + (j * stride);
2157
3597
  }
2158
3598
 
2159
- if (ptr->need_meta) add_meta(ret, ptr);
2160
- if (ptr->format == FMT_YVU) swap_cbcr(raw, raw_sz);
3599
+ jpeg_read_scanlines(cinfo, array, UNIT_LINES);
3600
+ }
3601
+
3602
+ jpeg_finish_decompress(&ptr->cinfo);
2161
3603
 
2162
- jpeg_finish_decompress(cinfo);
2163
- jpeg_destroy_decompress(&ptr->cinfo);
3604
+ /*
3605
+ * build return data
3606
+ */
3607
+ if (TEST_FLAG(ptr, F_EXPAND_COLORMAP) && IS_COLORMAPPED(cinfo)) {
3608
+ ret = expand_colormap(cinfo, raw);
3609
+ } else {
3610
+ rb_str_set_len(ret, raw_sz);
2164
3611
  }
2165
- break;
2166
- }
2167
3612
 
2168
- free(array);
3613
+ if (ptr->format == FMT_YVU) swap_cbcr(raw, raw_sz);
3614
+
3615
+ if (TEST_FLAG(ptr, F_APPLY_ORIENTATION)) {
3616
+ pick_exif_orientation(ptr);
3617
+ ret = apply_orientation(ptr, ret);
3618
+ }
3619
+
3620
+ if (TEST_FLAG(ptr, F_NEED_META)) add_meta(ret, ptr);
3621
+ }
2169
3622
 
2170
3623
  return ret;
2171
3624
  }
2172
3625
 
3626
+ /**
3627
+ * decode JPEG data
3628
+ *
3629
+ * @overload decode(jpeg)
3630
+ *
3631
+ * @param jpeg [String] JPEG data to decode.
3632
+ *
3633
+ * @return [String] decoded raw image data.
3634
+ */
2173
3635
  static VALUE
2174
3636
  rb_decoder_decode(VALUE self, VALUE data)
2175
3637
  {
2176
- VALUE ret;
2177
- jpeg_decode_t* ptr;
3638
+ VALUE ret;
3639
+ jpeg_decode_t* ptr;
3640
+ int state;
2178
3641
 
2179
- /*
2180
- * initialize
2181
- */
2182
- Data_Get_Struct(self, jpeg_decode_t, ptr);
3642
+ /*
3643
+ * initialize
3644
+ */
3645
+ ret = Qnil;
3646
+ state = 0;
2183
3647
 
2184
- /*
2185
- * argument check
2186
- */
2187
- Check_Type(data, T_STRING);
3648
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
2188
3649
 
2189
- /*
2190
- * do encode
2191
- */
2192
- ret = do_decode(ptr, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
3650
+ /*
3651
+ * argument check
3652
+ */
3653
+ Check_Type(data, T_STRING);
3654
+
3655
+ /*
3656
+ * prepare
3657
+ */
3658
+ SET_DATA(ptr, data);
2193
3659
 
2194
- return ret;
3660
+ /*
3661
+ * do decode
3662
+ */
3663
+ ret = rb_protect(do_decode, (VALUE)ptr, &state);
3664
+
3665
+ /*
3666
+ * post process
3667
+ */
3668
+ CLR_DATA(ptr);
3669
+
3670
+ if (state != 0) rb_jump_tag(state);
3671
+
3672
+ return ret;
2195
3673
  }
2196
3674
 
2197
3675
  static VALUE
@@ -2201,28 +3679,19 @@ rb_test_image(VALUE self, VALUE data)
2201
3679
  struct jpeg_decompress_struct cinfo;
2202
3680
  ext_error_t err_mgr;
2203
3681
 
2204
- jpeg_create_decompress(&cinfo);
2205
-
2206
- cinfo.err = jpeg_std_error(&err_mgr.jerr);
2207
-
2208
- err_mgr.jerr.output_message = decode_output_message;
2209
- err_mgr.jerr.emit_message = decode_emit_message;
2210
- err_mgr.jerr.error_exit = decode_error_exit;
2211
-
2212
- cinfo.raw_data_out = FALSE;
2213
- cinfo.dct_method = JDCT_FLOAT;
3682
+ cinfo.raw_data_out = FALSE;
3683
+ cinfo.dct_method = JDCT_FLOAT;
2214
3684
 
2215
3685
  if (setjmp(err_mgr.jmpbuf)) {
2216
- ret = Qtrue;
2217
- } else {
2218
3686
  ret = Qfalse;
2219
3687
 
3688
+ } else {
2220
3689
  jpeg_mem_src(&cinfo, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
2221
3690
  jpeg_read_header(&cinfo, TRUE);
2222
3691
  jpeg_calc_output_dimensions(&cinfo);
2223
- }
2224
3692
 
2225
- jpeg_destroy_decompress(&cinfo);
3693
+ ret = Qtrue;
3694
+ }
2226
3695
 
2227
3696
  return ret;
2228
3697
  }
@@ -2256,11 +3725,12 @@ Init_jpeg()
2256
3725
 
2257
3726
  meta_klass = rb_define_class_under(module, "Meta", rb_cObject);
2258
3727
  rb_define_attr(meta_klass, "width", 1, 0);
3728
+ rb_define_attr(meta_klass, "stride", 1, 0);
2259
3729
  rb_define_attr(meta_klass, "height", 1, 0);
2260
3730
  rb_define_attr(meta_klass, "original_colorspace", 1, 0);
2261
3731
  rb_define_attr(meta_klass, "output_colorspace", 1, 0);
2262
3732
  rb_define_attr(meta_klass, "num_components", 1, 0);
2263
- rb_define_attr(meta_klass, "exif", 1, 0);
3733
+ rb_define_attr(meta_klass, "colormap", 1, 0);
2264
3734
 
2265
3735
  decerr_klass = rb_define_class_under(module,
2266
3736
  "DecodeError", rb_eRuntimeError);
@@ -2278,11 +3748,13 @@ Init_jpeg()
2278
3748
  decoder_opts_ids[i] = rb_intern_const(decoder_opts_keys[i]);
2279
3749
  }
2280
3750
 
2281
- id_meta = rb_intern_const("@meta");
2282
- id_width = rb_intern_const("@width");
2283
- id_height = rb_intern_const("@height");
2284
- id_orig_cs = rb_intern_const("@original_colorspace");
2285
- id_out_cs = rb_intern_const("@output_colorspace");
2286
- id_ncompo = rb_intern_const("@num_components");
2287
- id_exif = rb_intern_const("@exif");
3751
+ id_meta = rb_intern_const("@meta");
3752
+ id_width = rb_intern_const("@width");
3753
+ id_stride = rb_intern_const("@stride");
3754
+ id_height = rb_intern_const("@height");
3755
+ id_orig_cs = rb_intern_const("@original_colorspace");
3756
+ id_out_cs = rb_intern_const("@output_colorspace");
3757
+ id_ncompo = rb_intern_const("@num_components");
3758
+ id_exif_tags = rb_intern_const("@exif_tags");
3759
+ id_colormap = rb_intern_const("@colormap");
2288
3760
  }