libjpeg-ruby 0.6.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fbc3ef237e2de37ab66acc9d4688f2e9c40eb400fecc806aaafa3fdb6cff2c92
4
- data.tar.gz: 2c112043c71e0c4f04760cf25c708e9bd6e2098eaed5b2a5fc588785cc802743
3
+ metadata.gz: 8bd107f31f10ef4251f056cfc06e2c16082b1d5e42b98a6b810385a171f92991
4
+ data.tar.gz: eef3261d6619e567a5b063ccd5c72468ab975b4fc80d693ebe49bc3531c76139
5
5
  SHA512:
6
- metadata.gz: a68965a542eee203bca65df1e88ba0dddf6a39a9dd62499e4f1ddb56813f879b47626ffc6bcc5dd14bb54fb83a095161ac340d7506a3cf475c370adf925f118f
7
- data.tar.gz: 3083edd573718ff0d5b5ed6d25dc00efd90c64235c70e10436205a13822b54f967335d1c128eac24985791f63e4fc0f7a58634473a0291fa108a0b0bc55bcf74
6
+ metadata.gz: c8d4ce1bd5e96f70f26cc167282f1761c5085c0eb901df9c5b948d2ce6bd9aac8cb3006e4d17a28bbed1a7d6ef597dcbbb028529075839aca992ce2e5dd5e55a
7
+ data.tar.gz: 4e4f0fc6e9a9ec579e50ad00f6f5558caf1753f689e1a5aea8fe7fe11bb188863cbd77f1706591a14532d77be92316b2eb16b912a835ac80bf18ae74952deb57
@@ -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,6 +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_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. |
53
55
 
54
56
  #### supported output format
55
57
  RGB RGB24 YUV422 YUYV RGB565 YUV444 YCbCr BGR BGR24 RGBX RGB32 BGRX BGR32
@@ -74,4 +76,5 @@ IO.binwrite("test.jpg", enc << IO.binread("test.raw"))
74
76
  | :quality | Integer | encode quality (0-100) |
75
77
  | :scale | Rational or Float | |
76
78
  | :dct_method | String or Symbol | T.B.D |
79
+ | :orientation | Integer | Specify Exif orientation value (1-8). |
77
80
 
@@ -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")
@@ -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,46 +12,73 @@
22
12
  #include <jpeglib.h>
23
13
 
24
14
  #include "ruby.h"
15
+ #include "ruby/version.h"
16
+ #include "ruby/encoding.h"
25
17
 
26
- #define UNIT_LINES 10
18
+ #define UNIT_LINES 10
27
19
 
28
20
  #ifdef DEFAULT_QUALITY
29
21
  #undef DEFAULT_QUALITY
30
22
  #endif /* defined(DEFAULT_QUALITY) */
31
23
 
32
- #define DEFAULT_QUALITY 75
33
- #define DEFAULT_INPUT_COLOR_SPACE JCS_YCbCr
34
- #define DEFAULT_INPUT_COMPONENTS 2
35
-
36
- #define FMT_YUV422 1
37
- #define FMT_RGB565 2
38
- #define FMT_GRAYSCALE 3
39
- #define FMT_YUV 4
40
- #define FMT_RGB 5
41
- #define FMT_BGR 6
42
- #define FMT_RGB32 7
43
- #define FMT_BGR32 8
44
-
45
- #define FMT_YVU 20 /* original extend */
46
-
47
- #define N(x) (sizeof(x)/sizeof(*x))
48
-
49
- #define RUNTIME_ERROR(msg) rb_raise(rb_eRuntimeError, (msg))
50
- #define ARGUMENT_ERROR(msg) rb_raise(rb_eArgError, (msg))
51
-
52
- #define IS_COLORMAPPED(ci) (((ci)->actual_number_of_colors > 0) &&\
53
- ((ci)->colormap != NULL) && \
54
- ((ci)->output_components == 1) && \
55
- (((ci)->out_color_components == 1) || \
56
- ((ci)->out_color_components == 3)))
24
+ #define DEFAULT_QUALITY 75
25
+ #define DEFAULT_INPUT_COLOR_SPACE JCS_YCbCr
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
+ #define F_START 0x00020000
37
+
38
+ #define SET_FLAG(ptr, msk) ((ptr)->flags |= (msk))
39
+ #define CLR_FLAG(ptr, msk) ((ptr)->flags &= ~(msk))
40
+ #define TEST_FLAG(ptr, msk) ((ptr)->flags & (msk))
41
+ #define TEST_FLAG_ALL(ptr, msk) (((ptr)->flags & (msk)) == (msk))
42
+
43
+ #define SET_DATA(ptr, dat) ((ptr)->data = (dat))
44
+ #define CLR_DATA(ptr) ((ptr)->data = Qnil)
45
+
46
+ #define FMT_YUV422 1
47
+ #define FMT_RGB565 2
48
+ #define FMT_GRAYSCALE 3
49
+ #define FMT_YUV 4
50
+ #define FMT_RGB 5
51
+ #define FMT_BGR 6
52
+ #define FMT_RGB32 7
53
+ #define FMT_BGR32 8
54
+
55
+ #define FMT_YVU 20 /* original extend */
56
+
57
+ #define JPEG_APP1 0xe1 /* Exif marker */
58
+
59
+ #define N(x) (sizeof(x)/sizeof(*x))
60
+ #define SWAP(a,b,t) \
61
+ do {t c; c = (a); (a) = (b); (b) = c;} while (0)
62
+
63
+ #define RUNTIME_ERROR(msg) rb_raise(rb_eRuntimeError, (msg))
64
+ #define ARGUMENT_ERROR(msg) rb_raise(rb_eArgError, (msg))
65
+ #define TYPE_ERROR(msg) rb_raise(rb_eTypeError, (msg))
66
+ #define RANGE_ERROR(msg) rb_raise(rb_eRangeError, (msg))
67
+ #define NOT_IMPLEMENTED_ERROR(msg) rb_raise(rb_eNotImpError, (msg))
68
+
69
+ #define IS_COLORMAPPED(ci) (((ci)->actual_number_of_colors > 0) &&\
70
+ ((ci)->colormap != NULL) && \
71
+ ((ci)->output_components == 1) && \
72
+ (((ci)->out_color_components == 1) || \
73
+ ((ci)->out_color_components == 3)))
57
74
 
58
75
  #define ALLOC_ARRAY() \
59
- ((JSAMPARRAY)xmalloc(sizeof(JSAMPROW) * UNIT_LINES))
76
+ ((JSAMPARRAY)malloc(sizeof(JSAMPROW) * UNIT_LINES))
60
77
  #define ALLOC_ROWS(w,c) \
61
- ((JSAMPROW)xmalloc(sizeof(JSAMPLE) * (w) * (c) * UNIT_LINES))
78
+ ((JSAMPROW)malloc(sizeof(JSAMPLE) * (w) * (c) * UNIT_LINES))
62
79
 
63
- #define EQ_STR(val,str) (rb_to_id(val) == rb_intern(str))
64
- #define EQ_INT(val,n) (FIX2INT(val) == n)
80
+ #define EQ_STR(val,str) (rb_to_id(val) == rb_intern(str))
81
+ #define EQ_INT(val,n) (FIX2INT(val) == n)
65
82
 
66
83
  static VALUE module;
67
84
  static VALUE encoder_klass;
@@ -73,33 +90,219 @@ static VALUE decerr_klass;
73
90
 
74
91
  static ID id_meta;
75
92
  static ID id_width;
93
+ static ID id_stride;
76
94
  static ID id_height;
77
95
  static ID id_orig_cs;
78
96
  static ID id_out_cs;
79
97
  static ID id_ncompo;
98
+ static ID id_exif_tags;
99
+ static ID id_colormap;
100
+
101
+ typedef struct {
102
+ int tag;
103
+ const char* name;
104
+ } tag_entry_t;
105
+
106
+ tag_entry_t tag_tiff[] = {
107
+ /* 0th IFD */
108
+ {0x0100, "image_width", },
109
+ {0x0101, "image_length", },
110
+ {0x0102, "bits_per_sample", },
111
+ {0x0103, "compression", },
112
+ {0x0106, "photometric_interpretation", },
113
+ {0x010e, "image_description", },
114
+ {0x010f, "maker", },
115
+ {0x0110, "model", },
116
+ {0x0111, "strip_offsets", },
117
+ {0x0112, "orientation", },
118
+ {0x0115, "sample_per_pixel", },
119
+ {0x0116, "rows_per_strip", },
120
+ {0x0117, "strip_byte_counts", },
121
+ {0x011a, "x_resolution", },
122
+ {0x011b, "y_resolution", },
123
+ {0x011c, "planer_configuration", },
124
+ {0x0128, "resolution_unit", },
125
+ {0x012d, "transfer_function", },
126
+ {0x0131, "software", },
127
+ {0x0132, "date_time", },
128
+ {0x013b, "artist", },
129
+ {0x013e, "white_point", },
130
+ {0x013f, "primary_chromaticities", },
131
+ {0x0201, "jpeg_interchange_format", },
132
+ {0x0202, "jpeg_interchange_format_length"},
133
+ {0x0211, "ycbcr_coefficients", },
134
+ {0x0212, "ycbcr_sub_sampling", },
135
+ {0x0213, "ycbcr_positioning", },
136
+ {0x0214, "reference_black_white", },
137
+ {0x0d68, "copyright", },
138
+ {0x8298, "copyright", },
139
+ {0x8769, NULL, }, /* ExifIFDPointer */
140
+ {0x8825, NULL, }, /* GPSInfoIFDPointer */
141
+ {0xc4a5, "print_im", },
142
+ };
143
+
144
+ tag_entry_t tag_exif[] = {
145
+ /* Exif IFD */
146
+ {0x829a, "exposure_time", },
147
+ {0x829d, "f_number", },
148
+ {0x8822, "exposure_program", },
149
+ {0x8824, "spectral_sensitivity", },
150
+ {0x8827, "iso_speed_ratings", },
151
+ {0x8828, "oecf", },
152
+ {0x882a, "time_zone_offset", },
153
+ {0x882b, "self_timer_mode", },
154
+ {0x8830, "sensitivity_type", },
155
+ {0x8831, "standard_output_sensitivity", },
156
+ {0x8832, "recommended_exposure_index", },
157
+ {0x9000, "exif_version", },
158
+ {0x9003, "data_time_original", },
159
+ {0x9004, "data_time_digitized", },
160
+ {0x9010, "offset_time", },
161
+ {0x9011, "offset_time_original", },
162
+ {0x9012, "offset_time_digitized", },
163
+ {0x9101, "color_space", },
164
+ {0x9102, "components_configuration", },
165
+ {0x9201, "shutter_speed_value", },
166
+ {0x9202, "apertutre_value", },
167
+ {0x9203, "brightness_value", },
168
+ {0x9204, "exposure_bias_value", },
169
+ {0x9205, "max_aperture_value", },
170
+ {0x9206, "subject_distance", },
171
+ {0x9207, "metering_mode", },
172
+ {0x9208, "light_source", },
173
+ {0x9209, "flash", },
174
+ {0x920a, "focal_length", },
175
+ {0x927c, "marker_note", },
176
+ {0x9286, "user_comment", },
177
+ {0x9290, "sub_sec_time", },
178
+ {0x9291, "sub_sec_time_original", },
179
+ {0x9292, "sub_sec_time_digitized", },
180
+ {0xa000, "flash_pix_version", },
181
+ {0xa001, "color_space", },
182
+ {0xa002, "pixel_x_dimension", },
183
+ {0xa003, "pixel_y_dimension", },
184
+ {0xa004, "related_sound_file", },
185
+ {0xa005, NULL, }, /* InteroperabilityIFDPointer */
186
+ {0xa20b, "flash_energy", },
187
+ {0xa20b, "flash_energy", },
188
+ {0xa20c, "spatial_frequency_response", },
189
+ {0xa20e, "focal_panel_x_resolution", },
190
+ {0xa20f, "focal_panel_y_resolution", },
191
+ {0xa210, "focal_panel_resolution_unit", },
192
+ {0xa214, "subject_location", },
193
+ {0xa215, "exposure_index", },
194
+ {0xa217, "sensing_method", },
195
+ {0xa300, "file_source", },
196
+ {0xa301, "scene_type", },
197
+ {0xa302, "cfa_pattern", },
198
+ {0xa401, "custom_rendered", },
199
+ {0xa402, "exposure_mode", },
200
+ {0xa403, "white_balance", },
201
+ {0xa404, "digital_zoom_ratio", },
202
+ {0xa405, "focal_length_in_35mm_film", },
203
+ {0xa406, "scene_capture_type", },
204
+ {0xa407, "gain_control", },
205
+ {0xa408, "contrast", },
206
+ {0xa409, "sturation", },
207
+ {0xa40a, "sharpness", },
208
+ {0xa40b, "device_setting_description", },
209
+ {0xa40c, "subject_distance_range", },
210
+ {0xa420, "image_unique_id", },
211
+ {0xa430, "owner_name", },
212
+ {0xa431, "serial_number", },
213
+ {0xa432, "lens_info", },
214
+ {0xa433, "lens_make", },
215
+ {0xa434, "lens_model", },
216
+ {0xa435, "lens_serial_number", },
217
+ };
218
+
219
+ tag_entry_t tag_gps[] = {
220
+ /* GPS IFD */
221
+ {0x0000, "version_id", },
222
+ {0x0001, "latitude_ref", },
223
+ {0x0002, "latitude", },
224
+ {0x0003, "longitude_ref", },
225
+ {0x0004, "longitude", },
226
+ {0x0005, "altitude_ref", },
227
+ {0x0006, "altitude", },
228
+ {0x0007, "timestamp", },
229
+ {0x0008, "satellites", },
230
+ {0x0009, "status", },
231
+ {0x000a, "measure_mode", },
232
+ {0x000b, "dop", },
233
+ {0x000c, "speed_ref", },
234
+ {0x000d, "speed", },
235
+ {0x000e, "track_ref", },
236
+ {0x000f, "track", },
237
+ {0x0010, "img_direction_ref", },
238
+ {0x0011, "img_direction", },
239
+ {0x0012, "map_datum", },
240
+ {0x0013, "dest_latitude_ref", },
241
+ {0x0014, "dest_latitude", },
242
+ {0x0015, "dest_longitude_ref", },
243
+ {0x0016, "dest_longitude", },
244
+ {0x0017, "bearing_ref", },
245
+ {0x0018, "bearing", },
246
+ {0x0019, "dest_distance_ref", },
247
+ {0x001a, "dest_distance", },
248
+ {0x001b, "processing_method", },
249
+ {0x001c, "area_infotmation", },
250
+ {0x001d, "date_stamp", },
251
+ {0x001e, "differential", },
252
+ };
253
+
254
+ tag_entry_t tag_i14y[] = {
255
+ /* Interoperability IFD */
256
+ {0x0001, "interoperability_index", },
257
+ {0x0002, "interoperability_version", },
258
+ {0x1000, "related_image_file_format", },
259
+ {0x1001, "related_image_width", },
260
+ };
80
261
 
81
262
  static const char* encoder_opts_keys[] = {
82
263
  "pixel_format", // {str}
83
264
  "quality", // {integer}
84
- "scale", // {rational} or {float}
85
- "dct_method" // {str}
265
+ "dct_method", // {str}
266
+ "orientation", // {integer}
267
+ "stride", // {integer}
86
268
  };
87
269
 
88
270
  static ID encoder_opts_ids[N(encoder_opts_keys)];
89
271
 
90
272
  typedef struct {
91
- int format;
273
+ struct jpeg_error_mgr jerr;
274
+
275
+ char msg[JMSG_LENGTH_MAX+10];
276
+ jmp_buf jmpbuf;
277
+ } ext_error_t;
278
+
279
+ typedef struct {
280
+ int flags;
92
281
  int width;
282
+ int stride;
93
283
  int height;
94
-
95
284
  int data_size;
285
+
286
+ int format;
287
+ int color_space;
288
+ int components;
289
+ int quality;
96
290
  J_DCT_METHOD dct_method;
97
291
 
98
292
  struct jpeg_compress_struct cinfo;
99
- struct jpeg_error_mgr jerr;
293
+ ext_error_t err_mgr;
100
294
 
101
295
  JSAMPARRAY array;
102
296
  JSAMPROW rows;
297
+
298
+ VALUE data;
299
+
300
+ struct {
301
+ unsigned char* mem;
302
+ unsigned long size;
303
+ } buf;
304
+
305
+ int orientation;
103
306
  } jpeg_encode_t;
104
307
 
105
308
  static const char* decoder_opts_keys[] = {
@@ -108,28 +311,24 @@ static const char* decoder_opts_keys[] = {
108
311
  "do_fancy_upsampling", // {bool}
109
312
  "do_smoothing", // {bool}
110
313
  "dither", // [{str}MODE, {bool}2PASS, {int}NUM_COLORS]
314
+ #if 0
111
315
  "use_1pass_quantizer", // {bool}
112
316
  "use_external_colormap", // {bool}
113
317
  "use_2pass_quantizer", // {bool}
318
+ #endif
114
319
  "without_meta", // {bool}
115
320
  "expand_colormap", // {bool}
116
321
  "scale", // {rational} or {float}
117
- "dct_method" // {str}
322
+ "dct_method", // {str}
323
+ "with_exif_tags", // {bool}
324
+ "orientation" // {bool}
118
325
  };
119
326
 
120
327
  static ID decoder_opts_ids[N(decoder_opts_keys)];
121
328
 
122
329
  typedef struct {
123
- struct jpeg_error_mgr jerr;
124
-
125
- char msg[JMSG_LENGTH_MAX+10];
126
- jmp_buf jmpbuf;
127
- } ext_error_t;
128
-
129
- typedef struct {
330
+ int flags;
130
331
  int format;
131
- int need_meta;
132
- int expand_colormap;
133
332
 
134
333
  J_COLOR_SPACE out_color_space;
135
334
  int scale_num;
@@ -150,553 +349,1104 @@ typedef struct {
150
349
 
151
350
  struct jpeg_decompress_struct cinfo;
152
351
  ext_error_t err_mgr;
352
+
353
+ JSAMPARRAY array;
354
+
355
+ VALUE data;
356
+
357
+ struct {
358
+ int value;
359
+ VALUE buf;
360
+ } orientation;
153
361
  } jpeg_decode_t;
154
362
 
155
- static void
156
- encode_output_message(j_common_ptr cinfo)
363
+ #if 0
364
+ static VALUE
365
+ create_runtime_error(const char* fmt, ...)
157
366
  {
158
- char msg[JMSG_LENGTH_MAX];
367
+ VALUE ret;
368
+ va_list ap;
159
369
 
160
- (*cinfo->err->format_message)(cinfo, msg);
370
+ va_start(ap, fmt);
371
+ ret = rb_exc_new_str(rb_eRuntimeError, rb_vsprintf(fmt, ap));
372
+ va_end(ap);
373
+
374
+ return ret;
161
375
  }
376
+ #endif
162
377
 
163
- static void
164
- encode_error_exit(j_common_ptr cinfo)
378
+ static VALUE
379
+ create_argument_error(const char* fmt, ...)
165
380
  {
166
- char msg[JMSG_LENGTH_MAX];
381
+ VALUE ret;
382
+ va_list ap;
167
383
 
168
- (*cinfo->err->format_message)(cinfo, msg);
384
+ va_start(ap, fmt);
385
+ ret = rb_exc_new_str(rb_eArgError, rb_vsprintf(fmt, ap));
386
+ va_end(ap);
169
387
 
170
- jpeg_destroy_compress((j_compress_ptr)cinfo);
171
- rb_raise(encerr_klass, "%s", msg);
388
+ return ret;
172
389
  }
173
390
 
174
-
175
- static void
176
- rb_encoder_free( void* _ptr)
391
+ static VALUE
392
+ create_type_error(const char* fmt, ...)
177
393
  {
178
- jpeg_encode_t* ptr;
179
-
180
- ptr = (jpeg_encode_t*)_ptr;
181
-
182
- if (ptr->array != NULL) xfree(ptr->array);
183
- if (ptr->rows != NULL) xfree(ptr->rows);
394
+ VALUE ret;
395
+ va_list ap;
184
396
 
185
- jpeg_destroy_compress(&ptr->cinfo);
397
+ va_start(ap, fmt);
398
+ ret = rb_exc_new_str(rb_eTypeError, rb_vsprintf(fmt, ap));
399
+ va_end(ap);
186
400
 
187
- free(_ptr);
401
+ return ret;
188
402
  }
189
403
 
190
404
  static VALUE
191
- rb_encoder_alloc(VALUE self)
405
+ create_range_error(const char* fmt, ...)
192
406
  {
193
- jpeg_encode_t* ptr;
194
-
195
- ptr = ALLOC(jpeg_encode_t);
196
- memset(ptr, 0, sizeof(*ptr));
407
+ VALUE ret;
408
+ va_list ap;
197
409
 
198
- ptr->dct_method = JDCT_FASTEST;
410
+ va_start(ap, fmt);
411
+ ret = rb_exc_new_str(rb_eRangeError, rb_vsprintf(fmt, ap));
412
+ va_end(ap);
199
413
 
200
- return Data_Wrap_Struct(encoder_klass, 0, rb_encoder_free, ptr);
414
+ return ret;
201
415
  }
202
416
 
203
- static void
204
- set_encoder_context(jpeg_encode_t* ptr, int wd, int ht, VALUE opt)
417
+ static VALUE
418
+ create_not_implement_error(const char* fmt, ...)
205
419
  {
206
- VALUE opts[N(encoder_opts_ids)];
207
- int format;
208
- int color_space;
209
- int components;
210
- int data_size;
211
- int quality;
212
- int scale_num;
213
- int scale_denom;
214
- int i;
215
-
216
- /*
217
- * parse options
218
- */
219
- rb_get_kwargs(opt, encoder_opts_ids, 0, N(encoder_opts_ids), opts);
420
+ VALUE ret;
421
+ va_list ap;
220
422
 
221
- /*
222
- * eval :pixel_format option
223
- */
224
- if (opts[0] == Qundef||EQ_STR(opts[0], "YUV422")||EQ_STR(opts[0], "YUYV")) {
225
- format = FMT_YUV422;
226
- color_space = JCS_YCbCr;
227
- components = 3;
228
- data_size = (wd * ht * 2);
423
+ va_start(ap, fmt);
424
+ ret = rb_exc_new_str(rb_eNotImpError, rb_vsprintf(fmt, ap));
425
+ va_end(ap);
229
426
 
230
- } else if (EQ_STR(opts[0], "RGB565")) {
231
- format = FMT_RGB565;
232
- color_space = JCS_RGB;
233
- components = 3;
234
- data_size = (wd * ht * 2);
427
+ return ret;
428
+ }
235
429
 
236
- } else if (EQ_STR(opts[0], "RGB") || EQ_STR(opts[0], "RGB24")) {
237
- format = FMT_RGB;
238
- color_space = JCS_RGB;
239
- components = 3;
240
- data_size = (wd * ht * 3);
430
+ static VALUE
431
+ create_memory_error()
432
+ {
433
+ return rb_exc_new_str(rb_eRangeError, rb_str_new_cstr("no memory"));
434
+ }
241
435
 
242
- } else if (EQ_STR(opts[0], "BGR") || EQ_STR(opts[0], "BGR24")) {
243
- format = FMT_BGR;
244
- color_space = JCS_EXT_BGR;
245
- components = 3;
246
- data_size = (wd * ht * 3);
436
+ static void
437
+ output_message(j_common_ptr cinfo)
438
+ {
439
+ ext_error_t* err;
247
440
 
248
- } else if (EQ_STR(opts[0], "YUV444") || EQ_STR(opts[0], "YCbCr")) {
249
- format = FMT_YUV;
250
- color_space = JCS_YCbCr;
251
- components = 3;
252
- data_size = (wd * ht * 3);
441
+ err = (ext_error_t*)cinfo->err;
253
442
 
254
- } else if (EQ_STR(opts[0], "RGBX") || EQ_STR(opts[0], "RGB32")) {
255
- format = FMT_RGB32;
256
- color_space = JCS_EXT_RGBX;
257
- components = 4;
258
- data_size = (wd * ht * 4);
443
+ (*err->jerr.format_message)(cinfo, err->msg);
444
+ }
259
445
 
446
+ static void
447
+ emit_message(j_common_ptr cinfo, int msg_level)
448
+ {
449
+ ext_error_t* err;
260
450
 
261
- } else if (EQ_STR(opts[0], "BGRX") || EQ_STR(opts[0], "BGR32")) {
262
- format = FMT_BGR32;
263
- color_space = JCS_EXT_BGRX;
264
- components = 4;
265
- data_size = (wd * ht * 4);
451
+ if (msg_level < 0) {
452
+ err = (ext_error_t*)cinfo->err;
453
+ (*err->jerr.format_message)(cinfo, err->msg);
454
+ /*
455
+ * 以前はemit_messageが呼ばれるとエラー扱いしていたが、
456
+ * Logicoolの一部のモデルなどで問題が出るので無視する
457
+ * ようにした。
458
+ * また本来であれば、警告表示を行うべきでもあるが一部
459
+ * のモデルで大量にemitされる場合があるので表示しない
460
+ * ようにしている。
461
+ * 問題が発生した際は、最後のメッセージをオブジェクト
462
+ * のインスタンスとして持たすべき。
463
+ */
464
+ // longjmp(err->jmpbuf, 1);
465
+ }
466
+ }
266
467
 
468
+ static void
469
+ error_exit(j_common_ptr cinfo)
470
+ {
471
+ ext_error_t* err;
267
472
 
268
- } else if (EQ_STR(opts[0], "GRAYSCALE")) {
269
- format = FMT_GRAYSCALE;
270
- color_space = JCS_GRAYSCALE;
271
- components = 1;
272
- data_size = (wd * ht);
473
+ err = (ext_error_t*)cinfo->err;
474
+ (*err->jerr.format_message)(cinfo, err->msg);
475
+ longjmp(err->jmpbuf, 1);
476
+ }
273
477
 
274
- } else {
275
- ARGUMENT_ERROR("Unsupportd :pixel_format option value.");
276
- }
478
+ static VALUE
479
+ lookup_tag_symbol(tag_entry_t* tbl, size_t n, int tag)
480
+ {
481
+ VALUE ret;
482
+ int l;
483
+ int r;
484
+ int i;
485
+ tag_entry_t* p;
486
+ char buf[16];
277
487
 
278
- /*
279
- * eval :quality option
280
- */
281
- if (opts[1] == Qundef) {
282
- quality = DEFAULT_QUALITY;
488
+ ret = Qundef;
489
+ l = 0;
490
+ r = n - 1;
283
491
 
284
- } else {
285
- if (TYPE(opts[1]) != T_FIXNUM) {
286
- ARGUMENT_ERROR("Unsupportd :quality option value.");
492
+ while (r >= l) {
493
+ i = (l + r) / 2;
494
+ p = tbl + i;
287
495
 
288
- } else {
289
- quality = FIX2INT(opts[1]);
496
+ if (p->tag < tag) {
497
+ l = i + 1;
498
+ continue;
290
499
  }
291
500
 
292
- if (quality < 0) {
293
- ARGUMENT_ERROR(":quality value is to little.");
294
-
295
- } else if (quality > 100) {
296
- ARGUMENT_ERROR(":quality value is to big.");
501
+ if (p->tag > tag) {
502
+ r = i - 1;
503
+ continue;
297
504
  }
298
- }
299
-
300
- /*
301
- * eval scale option
302
- */
303
- switch (TYPE(opts[2])) {
304
- case T_UNDEF:
305
- // Nothing
306
- break;
307
-
308
- case T_FLOAT:
309
- scale_num = 1000;
310
- scale_denom = (int)(NUM2DBL(opts[2]) * 1000.0);
311
- break;
312
505
 
313
- case T_RATIONAL:
314
- scale_num = FIX2INT(rb_rational_num(opts[2]));
315
- scale_denom = FIX2INT(rb_rational_den(opts[2]));
316
- break;
317
-
318
- default:
319
- ARGUMENT_ERROR("Unsupportd :scale option value.");
506
+ ret = (p->name)? ID2SYM(rb_intern(p->name)): Qnil;
320
507
  break;
321
508
  }
322
509
 
323
- /*
324
- * eval dct_method option
325
- */
326
- if (opts[3] == Qundef || EQ_STR(opts[3], "FASTEST")) {
327
- ptr->dct_method = JDCT_FASTEST;
328
-
329
- } else if (EQ_STR(opts[3], "ISLOW")) {
330
- ptr->dct_method = JDCT_ISLOW;
331
-
332
- } else if (EQ_STR(opts[3], "IFAST")) {
333
- ptr->dct_method = JDCT_IFAST;
334
-
335
- } else if (EQ_STR(opts[3], "FLOAT")) {
336
- ptr->dct_method = JDCT_FLOAT;
337
-
338
- } else {
339
- ARGUMENT_ERROR("Unsupportd :dct_method option value.");
340
- }
341
-
342
- /*
343
- * set context
344
- */
345
- ptr->format = format;
346
- ptr->width = wd;
347
- ptr->height = ht;
348
- ptr->data_size = data_size;
349
- ptr->array = ALLOC_ARRAY();
350
- ptr->rows = ALLOC_ROWS(wd, components);
351
-
352
- for (i = 0; i < UNIT_LINES; i++) {
353
- ptr->array[i] = ptr->rows + (i * components * wd);
510
+ if (ret == Qundef) {
511
+ sprintf(buf, "tag_%04x", tag);
512
+ ret = ID2SYM(rb_intern(buf));
354
513
  }
355
514
 
356
- jpeg_create_compress(&ptr->cinfo);
357
-
358
- ptr->cinfo.err = jpeg_std_error(&ptr->jerr);
359
- ptr->jerr.output_message = encode_output_message;
360
- ptr->jerr.error_exit = encode_error_exit;
361
-
362
- ptr->cinfo.image_width = wd;
363
- ptr->cinfo.image_height = ht;
364
- ptr->cinfo.in_color_space = color_space;
365
- ptr->cinfo.input_components = components;
366
-
367
- ptr->cinfo.optimize_coding = TRUE;
368
- ptr->cinfo.arith_code = TRUE;
369
- ptr->cinfo.raw_data_in = FALSE;
370
- ptr->cinfo.dct_method = ptr->dct_method;
371
-
372
- jpeg_set_defaults(&ptr->cinfo);
373
- jpeg_set_quality(&ptr->cinfo, quality, TRUE);
374
- jpeg_suppress_tables(&ptr->cinfo, TRUE);
515
+ return ret;
375
516
  }
376
517
 
377
- static VALUE
378
- rb_encoder_initialize(int argc, VALUE *argv, VALUE self)
518
+ static void
519
+ rb_encoder_mark(void* _ptr)
379
520
  {
380
521
  jpeg_encode_t* ptr;
381
- VALUE wd;
382
- VALUE ht;
383
- VALUE opt;
384
522
 
385
- /*
386
- * initialize
387
- */
388
- Data_Get_Struct(self, jpeg_encode_t, ptr);
389
-
390
- /*
391
- * parse arguments
392
- */
393
- rb_scan_args(argc, argv, "21", &wd, &ht, &opt);
394
-
395
- Check_Type(wd, T_FIXNUM);
396
- Check_Type(ht, T_FIXNUM);
397
- if (opt != Qnil) Check_Type(opt, T_HASH);
398
-
399
- /*
400
- * set context
401
- */
402
- set_encoder_context(ptr, FIX2INT(wd), FIX2INT(ht), opt);
523
+ ptr = (jpeg_encode_t*)_ptr;
403
524
 
404
- return Qtrue;
525
+ if (ptr->data != Qnil) {
526
+ rb_gc_mark(ptr->data);
527
+ }
405
528
  }
406
529
 
407
- static int
408
- push_rows_yuv422(JSAMPROW rows, int wd, uint8_t* data, int nrow)
530
+ static void
531
+ rb_encoder_free(void* _ptr)
409
532
  {
410
- int size;
411
- int i;
412
-
413
- size = wd * nrow;
533
+ jpeg_encode_t* ptr;
414
534
 
415
- for (i = 0; i < size; i += 2) {
416
- rows[0] = data[0];
417
- rows[1] = data[1];
418
- rows[2] = data[3];
419
- rows[3] = data[2];
420
- rows[4] = data[1];
421
- rows[5] = data[3];
535
+ ptr = (jpeg_encode_t*)_ptr;
422
536
 
423
- rows += 6;
424
- data += 4;
537
+ if (ptr->array != NULL) {
538
+ free(ptr->array);
425
539
  }
426
540
 
427
- return (size * 2);
428
- }
429
-
430
- static int
431
- push_rows_rgb565(JSAMPROW rows, int wd, uint8_t* data, int nrow)
432
- {
433
- int size;
434
- int i;
435
-
436
- size = wd * nrow;
541
+ if (ptr->rows != NULL) {
542
+ free(ptr->rows);
543
+ }
437
544
 
438
- for (i = 0; i < size; i += 1) {
439
- rows[0] = data[1] & 0xf8;
440
- rows[1] = ((data[1] << 5) & 0xe0) | ((data[0] >> 3) & 0x1c);
441
- rows[2] = (data[0] << 3) & 0xf8;
545
+ if (ptr->buf.mem != NULL) {
546
+ free(ptr->buf.mem);
547
+ }
442
548
 
443
- rows += 3;
444
- data += 2;
549
+ if (TEST_FLAG(ptr, F_CREAT)) {
550
+ jpeg_destroy_compress(&ptr->cinfo);
445
551
  }
446
552
 
447
- return (size * 2);
553
+ free(ptr);
448
554
  }
449
555
 
450
- static int
451
- push_rows_comp3(JSAMPROW rows, int wd, uint8_t* data, int nrow)
556
+ static size_t
557
+ rb_encoder_size(const void* _ptr)
452
558
  {
453
- int size;
454
-
455
- size = wd * nrow * 3;
456
- memcpy(rows, data, size);
457
-
458
- return size;
459
- }
559
+ size_t ret;
560
+ jpeg_encode_t* ptr;
460
561
 
461
- static int
462
- push_rows_comp4(JSAMPROW rows, int wd, uint8_t* data, int nrow)
463
- {
464
- int size;
562
+ ptr = (jpeg_encode_t*)_ptr;
465
563
 
466
- size = wd * nrow * 4;
467
- memcpy(rows, data, size);
564
+ ret = sizeof(jpeg_encode_t);
565
+ ret += sizeof(JSAMPROW) * UNIT_LINES;
566
+ ret += sizeof(JSAMPLE) * ptr->stride * UNIT_LINES;
468
567
 
469
- return size;
568
+ return ret;
470
569
  }
471
570
 
571
+ #if RUBY_API_VERSION_CODE > 20600
572
+ static const rb_data_type_t jpeg_encoder_data_type = {
573
+ "libjpeg-ruby encoder object", // wrap_struct_name
574
+ {
575
+ rb_encoder_mark, // function.dmark
576
+ rb_encoder_free, // function.dfree
577
+ rb_encoder_size, // function.dsize
578
+ NULL, // function.dcompact
579
+ {NULL}, // function.reserved
580
+ },
581
+ NULL, // parent
582
+ NULL, // data
583
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
584
+ };
585
+ #else /* RUBY_API_VERSION_CODE > 20600 */
586
+ static const rb_data_type_t jpeg_encoder_data_type = {
587
+ "libjpeg-ruby encoder object", // wrap_struct_name
588
+ {
589
+ rb_encoder_mark, // function.dmark
590
+ rb_encoder_free, // function.dfree
591
+ rb_encoder_size, // function.dsize
592
+ {NULL, NULL}, // function.reserved
593
+ },
594
+ NULL, // parent
595
+ NULL, // data
596
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
597
+ };
598
+ #endif /* RUBY_API_VERSION_CODE > 20600 */
472
599
 
473
-
474
- static int
475
- push_rows_grayscale(JSAMPROW rows, int wd, uint8_t* data, int nrow)
600
+ static VALUE
601
+ rb_encoder_alloc(VALUE self)
476
602
  {
477
- int size;
603
+ jpeg_encode_t* ptr;
604
+
605
+ ptr = ALLOC(jpeg_encode_t);
606
+ memset(ptr, 0, sizeof(*ptr));
478
607
 
479
- size = wd * nrow;
480
- memcpy(rows, data, size);
608
+ ptr->flags = DEFAULT_ENCODE_FLAGS;
481
609
 
482
- return size;
610
+ return TypedData_Wrap_Struct(encoder_klass, &jpeg_encoder_data_type, ptr);
483
611
  }
484
612
 
485
- static int
486
- push_rows(jpeg_encode_t* ptr, uint8_t* data, int nrow)
613
+ static VALUE
614
+ eval_encoder_pixel_format_opt(jpeg_encode_t* ptr, VALUE opt)
487
615
  {
488
- int ret;
616
+ VALUE ret;
617
+ int format;
618
+ int color_space;
619
+ int components;
489
620
 
490
- switch (ptr->format) {
491
- case FMT_YUV422:
492
- ret = push_rows_yuv422(ptr->rows, ptr->width, data, nrow);
493
- break;
621
+ ret = Qnil;
494
622
 
495
- case FMT_RGB565:
496
- ret = push_rows_rgb565(ptr->rows, ptr->width, data, nrow);
623
+ switch (TYPE(opt)) {
624
+ case T_UNDEF:
625
+ format = FMT_YUV422;
626
+ color_space = JCS_YCbCr;
627
+ components = 3;
497
628
  break;
498
629
 
499
- case FMT_YUV:
500
- case FMT_RGB:
501
- case FMT_BGR:
502
- ret = push_rows_comp3(ptr->rows, ptr->width, data, nrow);
630
+ case T_STRING:
631
+ case T_SYMBOL:
632
+ if (EQ_STR(opt, "YUV422") || EQ_STR(opt, "YUYV")) {
633
+ format = FMT_YUV422;
634
+ color_space = JCS_YCbCr;
635
+ components = 3;
636
+
637
+ } else if (EQ_STR(opt, "RGB565")) {
638
+ format = FMT_RGB565;
639
+ color_space = JCS_RGB;
640
+ components = 3;
641
+
642
+ } else if (EQ_STR(opt, "RGB") || EQ_STR(opt, "RGB24")) {
643
+ format = FMT_RGB;
644
+ color_space = JCS_RGB;
645
+ components = 3;
646
+
647
+ } else if (EQ_STR(opt, "BGR") || EQ_STR(opt, "BGR24")) {
648
+ format = FMT_BGR;
649
+ color_space = JCS_EXT_BGR;
650
+ components = 3;
651
+
652
+ } else if (EQ_STR(opt, "YUV444") || EQ_STR(opt, "YCbCr")) {
653
+ format = FMT_YUV;
654
+ color_space = JCS_YCbCr;
655
+ components = 3;
656
+
657
+ } else if (EQ_STR(opt, "RGBX") || EQ_STR(opt, "RGB32")) {
658
+ format = FMT_RGB32;
659
+ color_space = JCS_EXT_RGBX;
660
+ components = 4;
661
+
662
+ } else if (EQ_STR(opt, "BGRX") || EQ_STR(opt, "BGR32")) {
663
+ format = FMT_BGR32;
664
+ color_space = JCS_EXT_BGRX;
665
+ components = 4;
666
+
667
+ } else if (EQ_STR(opt, "GRAYSCALE")) {
668
+ format = FMT_GRAYSCALE;
669
+ color_space = JCS_GRAYSCALE;
670
+ components = 1;
671
+
672
+ } else {
673
+ ret = create_argument_error("unsupportd :pixel_format option value");
674
+ }
503
675
  break;
504
676
 
505
- case FMT_RGB32:
506
- case FMT_BGR32:
507
- ret = push_rows_comp4(ptr->rows, ptr->width, data, nrow);
677
+ default:
678
+ ret = create_type_error("unsupportd :pixel_format option type");
508
679
  break;
680
+ }
509
681
 
510
- case FMT_GRAYSCALE:
511
- ret = push_rows_grayscale(ptr->rows, ptr->width, data, nrow);
682
+ if (!RTEST(ret)) {
683
+ ptr->format = format;
684
+ ptr->color_space = color_space;
685
+ ptr->components = components;
686
+ }
687
+
688
+ return ret;
689
+ }
690
+
691
+ static VALUE
692
+ eval_encoder_quality_opt(jpeg_encode_t* ptr, VALUE opt)
693
+ {
694
+ VALUE ret;
695
+ long quality;
696
+
697
+ ret = Qnil;
698
+
699
+ switch (TYPE(opt)) {
700
+ case T_UNDEF:
701
+ quality = DEFAULT_QUALITY;
702
+ break;
703
+
704
+ case T_FLOAT:
705
+ if (isnan(NUM2DBL(opt)) || isinf(NUM2DBL(opt))) {
706
+ ret = create_argument_error("unsupportd :quality option value");
707
+
708
+ } else if (NUM2DBL(opt) < 0.0) {
709
+ ret = create_range_error(":quality less than 0");
710
+
711
+ } else if (NUM2DBL(opt) > 100.0) {
712
+ ret = create_range_error(":quality greater than 100");
713
+
714
+ } else {
715
+ quality = NUM2INT(opt);
716
+ }
717
+ break;
718
+
719
+ case T_FIXNUM:
720
+ if (FIX2LONG(opt) < 0) {
721
+ ret = create_range_error(":quality less than 0");
722
+
723
+ } if (FIX2LONG(opt) > 100) {
724
+ ret = create_range_error(":quality greater than 100");
725
+
726
+ } else {
727
+ quality = FIX2INT(opt);
728
+ }
512
729
  break;
513
730
 
514
731
  default:
515
- RUNTIME_ERROR("Really?");
732
+ ret = create_type_error("unsupportd :quality option type");
733
+ break;
516
734
  }
517
735
 
736
+ if (!RTEST(ret)) ptr->quality = quality;
737
+
518
738
  return ret;
519
739
  }
520
740
 
521
741
  static VALUE
522
- do_encode(jpeg_encode_t* ptr, uint8_t* data)
742
+ eval_encoder_dct_method_opt(jpeg_encode_t* ptr, VALUE opt)
523
743
  {
524
744
  VALUE ret;
745
+ int dct_method;
525
746
 
526
- unsigned char* buf;
527
- unsigned long buf_size;
528
- int nrow;
747
+ ret = Qnil;
748
+
749
+ switch (TYPE(opt)) {
750
+ case T_UNDEF:
751
+ dct_method = JDCT_FASTEST;
752
+ break;
753
+
754
+ case T_STRING:
755
+ case T_SYMBOL:
756
+ if (EQ_STR(opt, "FASTEST")) {
757
+ dct_method = JDCT_FASTEST;
758
+
759
+ } else if (EQ_STR(opt, "ISLOW")) {
760
+ dct_method = JDCT_ISLOW;
761
+
762
+ } else if (EQ_STR(opt, "IFAST")) {
763
+ dct_method = JDCT_IFAST;
764
+
765
+ } else if (EQ_STR(opt, "FLOAT")) {
766
+ dct_method = JDCT_FLOAT;
767
+
768
+ } else {
769
+ ret = create_argument_error("unsupportd :dct_method option value");
770
+ }
771
+ break;
772
+
773
+ default:
774
+ ret = create_type_error("unsupportd :dct_method option type");
775
+ break;
776
+ }
777
+
778
+ if (!RTEST(ret)) ptr->dct_method = dct_method;
779
+
780
+ return ret;
781
+ }
782
+
783
+ static VALUE
784
+ eval_encoder_orientation_opt(jpeg_encode_t* ptr, VALUE opt)
785
+ {
786
+ VALUE ret;
787
+ int orientation;
788
+
789
+ ret = Qnil;
790
+
791
+ switch (TYPE(opt)) {
792
+ case T_UNDEF:
793
+ orientation = 0;
794
+ break;
795
+
796
+ case T_FIXNUM:
797
+ orientation = FIX2INT(opt);
798
+ if (orientation < 1 || orientation > 8) {
799
+ ret = create_range_error(":orientation option ouf range");
800
+ }
801
+ break;
802
+
803
+ default:
804
+ ret = create_type_error("Unsupportd :orientation option type.");
805
+ break;
806
+ }
807
+
808
+ if (!RTEST(ret)) ptr->orientation = orientation;
529
809
 
530
- buf = NULL;
810
+ return ret;
811
+ }
531
812
 
813
+ static VALUE
814
+ eval_encoder_stride_opt(jpeg_encode_t* ptr, VALUE opt)
815
+ {
816
+ VALUE ret;
817
+ int stride;
532
818
 
533
- jpeg_mem_dest(&ptr->cinfo, &buf, &buf_size);
819
+ ret = Qnil;
534
820
 
535
- jpeg_start_compress(&ptr->cinfo, TRUE);
821
+ switch (TYPE(opt)) {
822
+ case T_UNDEF:
823
+ stride = ptr->width * ptr->components;
824
+ break;
536
825
 
537
- while (ptr->cinfo.next_scanline < ptr->cinfo.image_height) {
538
- nrow = ptr->cinfo.image_height - ptr->cinfo.next_scanline;
539
- if (nrow > UNIT_LINES) nrow = UNIT_LINES;
826
+ case T_FIXNUM:
827
+ stride = FIX2INT(opt);
828
+ if (stride < (ptr->width * ptr->components)) {
829
+ ret = create_range_error(":stride too little");
830
+ }
831
+ break;
540
832
 
541
- data += push_rows(ptr, data, nrow);
542
- jpeg_write_scanlines(&ptr->cinfo, ptr->array, nrow);
833
+ default:
834
+ ret = create_type_error("unsupportd :stride option type");
543
835
  }
544
836
 
545
- jpeg_finish_compress(&ptr->cinfo);
837
+ if (!RTEST(ret)) ptr->stride = stride;
838
+
839
+ return ret;
840
+ }
841
+
842
+ static VALUE
843
+ set_encoder_context(jpeg_encode_t* ptr, int wd, int ht, VALUE opt)
844
+ {
845
+ VALUE ret;
846
+ VALUE opts[N(encoder_opts_ids)];
847
+ JSAMPARRAY ary;
848
+ JSAMPROW rows;
849
+
850
+ int i;
851
+
852
+ /*
853
+ * initialize
854
+ */
855
+ ret = Qnil;
856
+ ary = NULL;
857
+ rows = NULL;
858
+
859
+ /*
860
+ * argument check
861
+ */
862
+ do {
863
+ if (wd <= 0) {
864
+ ret = create_range_error("image width less equal zero");
865
+ break;
866
+ }
867
+
868
+ if (ht <= 0) {
869
+ ret = create_range_error("image height less equal zero");
870
+ break;
871
+ }
872
+ } while (0);
873
+
874
+ /*
875
+ * parse options
876
+ */
877
+ if (!RTEST(ret)) do {
878
+ rb_get_kwargs(opt, encoder_opts_ids, 0, N(encoder_opts_ids), opts);
879
+
880
+ // オプション評価で使用するので前もって設定しておく
881
+ ptr->width = wd;
882
+ ptr->height = ht;
883
+
884
+ ret = eval_encoder_pixel_format_opt(ptr, opts[0]);
885
+ if (RTEST(ret)) break;
886
+
887
+ ret = eval_encoder_quality_opt(ptr, opts[1]);
888
+ if (RTEST(ret)) break;
889
+
890
+ ret = eval_encoder_dct_method_opt(ptr, opts[2]);
891
+ if (RTEST(ret)) break;
892
+
893
+ ret = eval_encoder_orientation_opt(ptr, opts[3]);
894
+ if (RTEST(ret)) break;
895
+
896
+ ret = eval_encoder_stride_opt(ptr, opts[4]);
897
+ if (RTEST(ret)) break;
898
+ } while (0);
899
+
900
+ /*
901
+ * alloc memory
902
+ */
903
+ if (!RTEST(ret)) do {
904
+ ary = ALLOC_ARRAY();
905
+ if (ary == NULL) {
906
+ ret = create_memory_error();
907
+ break;
908
+ }
909
+
910
+ rows = ALLOC_ROWS(ptr->width, ptr->components);
911
+ if (rows == NULL) {
912
+ ret = create_memory_error();
913
+ break;
914
+ }
915
+ } while (0);
546
916
 
547
917
  /*
548
- * create return data
918
+ * set the rest context parameter
549
919
  */
550
- ret = rb_str_buf_new(buf_size);
551
- rb_str_set_len(ret, buf_size);
920
+ if (!RTEST(ret)) {
921
+ ptr->err_mgr.jerr.output_message = output_message;
922
+ ptr->err_mgr.jerr.emit_message = emit_message;
923
+ ptr->err_mgr.jerr.error_exit = error_exit;
924
+
925
+ ptr->data_size = ptr->stride * ptr->height;
926
+ ptr->buf.mem = NULL;
927
+ ptr->buf.size = 0;
928
+ ptr->array = ary;
929
+ ptr->rows = rows;
930
+ ptr->data = Qnil;
931
+
932
+ for (i = 0; i < UNIT_LINES; i++) {
933
+ ptr->array[i] = ptr->rows + (i * ptr->width * ptr->components);
934
+ }
935
+ }
552
936
 
553
- memcpy(RSTRING_PTR(ret), buf, buf_size);
937
+ /*
938
+ * setup libjpeg
939
+ */
940
+ if (!RTEST(ret)) {
941
+ jpeg_create_compress(&ptr->cinfo);
942
+ SET_FLAG(ptr, F_CREAT);
943
+
944
+ ptr->cinfo.err = jpeg_std_error(&ptr->err_mgr.jerr);
945
+ ptr->cinfo.image_width = ptr->width;
946
+ ptr->cinfo.image_height = ptr->height;
947
+ ptr->cinfo.in_color_space = ptr->color_space;
948
+ ptr->cinfo.input_components = ptr->components;
949
+
950
+ ptr->cinfo.optimize_coding = TRUE;
951
+ ptr->cinfo.arith_code = TRUE;
952
+ ptr->cinfo.raw_data_in = FALSE;
953
+ ptr->cinfo.dct_method = ptr->dct_method;
954
+
955
+ jpeg_set_defaults(&ptr->cinfo);
956
+ jpeg_set_quality(&ptr->cinfo, ptr->quality, TRUE);
957
+ jpeg_suppress_tables(&ptr->cinfo, TRUE);
958
+ }
554
959
 
555
960
  /*
556
961
  * post process
557
962
  */
558
- free(buf);
963
+ if (RTEST(ret)) {
964
+ if (ary != NULL) free(ary);
965
+ if (rows != NULL) free(rows);
966
+ }
559
967
 
560
968
  return ret;
561
969
  }
562
970
 
971
+ /**
972
+ * initialize encoder object
973
+ *
974
+ * @overload initialize(width, height, opts)
975
+ *
976
+ * @param width [Integer] width of input image (px)
977
+ * @param height [Integer] height of input image (px)
978
+ * @param opts [Hash] options to initialize object
979
+ *
980
+ * @option opts [Symbol] :pixel_format
981
+ * specifies the format of the input image. possible values are:
982
+ * YUV422 YUYV RGB565 RGB RGB24 BGR BGR24 YUV444 YCbCr
983
+ * RGBX RGB32 BGRX BGR32 GRAYSCALE
984
+ *
985
+ * @option opts [Integer] :quality
986
+ * specifies the quality of the compressed image.
987
+ * You can specify from 0 (lowest) to 100 (best).
988
+ *
989
+ * @option opts [Symbol] :dct_method
990
+ * specifies how encoding is handled. possible values are:
991
+ * FASTEST ISLOW IFAST FLOAT
992
+ */
563
993
  static VALUE
564
- rb_encoder_encode(VALUE self, VALUE data)
994
+ rb_encoder_initialize(int argc, VALUE *argv, VALUE self)
565
995
  {
566
- VALUE ret;
567
996
  jpeg_encode_t* ptr;
997
+ VALUE exc;
998
+ VALUE wd;
999
+ VALUE ht;
1000
+ VALUE opt;
568
1001
 
569
1002
  /*
570
1003
  * initialize
571
1004
  */
572
- Data_Get_Struct(self, jpeg_encode_t, ptr);
1005
+ exc = Qnil;
1006
+
1007
+ TypedData_Get_Struct(self, jpeg_encode_t, &jpeg_encoder_data_type, ptr);
1008
+
1009
+ /*
1010
+ * parse arguments
1011
+ */
1012
+ rb_scan_args(argc, argv, "2:", &wd, &ht, &opt);
573
1013
 
574
1014
  /*
575
1015
  * argument check
576
1016
  */
577
- Check_Type(data, T_STRING);
1017
+ do {
1018
+ if (TYPE(wd) != T_FIXNUM) {
1019
+ exc = create_argument_error("invalid width");
1020
+ break;
1021
+ }
578
1022
 
579
- if (RSTRING_LEN(data) < ptr->data_size) {
580
- ARGUMENT_ERROR("raw image data is too short.");
581
- }
1023
+ if (TYPE(ht) != T_FIXNUM) {
1024
+ exc = create_argument_error("invalid height");
1025
+ break;
1026
+ }
1027
+ } while (0);
582
1028
 
583
- if (RSTRING_LEN(data) > ptr->data_size) {
584
- ARGUMENT_ERROR("raw image data is too large.");
1029
+ /*
1030
+ * set context
1031
+ */
1032
+ if (!RTEST(exc)) {
1033
+ exc = set_encoder_context(ptr, FIX2INT(wd), FIX2INT(ht), opt);
585
1034
  }
586
1035
 
587
1036
  /*
588
- * do encode
1037
+ * post process
589
1038
  */
590
- ret = do_encode(ptr, (uint8_t*)RSTRING_PTR(data));
1039
+ if (RTEST(exc)) rb_exc_raise(exc);
591
1040
 
592
- return ret;
1041
+ return Qtrue;
593
1042
  }
594
1043
 
595
1044
  static void
596
- rb_decoder_free(void* ptr)
1045
+ push_rows_yuv422(JSAMPROW dst, int wd, int st, uint8_t* data, int nrow)
597
1046
  {
598
- //jpeg_destroy_decompress(&(((jpeg_decode_t*)ptr)->cinfo));
1047
+ uint8_t* src;
1048
+ int i;
1049
+ int j;
599
1050
 
600
- free(ptr);
1051
+ for (i = 0; i < nrow; i++) {
1052
+ src = data;
1053
+
1054
+ for (j = 0; j < wd; j += 2) {
1055
+ dst[0] = src[0];
1056
+ dst[1] = src[1];
1057
+ dst[2] = src[3];
1058
+ dst[3] = src[2];
1059
+ dst[4] = src[1];
1060
+ dst[5] = src[3];
1061
+
1062
+ dst += 6;
1063
+ src += 4;
1064
+ }
1065
+
1066
+ data += st;
1067
+ }
601
1068
  }
602
1069
 
603
1070
  static void
604
- decode_output_message(j_common_ptr cinfo)
1071
+ push_rows_rgb565(JSAMPROW dst, int wd, int st, uint8_t* data, int nrow)
605
1072
  {
606
- ext_error_t* err;
1073
+ uint8_t* src;
1074
+ int i;
1075
+ int j;
607
1076
 
608
- err = (ext_error_t*)cinfo->err;
1077
+ for (i = 0; i < nrow; i++) {
1078
+ src = data;
609
1079
 
610
- (*err->jerr.format_message)(cinfo, err->msg);
1080
+ for (j = 0; j < wd; j++) {
1081
+ dst[0] = src[1] & 0xf8;
1082
+ dst[1] = ((src[1] << 5) & 0xe0) | ((src[0] >> 3) & 0x1c);
1083
+ dst[2] = (src[0] << 3) & 0xf8;
1084
+
1085
+ dst += 3;
1086
+ src += 2;
1087
+ }
1088
+
1089
+ data += st;
1090
+ }
611
1091
  }
612
1092
 
613
1093
  static void
614
- decode_emit_message(j_common_ptr cinfo, int msg_level)
1094
+ push_rows_comp3(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
615
1095
  {
616
- ext_error_t* err;
1096
+ int size;
1097
+ int i;
617
1098
 
618
- if (msg_level < 0) {
619
- err = (ext_error_t*)cinfo->err;
620
- (*err->jerr.format_message)(cinfo, err->msg);
621
- /*
622
- * 以前はemit_messageが呼ばれるとエラー扱いしていたが、
623
- * Logicoolの一部のモデルなどで問題が出るので無視する
624
- * ようにした。
625
- * また本来であれば、警告表示を行うべきでもあるが一部
626
- * のモデルで大量にemitされる場合があるので表示しない
627
- * ようにしている。
628
- * 問題が発生した際は、最後のメッセージをオブジェクト
629
- * のインスタンスとして持たすべき。
630
- */
631
- // longjmp(err->jmpbuf, 1);
1099
+ size = wd * 3;
1100
+
1101
+ for (i = 0; i < nrow; i++) {
1102
+ memcpy(rows, data, size);
1103
+
1104
+ rows += size;
1105
+ data += st;
632
1106
  }
633
1107
  }
634
1108
 
635
1109
  static void
636
- decode_error_exit(j_common_ptr cinfo)
1110
+ push_rows_comp4(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
637
1111
  {
638
- ext_error_t* err;
1112
+ int size;
1113
+ int i;
639
1114
 
640
- err = (ext_error_t*)cinfo->err;
641
- (*err->jerr.format_message)(cinfo, err->msg);
642
- longjmp(err->jmpbuf, 1);
1115
+ size = wd * 4;
1116
+
1117
+ for (i = 0; i < nrow; i++) {
1118
+ memcpy(rows, data, size);
1119
+
1120
+ rows += size;
1121
+ data += st;
1122
+ }
1123
+ }
1124
+
1125
+ static void
1126
+ push_rows_grayscale(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
1127
+ {
1128
+ int i;
1129
+
1130
+ for (i = 0; i < nrow; i++) {
1131
+ memcpy(rows, data, wd);
1132
+
1133
+ rows += wd;
1134
+ data += st;
1135
+ }
1136
+ }
1137
+
1138
+ static void
1139
+ push_rows(jpeg_encode_t* ptr, uint8_t* data, int nrow)
1140
+ {
1141
+ switch (ptr->format) {
1142
+ case FMT_YUV422:
1143
+ push_rows_yuv422(ptr->rows, ptr->width, ptr->stride, data, nrow);
1144
+ break;
1145
+
1146
+ case FMT_RGB565:
1147
+ push_rows_rgb565(ptr->rows, ptr->width, ptr->stride, data, nrow);
1148
+ break;
1149
+
1150
+ case FMT_YUV:
1151
+ case FMT_RGB:
1152
+ case FMT_BGR:
1153
+ push_rows_comp3(ptr->rows, ptr->width, ptr->stride, data, nrow);
1154
+ break;
1155
+
1156
+ case FMT_RGB32:
1157
+ case FMT_BGR32:
1158
+ push_rows_comp4(ptr->rows, ptr->width, ptr->stride, data, nrow);
1159
+ break;
1160
+
1161
+ case FMT_GRAYSCALE:
1162
+ push_rows_grayscale(ptr->rows, ptr->width, ptr->stride, data, nrow);
1163
+ break;
1164
+
1165
+ default:
1166
+ RUNTIME_ERROR("Really?");
1167
+ }
1168
+ }
1169
+
1170
+ static void
1171
+ put_exif_tags(jpeg_encode_t* ptr)
1172
+ {
1173
+ uint8_t data[] = {
1174
+ /* Exif header */
1175
+ 'E', 'x', 'i', 'f', 0x00, 0x00,
1176
+ 'M', 'M',
1177
+ 0x00, 0x2a,
1178
+ 0x00, 0x00, 0x00, 0x08,
1179
+ 0x00, 0x01,
1180
+
1181
+ /* orieatation */
1182
+ 0x01, 0x12,
1183
+ 0x00, 0x03,
1184
+ 0x00, 0x00, 0x00, 0x01,
1185
+ 0x00, 0x00,
1186
+ 0x00, 0x00,
1187
+
1188
+ /* end mark */
1189
+ 0x00, 0x00, 0x00, 0x00,
1190
+ };
1191
+
1192
+ data[24] = (ptr->orientation >> 8) & 0xff;
1193
+ data[25] = (ptr->orientation >> 0) & 0xff;
1194
+
1195
+ jpeg_write_marker(&ptr->cinfo, JPEG_APP1, data, sizeof(data));
643
1196
  }
644
1197
 
645
1198
  static VALUE
646
- rb_decoder_alloc(VALUE self)
1199
+ do_encode(VALUE _ptr)
647
1200
  {
648
- jpeg_decode_t* ptr;
1201
+ VALUE ret;
1202
+ jpeg_encode_t* ptr;
1203
+ uint8_t* data;
1204
+ int nrow;
649
1205
 
650
- ptr = ALLOC(jpeg_decode_t);
651
- memset(ptr, 0, sizeof(*ptr));
1206
+ /*
1207
+ * initialize
1208
+ */
1209
+ ret = Qnil;
1210
+ ptr = (jpeg_encode_t*)_ptr;
1211
+ data = (uint8_t*)RSTRING_PTR(ptr->data);
1212
+
1213
+ /*
1214
+ * do encode
1215
+ */
1216
+ if (setjmp(ptr->err_mgr.jmpbuf)) {
1217
+ /*
1218
+ * when error occurred
1219
+ */
1220
+ rb_raise(encerr_klass, "%s", ptr->err_mgr.msg);
1221
+
1222
+ } else {
1223
+ /*
1224
+ * normal path
1225
+ */
1226
+ jpeg_start_compress(&ptr->cinfo, TRUE);
1227
+ SET_FLAG(ptr, F_START);
1228
+
1229
+ if (ptr->orientation != 0) {
1230
+ put_exif_tags(ptr);
1231
+ }
1232
+
1233
+ while (ptr->cinfo.next_scanline < ptr->cinfo.image_height) {
1234
+ nrow = ptr->cinfo.image_height - ptr->cinfo.next_scanline;
1235
+ if (nrow > UNIT_LINES) nrow = UNIT_LINES;
1236
+
1237
+ push_rows(ptr, data, nrow);
1238
+
1239
+ jpeg_write_scanlines(&ptr->cinfo, ptr->array, nrow);
1240
+ data += (ptr->stride * nrow);
1241
+ }
1242
+
1243
+ /*
1244
+ * build return data
1245
+ */
1246
+ ret = rb_str_buf_new(ptr->buf.size);
1247
+ rb_str_set_len(ret, ptr->buf.size);
1248
+
1249
+ memcpy(RSTRING_PTR(ret), ptr->buf.mem, ptr->buf.size);
1250
+ }
1251
+
1252
+ return ret;
1253
+ }
1254
+
1255
+ /**
1256
+ * encode data
1257
+ *
1258
+ * @overload encode(raw)
1259
+ *
1260
+ * @param raw [String] raw image data to encode.
1261
+ *
1262
+ * @return [String] encoded JPEG data.
1263
+ */
1264
+ static VALUE
1265
+ rb_encoder_encode(VALUE self, VALUE data)
1266
+ {
1267
+ VALUE ret;
1268
+ int state;
1269
+ jpeg_encode_t* ptr;
1270
+
1271
+ /*
1272
+ * initialize
1273
+ */
1274
+ ret = Qnil;
1275
+ state = 0;
1276
+
1277
+ TypedData_Get_Struct(self, jpeg_encode_t, &jpeg_encoder_data_type, ptr);
1278
+
1279
+ /*
1280
+ * argument check
1281
+ */
1282
+ Check_Type(data, T_STRING);
1283
+
1284
+ if (RSTRING_LEN(data) < ptr->data_size) {
1285
+ ARGUMENT_ERROR("image data is too short");
1286
+ }
1287
+
1288
+ if (RSTRING_LEN(data) > ptr->data_size) {
1289
+ ARGUMENT_ERROR("image data is too large");
1290
+ }
1291
+
1292
+ /*
1293
+ * alloc memory
1294
+ */
1295
+ jpeg_mem_dest(&ptr->cinfo, &ptr->buf.mem, &ptr->buf.size);
1296
+ if (ptr->buf.mem == NULL) {
1297
+ RUNTIME_ERROR("jpeg_mem_dest() failed");
1298
+ }
1299
+
1300
+ /*
1301
+ * prepare
1302
+ */
1303
+ SET_DATA(ptr, data);
1304
+
1305
+ /*
1306
+ * do encode
1307
+ */
1308
+ ret = rb_protect(do_encode, (VALUE)ptr, &state);
1309
+
1310
+ /*
1311
+ * post process
1312
+ */
1313
+ if (TEST_FLAG(ptr, F_START)) {
1314
+ jpeg_finish_compress(&ptr->cinfo);
1315
+ CLR_FLAG(ptr, F_START);
1316
+ }
1317
+
1318
+ CLR_DATA(ptr);
652
1319
 
653
- ptr->format = FMT_RGB;
654
- ptr->need_meta = !0;
655
- ptr->expand_colormap = 0;
1320
+ if (ptr->buf.mem != NULL) {
1321
+ free(ptr->buf.mem);
656
1322
 
657
- ptr->out_color_space = JCS_RGB;
1323
+ ptr->buf.mem = NULL;
1324
+ ptr->buf.size = 0;
1325
+ }
1326
+
1327
+ if (state != 0) rb_jump_tag(state);
1328
+
1329
+ return ret;
1330
+ }
1331
+
1332
+ static void
1333
+ rb_decoder_mark(void* _ptr)
1334
+ {
1335
+ jpeg_decode_t* ptr;
658
1336
 
659
- ptr->scale_num = 1;
660
- ptr->scale_denom = 1;
1337
+ ptr = (jpeg_decode_t*)_ptr;
661
1338
 
662
- ptr->out_color_components = 3;
663
- ptr->output_gamma = 0.0;
664
- ptr->buffered_image = FALSE;
665
- ptr->do_fancy_upsampling = FALSE;
666
- ptr->do_block_smoothing = FALSE;
667
- ptr->quantize_colors = FALSE;
668
- ptr->dither_mode = JDITHER_NONE;
669
- ptr->dct_method = JDCT_FASTEST;
670
- ptr->desired_number_of_colors = 0;
671
- ptr->enable_1pass_quant = FALSE;
672
- ptr->enable_external_quant = FALSE;
673
- ptr->enable_2pass_quant = FALSE;
1339
+ if (ptr->orientation.buf != Qnil) {
1340
+ rb_gc_mark(ptr->orientation.buf);
1341
+ }
674
1342
 
675
- return Data_Wrap_Struct(decoder_klass, 0, rb_decoder_free, ptr);
1343
+ if (ptr->data != Qnil) {
1344
+ rb_gc_mark(ptr->data);
1345
+ }
676
1346
  }
677
1347
 
678
1348
  static void
679
- eval_decoder_opt_pixel_format(jpeg_decode_t* ptr, VALUE opt)
1349
+ rb_decoder_free(void* _ptr)
1350
+ {
1351
+ jpeg_decode_t* ptr;
1352
+
1353
+ ptr = (jpeg_decode_t*)_ptr;
1354
+
1355
+ if (ptr->array != NULL) {
1356
+ free(ptr->array);
1357
+ }
1358
+
1359
+ ptr->orientation.buf = Qnil;
1360
+ ptr->data = Qnil;
1361
+
1362
+ if (TEST_FLAG(ptr, F_CREAT)) {
1363
+ jpeg_destroy_decompress(&ptr->cinfo);
1364
+ }
1365
+
1366
+ free(ptr);
1367
+ }
1368
+
1369
+ static size_t
1370
+ rb_decoder_size(const void* ptr)
1371
+ {
1372
+ size_t ret;
1373
+
1374
+ ret = sizeof(jpeg_decode_t);
1375
+
1376
+ return ret;
1377
+ }
1378
+
1379
+ #if RUBY_API_VERSION_CODE > 20600
1380
+ static const rb_data_type_t jpeg_decoder_data_type = {
1381
+ "libjpeg-ruby decoder object", // wrap_struct_name
1382
+ {
1383
+ rb_decoder_mark, // function.dmark
1384
+ rb_decoder_free, // function.dfree
1385
+ rb_decoder_size, // function.dsize
1386
+ NULL, // function.dcompact
1387
+ {NULL}, // function.reserved
1388
+ },
1389
+ NULL, // parent
1390
+ NULL, // data
1391
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
1392
+ };
1393
+ #else /* RUBY_API_VERSION_CODE > 20600 */
1394
+ static const rb_data_type_t jpeg_decoder_data_type = {
1395
+ "libjpeg-ruby decoder object", // wrap_struct_name
1396
+ {
1397
+ rb_decoder_mark, // function.dmark
1398
+ rb_decoder_free, // function.dfree
1399
+ rb_decoder_size, // function.dsize
1400
+ {NULL, NULL}, // function.reserved
1401
+ },
1402
+ NULL, // parent
1403
+ NULL, // data
1404
+ (VALUE)RUBY_TYPED_FREE_IMMEDIATELY // flags
1405
+ };
1406
+ #endif /* RUBY_API_VERSION_CODE > 20600 */
1407
+
1408
+ static VALUE
1409
+ rb_decoder_alloc(VALUE self)
1410
+ {
1411
+ jpeg_decode_t* ptr;
1412
+
1413
+ ptr = ALLOC(jpeg_decode_t);
1414
+ memset(ptr, 0, sizeof(*ptr));
1415
+
1416
+ ptr->flags = DEFAULT_DECODE_FLAGS;
1417
+
1418
+ return TypedData_Wrap_Struct(decoder_klass, &jpeg_decoder_data_type, ptr);
1419
+ }
1420
+
1421
+ static VALUE
1422
+ eval_decoder_pixel_format_opt(jpeg_decode_t* ptr, VALUE opt)
680
1423
  {
1424
+ VALUE ret;
681
1425
  int format;
682
1426
  int color_space;
683
1427
  int components;
684
1428
 
685
- if (opt != Qundef) {
1429
+ ret = Qnil;
1430
+
1431
+ switch (TYPE(opt)) {
1432
+ case T_UNDEF:
1433
+ format = FMT_RGB;
1434
+ color_space = JCS_RGB;
1435
+ components = 3;
1436
+ break;
1437
+
1438
+ case T_STRING:
1439
+ case T_SYMBOL:
686
1440
  if(EQ_STR(opt, "RGB") || EQ_STR(opt, "RGB24")) {
687
1441
  format = FMT_RGB;
688
1442
  color_space = JCS_RGB;
689
1443
  components = 3;
690
1444
 
691
1445
  } else if (EQ_STR(opt, "YUV422") || EQ_STR(opt, "YUYV")) {
692
- format = FMT_YUV422;
693
- color_space = JCS_YCbCr;
694
- components = 3;
1446
+ ret = create_not_implement_error( "not implemented colorspace");
695
1447
 
696
1448
  } else if (EQ_STR(opt, "RGB565")) {
697
- format = FMT_RGB565;
698
- color_space = JCS_RGB;
699
- components = 3;
1449
+ ret = create_not_implement_error( "not implemented colorspace");
700
1450
 
701
1451
  } else if (EQ_STR(opt, "GRAYSCALE")) {
702
1452
  format = FMT_GRAYSCALE;
@@ -728,615 +1478,2050 @@ eval_decoder_opt_pixel_format(jpeg_decode_t* ptr, VALUE opt)
728
1478
  color_space = JCS_EXT_BGRX;
729
1479
  components = 4;
730
1480
 
731
- } else {
732
- ARGUMENT_ERROR("Unsupportd :pixel_format option value.");
733
- }
1481
+ } else {
1482
+ ret = create_argument_error("unsupportd :pixel_format option value");
1483
+ }
1484
+ break;
1485
+
1486
+ default:
1487
+ ret = create_type_error("unsupportd :pixel_format option type");
1488
+ break;
1489
+ }
1490
+
1491
+ if (!RTEST(ret)) {
1492
+ ptr->format = format;
1493
+ ptr->out_color_space = color_space;
1494
+ ptr->out_color_components = components;
1495
+ }
1496
+
1497
+ return ret;
1498
+ }
1499
+
1500
+ static VALUE
1501
+ eval_decoder_output_gamma_opt(jpeg_decode_t* ptr, VALUE opt)
1502
+ {
1503
+ VALUE ret;
1504
+ double gamma;
1505
+
1506
+ ret = Qnil;
1507
+
1508
+ switch (TYPE(opt)) {
1509
+ case T_UNDEF:
1510
+ gamma = 0.0;
1511
+ break;
1512
+
1513
+ case T_FIXNUM:
1514
+ case T_FLOAT:
1515
+ if (isnan(NUM2DBL(opt)) || isinf(NUM2DBL(opt))) {
1516
+ ret = create_argument_error("unsupported :output_gamma value");
1517
+ } else {
1518
+ gamma = NUM2DBL(opt);
1519
+ }
1520
+ break;
1521
+
1522
+ default:
1523
+ ret = create_type_error("unsupported :output_gamma type");
1524
+ break;
1525
+ }
1526
+
1527
+ if (!RTEST(ret)) ptr->output_gamma = gamma;
1528
+
1529
+ return ret;
1530
+ }
1531
+
1532
+ static VALUE
1533
+ eval_decoder_do_fancy_upsampling_opt(jpeg_decode_t* ptr, VALUE opt)
1534
+ {
1535
+ if (opt != Qundef && RTEST(opt)) {
1536
+ ptr->do_fancy_upsampling = TRUE;
1537
+ } else {
1538
+ ptr->do_fancy_upsampling = FALSE;
1539
+ }
1540
+
1541
+ return Qnil;
1542
+ }
1543
+
1544
+ static VALUE
1545
+ eval_decoder_do_smoothing_opt(jpeg_decode_t* ptr, VALUE opt)
1546
+ {
1547
+ if (opt != Qundef && RTEST(opt)) {
1548
+ ptr->do_block_smoothing = TRUE;
1549
+ } else {
1550
+ ptr->do_block_smoothing = FALSE;
1551
+ }
1552
+
1553
+ return Qnil;
1554
+ }
1555
+
1556
+ static VALUE
1557
+ eval_decoder_dither_opt( jpeg_decode_t* ptr, VALUE opt)
1558
+ {
1559
+ VALUE ret;
1560
+ VALUE tmp;
1561
+ int mode;
1562
+ int quant;
1563
+ int pass2;
1564
+ int ncol;
1565
+
1566
+ ret = Qnil;
1567
+
1568
+ switch (TYPE(opt)) {
1569
+ case T_UNDEF:
1570
+ mode = JDITHER_NONE;
1571
+ quant = FALSE;
1572
+ ncol = 0;
1573
+ pass2 = FALSE;
1574
+ break;
1575
+
1576
+ case T_ARRAY:
1577
+ if (RARRAY_LEN(opt) != 3) {
1578
+ ret = create_argument_error(":dither invalid size");
1579
+
1580
+ } else do {
1581
+ /*
1582
+ * dither mode
1583
+ */
1584
+ tmp = rb_ary_entry(opt, 0);
1585
+ if (TYPE(tmp) != T_STRING && TYPE(tmp) != T_SYMBOL) {
1586
+ ret = create_type_error("unsupported dither mode type");
1587
+ break;
1588
+
1589
+ } else if (EQ_STR(tmp, "NONE")) {
1590
+ mode = JDITHER_NONE;
1591
+ quant = FALSE;
1592
+
1593
+ } else if(EQ_STR(tmp, "ORDERED")) {
1594
+ mode = JDITHER_ORDERED;
1595
+ quant = TRUE;
1596
+
1597
+ } else if(EQ_STR(tmp, "FS")) {
1598
+ mode = JDITHER_FS;
1599
+ quant = TRUE;
1600
+
1601
+ } else {
1602
+ ret = create_argument_error("dither mode is illeagal value.");
1603
+ break;
1604
+ }
1605
+
1606
+ /*
1607
+ * 2 pass flag
1608
+ */
1609
+ pass2 = (RTEST(rb_ary_entry(opt, 1)))? TRUE: FALSE;
1610
+
1611
+ /*
1612
+ * number of color
1613
+ */
1614
+ tmp = rb_ary_entry(opt, 2);
1615
+ if (TYPE(tmp) != T_FIXNUM) {
1616
+ ret = create_type_error("unsupported number of colors type");
1617
+ break;
1618
+
1619
+ } else if (FIX2LONG(tmp) < 8) {
1620
+ ret = create_range_error("number of colors less than 0");
1621
+ break;
1622
+
1623
+ } else if (FIX2LONG(tmp) > 256) {
1624
+ ret = create_range_error("number of colors greater than 256");
1625
+ break;
1626
+
1627
+ } else {
1628
+ ncol = FIX2INT(tmp);
1629
+ }
1630
+ } while (0);
1631
+ break;
1632
+
1633
+ default:
1634
+ ret = create_type_error("unsupported :dither type");
1635
+ break;
1636
+ }
1637
+
1638
+ if (!RTEST(ret)) {
1639
+ ptr->dither_mode = mode;
1640
+ ptr->quantize_colors = quant;
1641
+ ptr->two_pass_quantize = pass2;
1642
+ ptr->desired_number_of_colors = ncol;
1643
+
1644
+ if (mode != JDITHER_NONE) SET_FLAG(ptr, F_DITHER);
1645
+ }
1646
+
1647
+ return ret;
1648
+ }
1649
+
1650
+ #if 0
1651
+ static void
1652
+ eval_decoder_use_1pass_quantizer_opt(jpeg_decode_t* ptr, VALUE opt)
1653
+ {
1654
+ if (opt != Qundef && RTEST(opt)) {
1655
+ ptr->enable_1pass_quant = TRUE;
1656
+ } else {
1657
+ ptr->enable_1pass_quant = FALSE;
1658
+ }
1659
+
1660
+ return Qnil;
1661
+ }
1662
+
1663
+ static VALUE
1664
+ eval_decoder_use_external_colormap_opt(jpeg_decode_t* ptr, VALUE opt)
1665
+ {
1666
+ if (opt != Qundef && RTEST(opt)) {
1667
+ ptr->enable_external_quant = TRUE;
1668
+ } else {
1669
+ ptr->enable_external_quant = FALSE;
1670
+ }
1671
+ }
1672
+
1673
+ return Qnil;
1674
+ }
1675
+
1676
+ static VALUE
1677
+ eval_decoder_use_2pass_quantizer_opt(jpeg_decode_t* ptr, VALUE opt)
1678
+ {
1679
+ if (opt != Qundef && RTEST(opt)) {
1680
+ ptr->enable_2pass_quant = TRUE;
1681
+ } else {
1682
+ ptr->enable_2pass_quant = FALSE;
1683
+ }
1684
+ }
1685
+
1686
+ return Qnil;
1687
+ }
1688
+ #endif
1689
+
1690
+ static VALUE
1691
+ eval_decoder_without_meta_opt(jpeg_decode_t* ptr, VALUE opt)
1692
+ {
1693
+ if (opt != Qundef && RTEST(opt)) {
1694
+ CLR_FLAG(ptr, F_NEED_META);
1695
+ } else {
1696
+ SET_FLAG(ptr, F_NEED_META);
1697
+ }
1698
+
1699
+ return Qnil;
1700
+ }
1701
+
1702
+ static VALUE
1703
+ eval_decoder_expand_colormap_opt(jpeg_decode_t* ptr, VALUE opt)
1704
+ {
1705
+ if (opt != Qundef && RTEST(opt)) {
1706
+ SET_FLAG(ptr, F_EXPAND_COLORMAP);
1707
+ } else {
1708
+ CLR_FLAG(ptr, F_EXPAND_COLORMAP);
1709
+ }
1710
+
1711
+ return Qnil;
1712
+ }
1713
+
1714
+
1715
+ static VALUE
1716
+ eval_decoder_scale_opt(jpeg_decode_t* ptr, VALUE opt)
1717
+ {
1718
+ VALUE ret;
1719
+ int scale_num;
1720
+ int scale_denom;
1721
+
1722
+ ret = Qnil;
1723
+
1724
+ switch (TYPE(opt)) {
1725
+ case T_UNDEF:
1726
+ scale_num = 1;
1727
+ scale_denom = 1;
1728
+ break;
1729
+
1730
+ case T_FIXNUM:
1731
+ if (FIX2LONG(opt) <= 0) {
1732
+ ret = create_range_error(":scale less equal 0");
1733
+
1734
+ } else {
1735
+ scale_num = FIX2INT(opt) * 1000;
1736
+ scale_denom = 1000;
1737
+ }
1738
+ break;
1739
+
1740
+ case T_FLOAT:
1741
+ if (isnan(NUM2DBL(opt)) || isinf(NUM2DBL(opt))) {
1742
+ ret = create_argument_error("unsupportd :quality option value");
1743
+
1744
+ } else if (NUM2DBL(opt) <= 0.0) {
1745
+ ret = create_range_error(":scale less equal 0");
1746
+
1747
+ } else {
1748
+ scale_num = (int)(NUM2DBL(opt) * 1000.0);
1749
+ scale_denom = 1000;
1750
+ }
1751
+ break;
1752
+
1753
+ case T_RATIONAL:
1754
+ scale_num = (int)FIX2LONG(rb_rational_num(opt));
1755
+ scale_denom = (int)FIX2LONG(rb_rational_den(opt));
1756
+ break;
1757
+
1758
+ default:
1759
+ ret = create_type_error("unsupportd :scale option type");
1760
+ break;
1761
+ }
1762
+
1763
+ if (!RTEST(ret)) {
1764
+ ptr->scale_num = scale_num;
1765
+ ptr->scale_denom = scale_denom;
1766
+ }
1767
+
1768
+ return ret;
1769
+ }
1770
+
1771
+ static VALUE
1772
+ eval_decoder_dct_method_opt(jpeg_decode_t* ptr, VALUE opt)
1773
+ {
1774
+ VALUE ret;
1775
+ int dct_method;
1776
+
1777
+ ret = Qnil;
1778
+
1779
+ switch (TYPE(opt)) {
1780
+ case T_UNDEF:
1781
+ dct_method = JDCT_FASTEST;
1782
+ break;
1783
+
1784
+ case T_STRING:
1785
+ case T_SYMBOL:
1786
+ if (EQ_STR(opt, "FASTEST")) {
1787
+ dct_method = JDCT_FASTEST;
1788
+
1789
+ } else if (EQ_STR(opt, "ISLOW")) {
1790
+ dct_method = JDCT_ISLOW;
1791
+
1792
+ } else if (EQ_STR(opt, "IFAST")) {
1793
+ dct_method = JDCT_IFAST;
1794
+
1795
+ } else if (EQ_STR(opt, "FLOAT")) {
1796
+ dct_method = JDCT_FLOAT;
1797
+
1798
+ } else {
1799
+ ret = create_argument_error("unsupportd :dct_method option value");
1800
+ }
1801
+ break;
1802
+
1803
+ default:
1804
+ ret = create_type_error("unsupportd :dct_method option type");
1805
+ break;
1806
+ }
1807
+
1808
+ if (!RTEST(ret)) ptr->dct_method = dct_method;
1809
+
1810
+ return ret;
1811
+ }
1812
+
1813
+ static VALUE
1814
+ eval_decoder_with_exif_tags_opt(jpeg_decode_t* ptr, VALUE opt)
1815
+ {
1816
+ if (opt != Qundef && RTEST(opt)) {
1817
+ SET_FLAG(ptr, F_PARSE_EXIF);
1818
+ } else {
1819
+ CLR_FLAG(ptr, F_PARSE_EXIF);
1820
+ }
1821
+
1822
+ return Qnil;
1823
+ }
1824
+
1825
+ static VALUE
1826
+ eval_decoder_orientation_opt(jpeg_decode_t* ptr, VALUE opt)
1827
+ {
1828
+ if (opt != Qundef && RTEST(opt)) {
1829
+ SET_FLAG(ptr, F_APPLY_ORIENTATION);
1830
+ } else {
1831
+ CLR_FLAG(ptr, F_APPLY_ORIENTATION);
1832
+ }
1833
+
1834
+ return Qnil;
1835
+ }
1836
+
1837
+ static VALUE
1838
+ set_decoder_context( jpeg_decode_t* ptr, VALUE opt)
1839
+ {
1840
+ VALUE ret;
1841
+ VALUE opts[N(decoder_opts_ids)];
1842
+ JSAMPARRAY ary;
1843
+
1844
+ /*
1845
+ * initialize
1846
+ */
1847
+ ret = Qnil;
1848
+ ary = NULL;
1849
+
1850
+ /*
1851
+ * parse options
1852
+ */
1853
+ do {
1854
+ rb_get_kwargs(opt, decoder_opts_ids, 0, N(decoder_opts_ids), opts);
1855
+
1856
+ /*
1857
+ * set context
1858
+ */
1859
+ ret = eval_decoder_pixel_format_opt(ptr, opts[0]);
1860
+ if (RTEST(ret)) break;
1861
+
1862
+ ret = eval_decoder_output_gamma_opt(ptr, opts[1]);
1863
+ if (RTEST(ret)) break;
1864
+
1865
+ ret = eval_decoder_do_fancy_upsampling_opt(ptr, opts[2]);
1866
+ if (RTEST(ret)) break;
1867
+
1868
+ ret = eval_decoder_do_smoothing_opt(ptr, opts[3]);
1869
+ if (RTEST(ret)) break;
1870
+
1871
+ ret = eval_decoder_dither_opt(ptr, opts[4]);
1872
+ if (RTEST(ret)) break;
1873
+
1874
+ #if 0
1875
+ ret = eval_decoder_use_1pass_quantizer_opt(ptr, opts[5]);
1876
+ if (RTEST(ret)) break;
1877
+
1878
+ ret = eval_decoder_use_external_colormap_opt(ptr, opts[6]);
1879
+ if (RTEST(ret)) break;
1880
+
1881
+ ret = eval_decoder_use_2pass_quantizer_opt(ptr, opts[7]);
1882
+ if (RTEST(ret)) break;
1883
+ #endif
1884
+
1885
+ ret = eval_decoder_without_meta_opt(ptr, opts[5]);
1886
+ if (RTEST(ret)) break;
1887
+
1888
+ ret = eval_decoder_expand_colormap_opt(ptr, opts[6]);
1889
+ if (RTEST(ret)) break;
1890
+
1891
+ ret = eval_decoder_scale_opt(ptr, opts[7]);
1892
+ if (RTEST(ret)) break;
1893
+
1894
+ ret = eval_decoder_dct_method_opt(ptr, opts[8]);
1895
+ if (RTEST(ret)) break;
1896
+
1897
+ ret = eval_decoder_with_exif_tags_opt(ptr, opts[9]);
1898
+ if (RTEST(ret)) break;
1899
+
1900
+ ret = eval_decoder_orientation_opt(ptr, opts[10]);
1901
+ if (RTEST(ret)) break;
1902
+ } while (0);
1903
+
1904
+ /*
1905
+ * alloc memory
1906
+ */
1907
+ if (!RTEST(ret)) {
1908
+ ary = ALLOC_ARRAY();
1909
+ if (ary == NULL) ret = create_memory_error();
1910
+ }
1911
+
1912
+ /*
1913
+ * set the rest context parameter
1914
+ */
1915
+ if (!RTEST(ret)) {
1916
+ ptr->err_mgr.jerr.output_message = output_message;
1917
+ ptr->err_mgr.jerr.emit_message = emit_message;
1918
+ ptr->err_mgr.jerr.error_exit = error_exit;
1919
+
1920
+ // 現時点でオプションでの対応をおこなっていないので
1921
+ // ここで値を設定
1922
+ ptr->enable_1pass_quant = FALSE;
1923
+ ptr->enable_external_quant = FALSE;
1924
+ ptr->enable_2pass_quant = FALSE;
1925
+ ptr->buffered_image = FALSE;
1926
+
1927
+ #if 0
1928
+ if (ptr->enable_1pass_quant == TRUE ||
1929
+ ptr->enable_external_quant == TRUE ||
1930
+ ptr->enable_2pass_quant == TRUE) {
1931
+ ptr->buffered_image = TRUE;
1932
+
1933
+ } else {
1934
+ ptr->buffered_image = FALSE;
1935
+ }
1936
+ #endif
1937
+
1938
+ ptr->array = ary;
1939
+ ptr->data = Qnil;
1940
+ ptr->orientation.value = 0;
1941
+ ptr->orientation.buf = Qnil;
1942
+ }
1943
+
1944
+ /*
1945
+ * setup libjpeg
1946
+ */
1947
+ if (!RTEST(ret)) {
1948
+ jpeg_create_decompress(&ptr->cinfo);
1949
+ SET_FLAG(ptr, F_CREAT);
1950
+
1951
+ ptr->cinfo.err = jpeg_std_error(&ptr->err_mgr.jerr);
1952
+ }
1953
+
1954
+ return ret;
1955
+ }
1956
+
1957
+ /**
1958
+ * initialize decoder object
1959
+ *
1960
+ * @overload initialize(opts)
1961
+ *
1962
+ * @param opts [Hash] options to initialize object
1963
+ *
1964
+ * @option opts [Symbol] :pixel_format
1965
+ * specifies the format of the output image. possible values are:
1966
+ * YUV422 YUYV RGB565 RGB RGB24 BGR BGR24 YUV444 YCbCr
1967
+ * RGBX RGB32 BGRX BGR32 GRAYSCALE
1968
+ *
1969
+ * @option opts [Float] :output_gamma
1970
+ *
1971
+ * @option opts [Boolean] :fancy_upsampling
1972
+ *
1973
+ * @option opts [Boolean] :do_smoothing
1974
+ *
1975
+ * @option opts [Array] :dither
1976
+ * specifies dithering parameters. A 3-elements array.
1977
+ * specify the dither type as a string for the 1st element,
1978
+ * whether to use 2-pass quantize for the 2nd element as a boolean,
1979
+ * and the number of colors used for the 3rd element as an integer
1980
+ * from 16 to 256.
1981
+ *
1982
+ * @option opts [Boolean] :without_meta
1983
+ * specifies whether or not to include meta information in the
1984
+ * output data. If true, no meta-information is output.
1985
+ *
1986
+ * @option opts [Boolean] :expand_colormap
1987
+ * specifies whether to expand the color map. If dither is specified,
1988
+ * the output will be a color number of 1 byte per pixel, but if this
1989
+ * option is set to true, the output will be expanded to color information.
1990
+ *
1991
+ * @option opts [Ratioanl] :scale
1992
+ *
1993
+ * @option opts [Symbol] :dct_method
1994
+ * specifies how decoding is handled. possible values are:
1995
+ * FASTEST ISLOW IFAST FLOAT
1996
+ *
1997
+ * @option opts [Boolean] :with_exif_tags
1998
+ * specifies whether to include Exif tag information in the output data.
1999
+ * set this option to true to parse the Exif tag information and include
2000
+ * it in the meta information output.
2001
+ *
2002
+ * @option opts [Boolean] :with_exif
2003
+ * alias to :with_exif_tags option.
2004
+ */
2005
+ static VALUE
2006
+ rb_decoder_initialize( int argc, VALUE *argv, VALUE self)
2007
+ {
2008
+ jpeg_decode_t* ptr;
2009
+ VALUE exc;
2010
+ VALUE opt;
2011
+
2012
+ /*
2013
+ * initialize
2014
+ */
2015
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
2016
+
2017
+ /*
2018
+ * parse arguments
2019
+ */
2020
+ rb_scan_args( argc, argv, "0:", &opt);
2021
+
2022
+ /*
2023
+ * set context
2024
+ */
2025
+ exc = set_decoder_context(ptr, opt);
2026
+
2027
+ /*
2028
+ * post process
2029
+ */
2030
+ if (RTEST(exc)) rb_exc_raise(exc);
2031
+
2032
+ return Qtrue;
2033
+ }
2034
+
2035
+ static VALUE
2036
+ rb_decoder_set(VALUE self, VALUE opt)
2037
+ {
2038
+ jpeg_decode_t* ptr;
2039
+ VALUE exc;
2040
+
2041
+ /*
2042
+ * initialize
2043
+ */
2044
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
2045
+
2046
+ /*
2047
+ * check argument
2048
+ */
2049
+ Check_Type(opt, T_HASH);
2050
+
2051
+ /*
2052
+ * set context
2053
+ */
2054
+ exc = set_decoder_context(ptr, opt);
2055
+
2056
+ /*
2057
+ * post process
2058
+ */
2059
+ if (RTEST(exc)) rb_exc_raise(exc);
2060
+
2061
+ return Qtrue;
2062
+ }
2063
+
2064
+ static VALUE
2065
+ get_colorspace_str( J_COLOR_SPACE cs)
2066
+ {
2067
+ const char* cstr;
2068
+
2069
+ switch (cs) {
2070
+ case JCS_GRAYSCALE:
2071
+ cstr = "GRAYSCALE";
2072
+ break;
2073
+
2074
+ case JCS_RGB:
2075
+ cstr = "RGB";
2076
+ break;
2077
+
2078
+ case JCS_YCbCr:
2079
+ cstr = "YCbCr";
2080
+ break;
2081
+
2082
+ case JCS_CMYK:
2083
+ cstr = "CMYK";
2084
+ break;
2085
+
2086
+ case JCS_YCCK:
2087
+ cstr = "YCCK";
2088
+ break;
2089
+ #if JPEG_LIB_VERSION < 90
2090
+ case JCS_EXT_RGB:
2091
+ cstr = "RGB";
2092
+ break;
2093
+
2094
+ case JCS_EXT_RGBX:
2095
+ cstr = "RGBX";
2096
+ break;
2097
+
2098
+ case JCS_EXT_BGR:
2099
+ cstr = "BGR";
2100
+ break;
2101
+
2102
+ case JCS_EXT_BGRX:
2103
+ cstr = "BGRX";
2104
+ break;
2105
+
2106
+ case JCS_EXT_XBGR:
2107
+ cstr = "XBGR";
2108
+ break;
2109
+
2110
+ case JCS_EXT_XRGB:
2111
+ cstr = "XRGB";
2112
+ break;
2113
+
2114
+ case JCS_EXT_RGBA:
2115
+ cstr = "RGBA";
2116
+ break;
2117
+
2118
+ case JCS_EXT_BGRA:
2119
+ cstr = "BGRA";
2120
+ break;
2121
+
2122
+ case JCS_EXT_ABGR:
2123
+ cstr = "ABGR";
2124
+ break;
2125
+
2126
+ case JCS_EXT_ARGB:
2127
+ cstr = "ARGB";
2128
+ break;
2129
+ #endif /* JPEG_LIB_VERSION < 90 */
2130
+
2131
+ default:
2132
+ cstr = "UNKNOWN";
2133
+ break;
2134
+ }
2135
+
2136
+ return rb_str_new_cstr(cstr);
2137
+ }
2138
+
2139
+ typedef struct {
2140
+ int be;
2141
+ uint8_t* head;
2142
+ uint8_t* cur;
2143
+ size_t size;
2144
+
2145
+ struct {
2146
+ tag_entry_t* tbl;
2147
+ size_t n;
2148
+ } tags;
2149
+
2150
+ int next;
2151
+ } exif_t;
2152
+
2153
+ static uint16_t
2154
+ get_u16(uint8_t* src, int be)
2155
+ {
2156
+ uint16_t ret;
2157
+
2158
+ if (be) {
2159
+ ret = (((src[0] << 8) & 0xff00)|
2160
+ ((src[1] << 0) & 0x00ff));
2161
+ } else {
2162
+ ret = (((src[1] << 8) & 0xff00)|
2163
+ ((src[0] << 0) & 0x00ff));
2164
+ }
2165
+
2166
+ return ret;
2167
+ }
2168
+
2169
+ /*
2170
+ static int16_t
2171
+ get_s16(uint8_t* src, int be)
2172
+ {
2173
+ int16_t ret;
2174
+
2175
+ if (be) {
2176
+ ret = (((src[0] << 8) & 0xff00)|
2177
+ ((src[1] << 0) & 0x00ff));
2178
+ } else {
2179
+ ret = (((src[1] << 8) & 0xff00)|
2180
+ ((src[0] << 0) & 0x00ff));
2181
+ }
2182
+
2183
+ return ret;
2184
+ }
2185
+ */
2186
+
2187
+ static uint32_t
2188
+ get_u32(uint8_t* src, int be)
2189
+ {
2190
+ uint32_t ret;
2191
+
2192
+ if (be) {
2193
+ ret = (((src[0] << 24) & 0xff000000)|
2194
+ ((src[1] << 16) & 0x00ff0000)|
2195
+ ((src[2] << 8) & 0x0000ff00)|
2196
+ ((src[3] << 0) & 0x000000ff));
2197
+ } else {
2198
+ ret = (((src[3] << 24) & 0xff000000)|
2199
+ ((src[2] << 16) & 0x00ff0000)|
2200
+ ((src[1] << 8) & 0x0000ff00)|
2201
+ ((src[0] << 0) & 0x000000ff));
2202
+ }
2203
+
2204
+ return ret;
2205
+ }
2206
+
2207
+ static int32_t
2208
+ get_s32(uint8_t* src, int be)
2209
+ {
2210
+ int32_t ret;
2211
+
2212
+ if (be) {
2213
+ ret = (((src[0] << 24) & 0xff000000)|
2214
+ ((src[1] << 16) & 0x00ff0000)|
2215
+ ((src[2] << 8) & 0x0000ff00)|
2216
+ ((src[3] << 0) & 0x000000ff));
2217
+ } else {
2218
+ ret = (((src[3] << 24) & 0xff000000)|
2219
+ ((src[2] << 16) & 0x00ff0000)|
2220
+ ((src[1] << 8) & 0x0000ff00)|
2221
+ ((src[0] << 0) & 0x000000ff));
2222
+ }
2223
+
2224
+ return ret;
2225
+ }
2226
+
2227
+ static void
2228
+ exif_increase(exif_t* ptr, size_t size)
2229
+ {
2230
+ ptr->cur += size;
2231
+ ptr->size -= size;
2232
+ }
2233
+
2234
+ static void
2235
+ exif_init(exif_t* ptr, uint8_t* src, size_t size)
2236
+ {
2237
+ int be;
2238
+ uint16_t ident;
2239
+ uint32_t off;
2240
+
2241
+ /*
2242
+ * Check Exif identifier
2243
+ */
2244
+ if (memcmp(src, "Exif\0\0", 6)) {
2245
+ rb_raise(decerr_klass, "invalid exif identifier");
2246
+ }
2247
+
2248
+ /*
2249
+ * Check TIFF header and judge endian
2250
+ */
2251
+ do {
2252
+ if (!memcmp(src + 6, "MM", 2)) {
2253
+ be = !0;
2254
+ break;
2255
+ }
2256
+
2257
+ if (!memcmp(src + 6, "II", 2)) {
2258
+ be = 0;
2259
+ break;
2260
+ }
2261
+
2262
+ rb_raise(decerr_klass, "invalid tiff header");
2263
+ } while (0);
2264
+
2265
+ /*
2266
+ * Check TIFF identifier
2267
+ */
2268
+ ident = get_u16(src + 8, be);
2269
+ if (ident != 0x002a) {
2270
+ rb_raise(decerr_klass, "invalid tiff identifier");
2271
+ }
2272
+
2273
+ /*
2274
+ * get offset for 0th IFD
2275
+ */
2276
+ off = get_u32(src + 10, be);
2277
+ if (off < 8 || off >= size - 6) {
2278
+ rb_raise(decerr_klass, "invalid offset dentifier");
2279
+ }
2280
+
2281
+ /*
2282
+ * initialize Exif context
2283
+ */
2284
+ ptr->be = be;
2285
+ ptr->head = src + 6;
2286
+ ptr->cur = ptr->head + off;
2287
+ ptr->size = size - (6 + off);
2288
+ ptr->tags.tbl = tag_tiff;
2289
+ ptr->tags.n = N(tag_tiff);
2290
+ ptr->next = 0;
2291
+ }
2292
+
2293
+ static void
2294
+ exif_fetch_tag_header(exif_t* ptr, uint16_t* tag, uint16_t* type)
2295
+ {
2296
+ *tag = get_u16(ptr->cur + 0, ptr->be);
2297
+ *type = get_u16(ptr->cur + 2, ptr->be);
2298
+ }
2299
+
2300
+
2301
+ static void
2302
+ exif_fetch_byte_data(exif_t* ptr, VALUE* dst)
2303
+ {
2304
+ VALUE obj;
2305
+
2306
+ int i;
2307
+ uint32_t n;
2308
+ uint8_t* p;
2309
+
2310
+ n = get_u32(ptr->cur + 4, ptr->be);
2311
+ p = ptr->cur + 8;
2312
+
2313
+ switch (n) {
2314
+ case 0:
2315
+ obj = Qnil;
2316
+ break;
2317
+
2318
+ case 1:
2319
+ obj = INT2FIX(*p);
2320
+ break;
2321
+
2322
+ default:
2323
+ p = ptr->head + get_u32(p, ptr->be);
2324
+
2325
+ case 2:
2326
+ case 3:
2327
+ case 4:
2328
+ obj = rb_ary_new_capa(n);
2329
+ for (i = 0; i < (int)n; i++) {
2330
+ rb_ary_push(obj, INT2FIX(p[i]));
2331
+ }
2332
+ break;
2333
+ }
2334
+
2335
+ *dst = obj;
2336
+ }
2337
+
2338
+ static void
2339
+ exif_fetch_ascii_data(exif_t* ptr, VALUE* dst)
2340
+ {
2341
+ VALUE obj;
2342
+
2343
+ uint32_t n;
2344
+ uint8_t* p;
2345
+
2346
+ n = get_u32(ptr->cur + 4, ptr->be);
2347
+ p = ptr->cur + 8;
2348
+
2349
+ if (n > 4) {
2350
+ p = ptr->head + get_u32(p, ptr->be);
2351
+ }
2352
+
2353
+ obj = rb_utf8_str_new((char*)p, n);
2354
+ rb_funcall(obj, rb_intern("strip!"), 0);
2355
+
2356
+ *dst = obj;
2357
+ }
2358
+
2359
+ static void
2360
+ exif_fetch_short_data(exif_t* ptr, VALUE* dst)
2361
+ {
2362
+ VALUE obj;
2363
+
2364
+ int i;
2365
+ uint32_t n;
2366
+ uint8_t* p;
2367
+
2368
+ n = get_u32(ptr->cur + 4, ptr->be);
2369
+ p = ptr->cur + 8;
2370
+
2371
+ switch (n) {
2372
+ case 0:
2373
+ obj = Qnil;
2374
+ break;
2375
+
2376
+ case 1:
2377
+ obj = INT2FIX(get_u16(p, ptr->be));
2378
+ break;
2379
+
2380
+ default:
2381
+ p = ptr->head + get_u32(p, ptr->be);
2382
+
2383
+ case 2:
2384
+ obj = rb_ary_new_capa(n);
2385
+ for (i = 0; i < (int)n; i++) {
2386
+ rb_ary_push(obj, INT2FIX(get_u16(p, ptr->be)));
2387
+ p += 2;
2388
+ }
2389
+ break;
2390
+ }
2391
+
2392
+ *dst = obj;
2393
+ }
2394
+
2395
+ static void
2396
+ exif_fetch_long_data(exif_t* ptr, VALUE* dst)
2397
+ {
2398
+ VALUE obj;
2399
+
2400
+ int i;
2401
+ uint32_t n;
2402
+ uint8_t* p;
2403
+
2404
+ n = get_u32(ptr->cur + 4, ptr->be);
2405
+ p = ptr->cur + 8;
2406
+
2407
+ switch (n) {
2408
+ case 0:
2409
+ obj = Qnil;
2410
+ break;
2411
+
2412
+ case 1:
2413
+ obj = INT2FIX(get_u32(p, ptr->be));
2414
+ break;
2415
+
2416
+ default:
2417
+ p = ptr->head + get_u32(p, ptr->be);
2418
+ obj = rb_ary_new_capa(n);
2419
+ for (i = 0; i < (int)n; i++) {
2420
+ rb_ary_push(obj, INT2FIX(get_u32(p, ptr->be)));
2421
+ p += 4;
2422
+ }
2423
+ break;
2424
+ }
2425
+
2426
+ *dst = obj;
2427
+ }
2428
+
2429
+ static void
2430
+ exif_fetch_rational_data(exif_t* ptr, VALUE* dst)
2431
+ {
2432
+ VALUE obj;
2433
+
2434
+ int i;
2435
+ uint32_t n;
2436
+ uint8_t* p;
2437
+ uint32_t deno;
2438
+ uint32_t num;
2439
+
2440
+ n = get_u32(ptr->cur + 4, ptr->be);
2441
+ p = ptr->head + get_u32(ptr->cur + 8, ptr->be);
2442
+
2443
+ switch (n) {
2444
+ case 0:
2445
+ obj = Qnil;
2446
+ break;
2447
+
2448
+ case 1:
2449
+ num = get_u32(p + 0, ptr->be);
2450
+ deno = get_u32(p + 4, ptr->be);
2451
+ if (num == 0 && deno == 0) {
2452
+ deno = 1;
2453
+ }
2454
+ obj = rb_rational_new(INT2FIX(num), INT2FIX(deno));
2455
+ break;
2456
+
2457
+ default:
2458
+ obj = rb_ary_new_capa(n);
2459
+ for (i = 0; i < (int)n; i++) {
2460
+ num = get_u32(p + 0, ptr->be);
2461
+ deno = get_u32(p + 4, ptr->be);
2462
+ if (num == 0 && deno == 0) {
2463
+ deno = 1;
2464
+ }
2465
+ rb_ary_push(obj, rb_rational_new(INT2FIX(num), INT2FIX(deno)));
2466
+ p += 8;
2467
+ }
2468
+ break;
2469
+ }
2470
+
2471
+ *dst = obj;
2472
+ }
2473
+
2474
+ static void
2475
+ exif_fetch_undefined_data(exif_t* ptr, VALUE* dst)
2476
+ {
2477
+ VALUE obj;
2478
+
2479
+ uint32_t n;
2480
+ uint8_t* p;
2481
+
2482
+ n = get_u32(ptr->cur + 4, ptr->be);
2483
+ p = ptr->cur + 8;
2484
+
2485
+ if (n > 4) {
2486
+ p = ptr->head + get_u32(p, ptr->be);
2487
+ }
2488
+
2489
+ obj = rb_enc_str_new((char*)p, n, rb_ascii8bit_encoding());
2490
+
2491
+ *dst = obj;
2492
+ }
2493
+
2494
+ static void
2495
+ exif_fetch_slong_data(exif_t* ptr, VALUE* dst)
2496
+ {
2497
+ VALUE obj;
2498
+
2499
+ int i;
2500
+ uint32_t n;
2501
+ uint8_t* p;
2502
+
2503
+ n = get_u32(ptr->cur + 4, ptr->be);
2504
+ p = ptr->cur + 8;
2505
+
2506
+ switch (n) {
2507
+ case 0:
2508
+ obj = Qnil;
2509
+ break;
2510
+
2511
+ case 1:
2512
+ obj = INT2FIX(get_s32(p, ptr->be));
2513
+ break;
2514
+
2515
+ default:
2516
+ p = ptr->head + get_u32(p, ptr->be);
2517
+ obj = rb_ary_new_capa(n);
2518
+ for (i = 0; i < (int)n; i++) {
2519
+ rb_ary_push(obj, INT2FIX(get_s32(p, ptr->be)));
2520
+ p += 4;
2521
+ }
2522
+ break;
2523
+ }
2524
+
2525
+ *dst = obj;
2526
+ }
2527
+
2528
+ static void
2529
+ exif_fetch_srational_data(exif_t* ptr, VALUE* dst)
2530
+ {
2531
+ VALUE obj;
2532
+
2533
+ int i;
2534
+ uint32_t n;
2535
+ uint8_t* p;
2536
+ uint32_t deno;
2537
+ uint32_t num;
2538
+
2539
+ n = get_u32(ptr->cur + 4, ptr->be);
2540
+ p = ptr->head + get_u32(ptr->cur + 8, ptr->be);
2541
+
2542
+ switch (n) {
2543
+ case 0:
2544
+ obj = Qnil;
2545
+ break;
2546
+
2547
+ case 1:
2548
+ num = get_s32(p + 0, ptr->be);
2549
+ deno = get_s32(p + 4, ptr->be);
2550
+ if (num == 0 && deno == 0) {
2551
+ deno = 1;
2552
+ }
2553
+ obj = rb_rational_new(INT2FIX(num), INT2FIX(deno));
2554
+ break;
2555
+
2556
+ default:
2557
+ obj = rb_ary_new_capa(n);
2558
+ for (i = 0; i < (int)n; i++) {
2559
+ num = get_s32(p + 0, ptr->be);
2560
+ deno = get_s32(p + 4, ptr->be);
2561
+ if (num == 0 && deno == 0) {
2562
+ deno = 1;
2563
+ }
2564
+ rb_ary_push(obj, rb_rational_new(INT2FIX(num), INT2FIX(deno)));
2565
+ p += 8;
2566
+ }
2567
+ break;
2568
+ }
2569
+
2570
+ *dst = obj;
2571
+ }
2572
+
2573
+ static void
2574
+ exif_fetch_child_ifd(exif_t* ptr, tag_entry_t* tbl, size_t n, exif_t* dst)
2575
+ {
2576
+ uint32_t off;
2577
+
2578
+ off = get_u32(ptr->cur + 8, ptr->be);
2579
+
2580
+ dst->be = ptr->be;
2581
+ dst->head = ptr->head;
2582
+ dst->cur = ptr->head + off;
2583
+ dst->size = ptr->size - off;
2584
+ dst->tags.tbl = tbl;
2585
+ dst->tags.n = n;
2586
+ dst->next = 0;
2587
+ }
2588
+
2589
+ static int
2590
+ exif_read(exif_t* ptr, VALUE dst)
2591
+ {
2592
+ int ret;
2593
+ int i;
2594
+ uint16_t ntag;
2595
+ uint16_t tag;
2596
+ uint16_t type;
2597
+ uint32_t off;
2598
+
2599
+ exif_t child;
2600
+
2601
+ VALUE key;
2602
+ VALUE val;
2603
+
2604
+ ntag = get_u16(ptr->cur, ptr->be);
2605
+ exif_increase(ptr, 2);
2606
+
2607
+ for (i = 0; i < ntag; i++) {
2608
+ exif_fetch_tag_header(ptr, &tag, &type);
2609
+
2610
+ switch (tag) {
2611
+ case 34665: // ExifIFDPointer
2612
+ key = ID2SYM(rb_intern("exif"));
2613
+ val = rb_hash_new();
2614
+
2615
+ exif_fetch_child_ifd(ptr, tag_exif, N(tag_exif), &child);
2616
+ exif_read(&child, val);
2617
+ break;
2618
+
2619
+ case 34853: // GPSInfoIFDPointer
2620
+ key = ID2SYM(rb_intern("gps"));
2621
+ val = rb_hash_new();
2622
+
2623
+ exif_fetch_child_ifd(ptr, tag_gps, N(tag_gps), &child);
2624
+ exif_read(&child, val);
2625
+ break;
2626
+
2627
+ case 40965: // InteroperabilityIFDPointer
2628
+ key = ID2SYM(rb_intern("interoperability"));
2629
+ val = rb_hash_new();
2630
+
2631
+ exif_fetch_child_ifd(ptr, tag_i14y, N(tag_i14y), &child);
2632
+ exif_read(&child, val);
2633
+ break;
2634
+
2635
+ default:
2636
+ key = lookup_tag_symbol(ptr->tags.tbl, ptr->tags.n, tag);
2637
+
2638
+ switch (type) {
2639
+ case 1: // when BYTE
2640
+ exif_fetch_byte_data(ptr, &val);
2641
+ break;
2642
+
2643
+ case 2: // when ASCII
2644
+ exif_fetch_ascii_data(ptr, &val);
2645
+ break;
2646
+
2647
+ case 3: // when SHORT
2648
+ exif_fetch_short_data(ptr, &val);
2649
+ break;
2650
+
2651
+ case 4: // when LONG
2652
+ exif_fetch_long_data(ptr, &val);
2653
+ break;
2654
+
2655
+ case 5: // when RATIONAL
2656
+ exif_fetch_rational_data(ptr, &val);
2657
+ break;
2658
+
2659
+ case 7: // when UNDEFINED
2660
+ exif_fetch_undefined_data(ptr, &val);
2661
+ break;
2662
+
2663
+ case 9: // when SLONG
2664
+ exif_fetch_slong_data(ptr, &val);
2665
+ break;
2666
+
2667
+ case 10: // when SRATIONAL
2668
+ exif_fetch_srational_data(ptr, &val);
2669
+ break;
2670
+
2671
+ default:
2672
+ rb_raise(decerr_klass, "invalid tag data type");
2673
+ }
2674
+ }
2675
+
2676
+ rb_hash_aset(dst, key, val);
2677
+ exif_increase(ptr, 12);
2678
+ }
2679
+
2680
+ off = get_u32(ptr->cur, ptr->be);
2681
+ if (off != 0) {
2682
+ ptr->cur = ptr->head + off;
2683
+ ptr->next = !0;
2684
+ }
2685
+
2686
+ return ret;
2687
+ }
2688
+
2689
+ #define THUMBNAIL_OFFSET ID2SYM(rb_intern("jpeg_interchange_format"))
2690
+ #define THUMBNAIL_SIZE ID2SYM(rb_intern("jpeg_interchange_format_length"))
2691
+
2692
+ static VALUE
2693
+ create_exif_tags_hash(jpeg_decode_t* ptr)
2694
+ {
2695
+ VALUE ret;
2696
+ jpeg_saved_marker_ptr marker;
2697
+ exif_t exif;
2698
+
2699
+ ret = rb_hash_new();
2700
+
2701
+ for (marker = ptr->cinfo.marker_list;
2702
+ marker != NULL; marker = marker->next) {
2703
+
2704
+ if (marker->data_length < 14) continue;
2705
+ if (memcmp(marker->data, "Exif\0\0", 6)) continue;
2706
+
2707
+ /* 0th IFD */
2708
+ exif_init(&exif, marker->data, marker->data_length);
2709
+ exif_read(&exif, ret);
2710
+
2711
+ if (exif.next) {
2712
+ /* when 1th IFD (tumbnail) exist */
2713
+ VALUE info;
2714
+ VALUE off;
2715
+ VALUE size;
2716
+ VALUE data;
2717
+
2718
+ info = rb_hash_new();
2719
+
2720
+ exif_read(&exif, info);
2721
+
2722
+ off = rb_hash_lookup(info, THUMBNAIL_OFFSET);
2723
+ size = rb_hash_lookup(info, THUMBNAIL_SIZE);
2724
+
2725
+ if (TYPE(off) == T_FIXNUM && TYPE(size) == T_FIXNUM) {
2726
+ data = rb_enc_str_new((char*)exif.head + FIX2INT(off),
2727
+ FIX2INT(size), rb_ascii8bit_encoding());
2728
+
2729
+ rb_hash_lookup(info, THUMBNAIL_OFFSET);
2730
+ rb_hash_lookup(info, THUMBNAIL_SIZE);
2731
+ rb_hash_aset(info, ID2SYM(rb_intern("jpeg_interchange")), data);
2732
+ rb_hash_aset(ret, ID2SYM(rb_intern("thumbnail")), info);
2733
+ }
2734
+ }
2735
+ break;
2736
+ }
2737
+
2738
+ return ret;
2739
+ }
2740
+
2741
+ static void
2742
+ pick_exif_orientation(jpeg_decode_t* ptr)
2743
+ {
2744
+ jpeg_saved_marker_ptr marker;
2745
+ int o9n;
2746
+ uint8_t* p;
2747
+ int be;
2748
+ uint32_t off;
2749
+ int i;
2750
+ int n;
2751
+
2752
+ o9n = 0;
2753
+
2754
+ for (marker = ptr->cinfo.marker_list;
2755
+ marker != NULL; marker = marker->next) {
2756
+
2757
+ if (marker->data_length < 14) continue;
2758
+
2759
+ p = marker->data;
2760
+
2761
+ /*
2762
+ * check Exif identifier
2763
+ */
2764
+ if (memcmp(p, "Exif\0\0", 6)) continue;
2765
+
2766
+ /*
2767
+ * check endian marker
2768
+ */
2769
+ if (!memcmp(p + 6, "MM", 2)) {
2770
+ be = !0;
2771
+
2772
+ } else if (!memcmp(p + 6, "II", 2)) {
2773
+ be = 0;
2774
+
2775
+ } else {
2776
+ continue;
2777
+ }
2778
+
2779
+ /*
2780
+ * check TIFF identifier
2781
+ */
2782
+ if (get_u16(p + 8, be) != 0x002a) continue;
2783
+
2784
+ /*
2785
+ * set 0th IFD address
2786
+ */
2787
+ off = get_u32(p + 10, be);
2788
+ if (off < 8 || off >= marker->data_length - 6) continue;
2789
+
2790
+ p += (6 + off);
2791
+
2792
+ /* ここまでくればAPP1がExifタグなので
2793
+ * 0th IFDをなめてOrientationタグを探す */
2794
+
2795
+ n = get_u16(p, be);
2796
+ p += 2;
2797
+
2798
+ for (i = 0; i < n; i++) {
2799
+ int tag;
2800
+ int type;
2801
+ int num;
2802
+
2803
+ tag = get_u16(p + 0, be);
2804
+ type = get_u16(p + 2, be);
2805
+ num = get_u32(p + 4, be);
2806
+
2807
+ if (tag == 0x0112) {
2808
+ if (type == 3 && num == 1) {
2809
+ o9n = get_u16(p + 8, be);
2810
+ goto loop_out;
2811
+
2812
+ } else {
2813
+ fprintf(stderr,
2814
+ "Illeagal orientation tag found [type:%d, num:%d]\n",
2815
+ type,
2816
+ num);
2817
+ }
2818
+ }
2819
+
2820
+ p += 12;
2821
+ }
2822
+ }
2823
+ loop_out:
2824
+
2825
+ ptr->orientation.value = (o9n >= 1 && o9n <= 8)? (o9n - 1): 0;
2826
+ }
2827
+
2828
+ static VALUE
2829
+ create_colormap(jpeg_decode_t* ptr)
2830
+ {
2831
+ VALUE ret;
2832
+ struct jpeg_decompress_struct* cinfo;
2833
+ JSAMPARRAY map;
2834
+ int i; // volatileを外すとaarch64のgcc6でクラッシュする場合がある
2835
+ uint32_t c;
2836
+
2837
+ cinfo = &ptr->cinfo;
2838
+ ret = rb_ary_new_capa(cinfo->actual_number_of_colors);
2839
+ map = cinfo->colormap;
2840
+
2841
+ switch (cinfo->out_color_components) {
2842
+ case 1:
2843
+ for (i = 0; i < cinfo->actual_number_of_colors; i++) {
2844
+ c = map[0][i];
2845
+ rb_ary_push(ret, INT2FIX(c));
2846
+ }
2847
+ break;
2848
+
2849
+ case 2:
2850
+ for (i = 0; i < cinfo->actual_number_of_colors; i++) {
2851
+ c = (map[0][i] << 8) | (map[1][i] << 0);
2852
+ rb_ary_push(ret, INT2FIX(c));
2853
+ }
2854
+ break;
2855
+
2856
+ case 3:
2857
+ for (i = 0; i < cinfo->actual_number_of_colors; i++) {
2858
+ c = (map[0][i] << 16) | (map[1][i] << 8) | (map[2][i] << 0);
2859
+
2860
+ rb_ary_push(ret, INT2FIX(c));
2861
+ }
2862
+ break;
2863
+
2864
+ default:
2865
+ RUNTIME_ERROR("this number of components is not implemented yet");
2866
+ }
2867
+
2868
+ return ret;
2869
+ }
2870
+
2871
+ static VALUE
2872
+ rb_meta_exif_tags(VALUE self)
2873
+ {
2874
+ return rb_ivar_get(self, id_exif_tags);
2875
+ }
2876
+
2877
+ static VALUE
2878
+ create_meta(jpeg_decode_t* ptr)
2879
+ {
2880
+ VALUE ret;
2881
+ struct jpeg_decompress_struct* cinfo;
2882
+ int width;
2883
+ int height;
2884
+ int stride;
2885
+
2886
+ ret = rb_obj_alloc(meta_klass);
2887
+ cinfo = &ptr->cinfo;
2888
+
2889
+ if (TEST_FLAG(ptr, F_APPLY_ORIENTATION) && (ptr->orientation.value & 4)) {
2890
+ width = cinfo->output_height;
2891
+ height = cinfo->output_width;
2892
+ } else {
2893
+ width = cinfo->output_width;
2894
+ height = cinfo->output_height;
2895
+ }
2896
+
2897
+ stride = cinfo->output_width * cinfo->output_components;
2898
+
2899
+ rb_ivar_set(ret, id_width, INT2FIX(width));
2900
+ rb_ivar_set(ret, id_stride, INT2FIX(stride));
2901
+ rb_ivar_set(ret, id_height, INT2FIX(height));
2902
+
2903
+ rb_ivar_set(ret, id_orig_cs, get_colorspace_str(cinfo->jpeg_color_space));
2904
+
2905
+ if (ptr->format == FMT_YVU) {
2906
+ rb_ivar_set(ret, id_out_cs, rb_str_new_cstr("YCrCb"));
2907
+ } else {
2908
+ rb_ivar_set(ret, id_out_cs, get_colorspace_str(cinfo->out_color_space));
2909
+ }
2910
+
2911
+ if (TEST_FLAG_ALL(ptr, F_DITHER | F_EXPAND_COLORMAP)) {
2912
+ rb_ivar_set(ret, id_ncompo, INT2FIX(cinfo->out_color_components));
2913
+ } else {
2914
+ rb_ivar_set(ret, id_ncompo, INT2FIX(cinfo->output_components));
2915
+ }
2916
+
2917
+ if (TEST_FLAG(ptr, F_PARSE_EXIF)) {
2918
+ rb_ivar_set(ret, id_exif_tags, create_exif_tags_hash(ptr));
2919
+ rb_define_singleton_method(ret, "exif_tags", rb_meta_exif_tags, 0);
2920
+ rb_define_singleton_method(ret, "exif", rb_meta_exif_tags, 0);
2921
+ }
2922
+
2923
+ if (TEST_FLAG(ptr, F_DITHER)) {
2924
+ rb_ivar_set(ret, id_colormap, create_colormap(ptr));
2925
+ }
2926
+
2927
+ return ret;
2928
+ }
2929
+
2930
+ static VALUE
2931
+ do_read_header(VALUE _ptr)
2932
+ {
2933
+ VALUE ret;
2934
+ jpeg_decode_t* ptr;
2935
+ uint8_t* data;
2936
+ size_t size;
2937
+
2938
+ /*
2939
+ * initialize
2940
+ */
2941
+ ret = Qnil;
2942
+ ptr = (jpeg_decode_t*)_ptr;
2943
+ data = (uint8_t*)RSTRING_PTR(ptr->data);
2944
+ size = RSTRING_LEN(ptr->data);
2945
+
2946
+ /*
2947
+ * process body
2948
+ */
2949
+ ptr->cinfo.raw_data_out = FALSE;
2950
+ ptr->cinfo.dct_method = JDCT_FLOAT;
2951
+
2952
+ if (setjmp(ptr->err_mgr.jmpbuf)) {
2953
+ /*
2954
+ * when error occurred
2955
+ */
2956
+ rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
2957
+
2958
+ } else {
2959
+ /*
2960
+ * normal path
2961
+ */
2962
+ jpeg_mem_src(&ptr->cinfo, data, size);
2963
+
2964
+ if (TEST_FLAG(ptr, F_PARSE_EXIF | F_APPLY_ORIENTATION)) {
2965
+ jpeg_save_markers(&ptr->cinfo, JPEG_APP1, 0xFFFF);
2966
+ }
2967
+
2968
+ jpeg_read_header(&ptr->cinfo, TRUE);
2969
+ jpeg_calc_output_dimensions(&ptr->cinfo);
2970
+
2971
+ if (TEST_FLAG(ptr, F_APPLY_ORIENTATION)) {
2972
+ pick_exif_orientation(ptr);
2973
+ }
2974
+
2975
+ ret = create_meta(ptr);
2976
+ }
2977
+
2978
+ return ret;
2979
+ }
2980
+
2981
+ /**
2982
+ * read meta data
2983
+ *
2984
+ * @overload read_header(jpeg)
2985
+ *
2986
+ * @param jpeg [String] input data.
2987
+ *
2988
+ * @return [JPEG::Meta] metadata.
2989
+ */
2990
+ static VALUE
2991
+ rb_decoder_read_header(VALUE self, VALUE data)
2992
+ {
2993
+ VALUE ret;
2994
+ jpeg_decode_t* ptr;
2995
+ int state;
2996
+
2997
+ /*
2998
+ * initialize
2999
+ */
3000
+ ret = Qnil;
3001
+ state = 0;
734
3002
 
735
- ptr->format = format;
736
- ptr->out_color_space = color_space;
737
- ptr->out_color_components = components;
738
- }
739
- }
3003
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
740
3004
 
741
- static void
742
- eval_decoder_opt_output_gamma(jpeg_decode_t* ptr, VALUE opt)
743
- {
744
- switch (TYPE(opt)) {
745
- case T_UNDEF:
746
- // Nothing
747
- break;
3005
+ /*
3006
+ * argument check
3007
+ */
3008
+ Check_Type(data, T_STRING);
748
3009
 
749
- case T_FLOAT:
750
- ptr->output_gamma = NUM2DBL(opt);
751
- break;
3010
+ /*
3011
+ * prepare
3012
+ */
3013
+ SET_DATA(ptr, data);
752
3014
 
753
- default:
754
- ARGUMENT_ERROR("Unsupportd :output_gamma option value.");
755
- break;
756
- }
757
- }
3015
+ /*
3016
+ * do encode
3017
+ */
3018
+ ret = rb_protect(do_read_header, (VALUE)ptr, &state);
758
3019
 
759
- static void
760
- eval_decoder_opt_do_fancy_upsampling(jpeg_decode_t* ptr, VALUE opt)
761
- {
762
- switch (TYPE(opt)) {
763
- case T_UNDEF:
764
- // Nothing
765
- break;
3020
+ /*
3021
+ * post process
3022
+ */
3023
+ CLR_DATA(ptr);
766
3024
 
767
- case T_TRUE:
768
- ptr->do_fancy_upsampling = TRUE;
769
- break;
3025
+ if (state != 0) rb_jump_tag(state);
770
3026
 
771
- case T_FALSE:
772
- ptr->do_fancy_upsampling = FALSE;
773
- break;
3027
+ return ret;
3028
+ }
774
3029
 
775
- default:
776
- ARGUMENT_ERROR("Unsupportd :do_fancy_up_sampling option value.");
777
- break;
778
- }
3030
+ static VALUE
3031
+ rb_decode_result_meta(VALUE self)
3032
+ {
3033
+ return rb_ivar_get(self, id_meta);
779
3034
  }
780
3035
 
781
3036
  static void
782
- eval_decoder_opt_do_smoothing(jpeg_decode_t* ptr, VALUE opt)
3037
+ add_meta(VALUE obj, jpeg_decode_t* ptr)
783
3038
  {
784
- switch (TYPE(opt)) {
785
- case T_UNDEF:
786
- // Nothing
787
- break;
788
-
789
- case T_TRUE:
790
- ptr->do_block_smoothing = TRUE;
791
- break;
3039
+ VALUE meta;
792
3040
 
793
- case T_FALSE:
794
- ptr->do_block_smoothing = FALSE;
795
- break;
3041
+ meta = create_meta(ptr);
796
3042
 
797
- default:
798
- ARGUMENT_ERROR("Unsupportd :do_smoothing option value.");
799
- break;
800
- }
3043
+ rb_ivar_set(obj, id_meta, meta);
3044
+ rb_define_singleton_method(obj, "meta", rb_decode_result_meta, 0);
801
3045
  }
802
3046
 
803
- static void
804
- eval_decoder_opt_dither( jpeg_decode_t* ptr, VALUE opt)
3047
+ static VALUE
3048
+ expand_colormap(struct jpeg_decompress_struct* cinfo, uint8_t* src)
805
3049
  {
806
- VALUE dmode;
807
- VALUE pass2;
808
- VALUE n_col;
809
-
810
- if (opt != Qundef) {
811
- if (TYPE(opt) != T_ARRAY) {
812
- ARGUMENT_ERROR("Unsupportd :dither option value.");
813
- }
3050
+ /*
3051
+ * 本関数はcinfo->out_color_componentsが1または3であることを前提に
3052
+ * 作成されています。
3053
+ */
814
3054
 
815
- if (RARRAY_LEN(opt) != 3) {
816
- ARGUMENT_ERROR(":dither is illeagal length (shall be 3 entries).");
817
- }
3055
+ VALUE ret;
3056
+ volatile int i; // volatileを外すとaarch64のgcc6でクラッシュする場合がある
3057
+ int n;
3058
+ uint8_t* dst;
3059
+ JSAMPARRAY map;
818
3060
 
819
- dmode = RARRAY_AREF(opt, 0);
820
- pass2 = RARRAY_AREF(opt, 1);
821
- n_col = RARRAY_AREF(opt, 2);
822
-
823
- if (EQ_STR(dmode, "NONE")) {
824
- ptr->dither_mode = JDITHER_NONE;
825
- ptr->quantize_colors = FALSE;
3061
+ n = cinfo->output_width * cinfo->output_height;
3062
+ ret = rb_str_buf_new(n * cinfo->out_color_components);
3063
+ dst = (uint8_t*)RSTRING_PTR(ret);
3064
+ map = cinfo->colormap;
826
3065
 
827
- } else if(EQ_STR(dmode, "ORDERED")) {
828
- ptr->dither_mode = JDITHER_ORDERED;
829
- ptr->quantize_colors = TRUE;
3066
+ switch (cinfo->out_color_components) {
3067
+ case 1:
3068
+ for (i = 0; i < n; i++) {
3069
+ dst[i] = map[0][src[i]];
3070
+ }
3071
+ break;
830
3072
 
831
- } else if(EQ_STR(dmode, "FS")) {
832
- ptr->dither_mode = JDITHER_FS;
833
- ptr->quantize_colors = TRUE;
3073
+ case 2:
3074
+ for (i = 0; i < n; i++) {
3075
+ dst[0] = map[0][src[i]];
3076
+ dst[1] = map[1][src[i]];
834
3077
 
835
- } else {
836
- ARGUMENT_ERROR("dither mode is illeagal value.");
3078
+ dst += 2;
837
3079
  }
3080
+ break;
838
3081
 
839
- switch (TYPE(pass2)) {
840
- case T_TRUE:
841
- ptr->two_pass_quantize = TRUE;
842
- break;
843
-
844
- case T_FALSE:
845
- ptr->two_pass_quantize = FALSE;
846
- break;
3082
+ case 3:
3083
+ for (i = 0; i < n; i++) {
3084
+ dst[0] = map[0][src[i]];
3085
+ dst[1] = map[1][src[i]];
3086
+ dst[2] = map[2][src[i]];
847
3087
 
848
- default:
849
- ARGUMENT_ERROR( "2pass quantize flag is illeagal value.");
3088
+ dst += 3;
850
3089
  }
3090
+ break;
851
3091
 
852
- if (TYPE(n_col) == T_FIXNUM) {
853
- ptr->desired_number_of_colors = FIX2INT(n_col);
854
- } else {
855
- ARGUMENT_ERROR( "number of dithered colors is illeagal value.");
856
- }
3092
+ default:
3093
+ RUNTIME_ERROR("this number of components is not implemented yet");
857
3094
  }
3095
+
3096
+ rb_str_set_len(ret, n * cinfo->out_color_components);
3097
+
3098
+ return ret;
858
3099
  }
859
3100
 
860
3101
  static void
861
- eval_decoder_opt_use_1pass_quantizer(jpeg_decode_t* ptr, VALUE opt)
3102
+ swap_cbcr(uint8_t* p, size_t size)
862
3103
  {
863
- switch (TYPE(opt)) {
864
- case T_UNDEF:
865
- // Nothing
866
- break;
867
-
868
- case T_TRUE:
869
- ptr->enable_1pass_quant = TRUE;
870
- ptr->buffered_image = TRUE;
871
- break;
872
-
873
- case T_FALSE:
874
- ptr->enable_1pass_quant = FALSE;
875
- break;
3104
+ int i;
3105
+ uint8_t tmp;
876
3106
 
877
- default:
878
- ARGUMENT_ERROR("Unsupportd :use_1pass_quantizer option value.");
879
- break;
3107
+ for (i = 0; i < (int)size; i++) {
3108
+ tmp = p[1];
3109
+ p[1] = p[2];
3110
+ p[2] = tmp;
880
3111
  }
881
3112
  }
882
3113
 
883
3114
  static void
884
- eval_decoder_opt_use_external_colormap(jpeg_decode_t* ptr, VALUE opt)
3115
+ do_transpose8(uint8_t* img, int wd, int ht, void* dst)
885
3116
  {
886
- switch (TYPE(opt)) {
887
- case T_UNDEF:
888
- // Nothing
889
- break;
3117
+ int x;
3118
+ int y;
890
3119
 
891
- case T_TRUE:
892
- ptr->enable_external_quant = TRUE;
893
- ptr->buffered_image = TRUE;
894
- break;
3120
+ uint8_t* sp;
3121
+ uint8_t* dp;
895
3122
 
896
- case T_FALSE:
897
- ptr->enable_external_quant = FALSE;
898
- break;
3123
+ sp = (uint8_t*)img;
899
3124
 
900
- default:
901
- ARGUMENT_ERROR("Unsupportd :use_external_colormap option value.");
902
- break;
3125
+ for (y = 0; y < ht; y++) {
3126
+ dp = (uint8_t*)dst + y;
3127
+
3128
+ for (x = 0; x < wd; x++) {
3129
+ *dp = *sp;
3130
+
3131
+ sp++;
3132
+ dp += ht;
3133
+ }
903
3134
  }
904
3135
  }
905
3136
 
906
3137
  static void
907
- eval_decoder_opt_use_2pass_quantizer(jpeg_decode_t* ptr, VALUE opt)
3138
+ do_transpose16(void* img, int wd, int ht, void* dst)
908
3139
  {
909
- switch (TYPE(opt)) {
910
- case T_UNDEF:
911
- // Nothing
912
- break;
3140
+ int x;
3141
+ int y;
913
3142
 
914
- case T_TRUE:
915
- ptr->enable_2pass_quant = TRUE;
916
- ptr->buffered_image = TRUE;
917
- break;
3143
+ uint16_t* sp;
3144
+ uint16_t* dp;
918
3145
 
919
- case T_FALSE:
920
- ptr->enable_2pass_quant = FALSE;
921
- break;
3146
+ sp = (uint16_t*)img;
922
3147
 
923
- default:
924
- ARGUMENT_ERROR("Unsupportd :use_2pass_quantizer option value.");
925
- break;
3148
+ for (y = 0; y < ht; y++) {
3149
+ dp = (uint16_t*)dst + y;
3150
+
3151
+ for (x = 0; x < wd; x++) {
3152
+ *dp = *sp;
3153
+
3154
+ sp++;
3155
+ dp += ht;
3156
+ }
926
3157
  }
927
3158
  }
928
3159
 
929
3160
  static void
930
- eval_decoder_opt_without_meta(jpeg_decode_t* ptr, VALUE opt)
3161
+ do_transpose24(void* img, int wd, int ht, void* dst)
931
3162
  {
932
- switch (TYPE(opt)) {
933
- case T_UNDEF:
934
- // Nothing
935
- break;
3163
+ int x;
3164
+ int y;
3165
+ int st;
936
3166
 
937
- case T_TRUE:
938
- ptr->need_meta = 0;
939
- break;
3167
+ uint8_t* sp;
3168
+ uint8_t* dp;
940
3169
 
941
- case T_FALSE:
942
- ptr->need_meta = !0;
943
- break;
3170
+ sp = (uint8_t*)img;
3171
+ st = ht * 3;
944
3172
 
945
- default:
946
- ARGUMENT_ERROR("Unsupportd :without_meta option value.");
947
- break;
3173
+ for (y = 0; y < ht; y++) {
3174
+ dp = (uint8_t*)dst + (y * 3);
3175
+
3176
+ for (x = 0; x < wd; x++) {
3177
+ dp[0] = sp[0];
3178
+ dp[1] = sp[1];
3179
+ dp[2] = sp[2];
3180
+
3181
+ sp += 3;
3182
+ dp += st;
3183
+ }
948
3184
  }
949
3185
  }
950
3186
 
951
3187
  static void
952
- eval_decoder_opt_expand_colormap(jpeg_decode_t* ptr, VALUE opt)
3188
+ do_transpose32(void* img, int wd, int ht, void* dst)
953
3189
  {
954
- switch (TYPE(opt)) {
955
- case T_UNDEF:
956
- // Nothing
957
- break;
3190
+ int x;
3191
+ int y;
958
3192
 
959
- case T_TRUE:
960
- ptr->expand_colormap = !0;
961
- break;
3193
+ uint32_t* sp;
3194
+ uint32_t* dp;
962
3195
 
963
- case T_FALSE:
964
- ptr->expand_colormap = 0;
965
- break;
3196
+ sp = (uint32_t*)img;
966
3197
 
967
- default:
968
- ARGUMENT_ERROR("Unsupportd :exapnd_colormap option value.");
969
- break;
3198
+ for (y = 0; y < ht; y++) {
3199
+ dp = (uint32_t*)dst + y;
3200
+
3201
+ for (x = 0; x < wd; x++) {
3202
+ *dp = *sp;
3203
+
3204
+ sp++;
3205
+ dp += ht;
3206
+ }
970
3207
  }
971
3208
  }
972
3209
 
973
3210
  static void
974
- eval_decoder_opt_scale(jpeg_decode_t* ptr, VALUE opt)
3211
+ do_transpose(void* img, int wd, int ht, int nc, void* dst)
975
3212
  {
976
- switch (TYPE(opt)) {
977
- case T_UNDEF:
978
- // Nothing
3213
+ switch (nc) {
3214
+ case 1:
3215
+ do_transpose8(img, wd, ht, dst);
979
3216
  break;
980
3217
 
981
- case T_FLOAT:
982
- ptr->scale_num = 1000;
983
- ptr->scale_denom = (int)(NUM2DBL(opt) * 1000.0);
3218
+ case 2:
3219
+ do_transpose16(img, wd, ht, dst);
984
3220
  break;
985
3221
 
986
- case T_RATIONAL:
987
- ptr->scale_num = FIX2INT(rb_rational_num(opt));
988
- ptr->scale_denom = FIX2INT(rb_rational_den(opt));
3222
+ case 3:
3223
+ do_transpose24(img, wd, ht, dst);
989
3224
  break;
990
3225
 
991
- default:
992
- ARGUMENT_ERROR("Unsupportd :exapnd_colormap option value.");
3226
+ case 4:
3227
+ do_transpose32(img, wd, ht, dst);
993
3228
  break;
994
3229
  }
995
3230
  }
996
3231
 
997
3232
  static void
998
- eval_decoder_opt_dct_method(jpeg_decode_t* ptr, VALUE opt)
3233
+ do_upside_down8(void* img, int wd, int ht)
999
3234
  {
1000
- if (opt != Qundef) {
1001
- if (EQ_STR(opt, "ISLOW")) {
1002
- ptr->dct_method = JDCT_ISLOW;
1003
-
1004
- } else if (EQ_STR(opt, "IFAST")) {
1005
- ptr->dct_method = JDCT_IFAST;
3235
+ uint8_t* sp;
3236
+ uint8_t* dp;
1006
3237
 
1007
- } else if (EQ_STR(opt, "FLOAT")) {
1008
- ptr->dct_method = JDCT_FLOAT;
3238
+ sp = (uint8_t*)img;
3239
+ dp = (uint8_t*)img + ((wd * ht) - 1);
1009
3240
 
1010
- } else if (EQ_STR(opt, "FASTEST")) {
1011
- ptr->dct_method = JDCT_FASTEST;
3241
+ while (sp < dp) {
3242
+ SWAP(*sp, *dp, uint8_t);
1012
3243
 
1013
- } else {
1014
- ARGUMENT_ERROR("Unsupportd :dct_method option value.");
1015
- }
3244
+ sp++;
3245
+ dp--;
1016
3246
  }
1017
3247
  }
1018
3248
 
1019
3249
  static void
1020
- set_decoder_context( jpeg_decode_t* ptr, VALUE opt)
1021
- {
1022
- VALUE opts[N(decoder_opts_ids)];
1023
-
1024
- /*
1025
- * parse options
1026
- */
1027
- rb_get_kwargs( opt, decoder_opts_ids, 0, N(decoder_opts_ids), opts);
1028
-
1029
- /*
1030
- * set context
1031
- */
1032
- eval_decoder_opt_pixel_format(ptr, opts[0]);
1033
- eval_decoder_opt_output_gamma(ptr, opts[1]);
1034
- eval_decoder_opt_do_fancy_upsampling(ptr, opts[2]);
1035
- eval_decoder_opt_do_smoothing(ptr, opts[3]);
1036
- eval_decoder_opt_dither(ptr, opts[4]);
1037
- eval_decoder_opt_use_1pass_quantizer(ptr, opts[5]);
1038
- eval_decoder_opt_use_external_colormap(ptr, opts[6]);
1039
- eval_decoder_opt_use_2pass_quantizer(ptr, opts[7]);
1040
- eval_decoder_opt_without_meta(ptr, opts[8]);
1041
- eval_decoder_opt_expand_colormap(ptr, opts[9]);
1042
- eval_decoder_opt_scale(ptr, opts[10]);
1043
- eval_decoder_opt_dct_method(ptr, opts[11]);
1044
- }
1045
-
1046
- static VALUE
1047
- rb_decoder_initialize( int argc, VALUE *argv, VALUE self)
1048
- {
1049
- jpeg_decode_t* ptr;
1050
- VALUE opt;
1051
-
1052
- /*
1053
- * initialize
1054
- */
1055
- Data_Get_Struct(self, jpeg_decode_t, ptr);
1056
-
1057
- /*
1058
- * parse arguments
1059
- */
1060
- rb_scan_args( argc, argv, "01", &opt);
1061
-
1062
- if (opt != Qnil) Check_Type(opt, T_HASH);
1063
-
1064
- /*
1065
- * set context
1066
- */
1067
- set_decoder_context(ptr, opt);
1068
-
1069
- return Qtrue;
1070
- }
1071
-
1072
- static VALUE
1073
- rb_decoder_set(VALUE self, VALUE opt)
3250
+ do_upside_down16(void* img, int wd, int ht)
1074
3251
  {
1075
- VALUE ret;
1076
- jpeg_decode_t* ptr;
1077
-
1078
- /*
1079
- * initialize
1080
- */
1081
- Data_Get_Struct(self, jpeg_decode_t, ptr);
3252
+ uint16_t* sp;
3253
+ uint16_t* dp;
1082
3254
 
1083
- /*
1084
- * check argument
1085
- */
1086
- Check_Type( opt, T_HASH);
3255
+ sp = (uint16_t*)img;
3256
+ dp = (uint16_t*)img + ((wd * ht) - 1);
1087
3257
 
1088
- /*
1089
- * set context
1090
- */
1091
- set_decoder_context(ptr, opt);
3258
+ while (sp < dp) {
3259
+ SWAP(*sp, *dp, uint8_t);
1092
3260
 
1093
- return Qtrue;
3261
+ sp++;
3262
+ dp--;
3263
+ }
1094
3264
  }
1095
3265
 
1096
-
1097
-
1098
- static VALUE
1099
- get_colorspace_str( J_COLOR_SPACE cs)
3266
+ static void
3267
+ do_upside_down24(void* img, int wd, int ht)
1100
3268
  {
1101
- const char* cstr;
1102
-
1103
- switch (cs) {
1104
- case JCS_GRAYSCALE:
1105
- cstr = "GRAYSCALE";
1106
- break;
1107
-
1108
- case JCS_RGB:
1109
- cstr = "RGB";
1110
- break;
1111
-
1112
- case JCS_YCbCr:
1113
- cstr = "YCbCr";
1114
- break;
1115
-
1116
- case JCS_CMYK:
1117
- cstr = "CMYK";
1118
- break;
3269
+ uint8_t* sp;
3270
+ uint8_t* dp;
1119
3271
 
1120
- case JCS_YCCK:
1121
- cstr = "YCCK";
1122
- break;
1123
- #if JPEG_LIB_VERSION < 90
1124
- case JCS_EXT_RGB:
1125
- cstr = "RGB";
1126
- break;
3272
+ sp = (uint8_t*)img;
3273
+ dp = (uint8_t*)img + ((wd * ht * 3) - 3);
1127
3274
 
1128
- case JCS_EXT_RGBX:
1129
- cstr = "RGBX";
1130
- break;
3275
+ while (sp < dp) {
3276
+ SWAP(sp[0], dp[0], uint8_t);
3277
+ SWAP(sp[1], dp[1], uint8_t);
3278
+ SWAP(sp[2], dp[2], uint8_t);
1131
3279
 
1132
- case JCS_EXT_BGR:
1133
- cstr = "BGR";
1134
- break;
3280
+ sp += 3;
3281
+ dp -= 3;
3282
+ }
3283
+ }
1135
3284
 
1136
- case JCS_EXT_BGRX:
1137
- cstr = "BGRX";
1138
- break;
3285
+ static void
3286
+ do_upside_down32(void* img, int wd, int ht)
3287
+ {
3288
+ uint32_t* sp;
3289
+ uint32_t* dp;
1139
3290
 
1140
- case JCS_EXT_XBGR:
1141
- cstr = "XBGR";
1142
- break;
3291
+ sp = (uint32_t*)img;
3292
+ dp = (uint32_t*)img + ((wd * ht) - 1);
1143
3293
 
1144
- case JCS_EXT_XRGB:
1145
- cstr = "XRGB";
1146
- break;
3294
+ ht /= 2;
1147
3295
 
1148
- case JCS_EXT_RGBA:
1149
- cstr = "RGBA";
1150
- break;
3296
+ while (sp < dp) {
3297
+ SWAP(*sp, *dp, uint32_t);
1151
3298
 
1152
- case JCS_EXT_BGRA:
1153
- cstr = "BGRA";
3299
+ sp++;
3300
+ dp--;
3301
+ }
3302
+ }
3303
+
3304
+ static void
3305
+ do_upside_down(void* img, int wd, int ht, int nc)
3306
+ {
3307
+ switch (nc) {
3308
+ case 1:
3309
+ do_upside_down8(img, wd, ht);
1154
3310
  break;
1155
3311
 
1156
- case JCS_EXT_ABGR:
1157
- cstr = "ABGR";
3312
+ case 2:
3313
+ do_upside_down16(img, wd, ht);
1158
3314
  break;
1159
3315
 
1160
- case JCS_EXT_ARGB:
1161
- cstr = "ARGB";
3316
+ case 3:
3317
+ do_upside_down24(img, wd, ht);
1162
3318
  break;
1163
- #endif /* JPEG_LIB_VERSION < 90 */
1164
3319
 
1165
- default:
1166
- cstr = "UNKNOWN";
3320
+ case 4:
3321
+ do_upside_down32(img, wd, ht);
1167
3322
  break;
1168
3323
  }
1169
-
1170
- return rb_str_new_cstr(cstr);
1171
3324
  }
1172
3325
 
1173
- static VALUE
1174
- create_meta(jpeg_decode_t* ptr)
3326
+ static void
3327
+ do_flip_horizon8(void* img, int wd, int ht)
1175
3328
  {
1176
- VALUE ret;
1177
- struct jpeg_decompress_struct* cinfo;
3329
+ int y;
3330
+ int st;
1178
3331
 
1179
- /* TODO: そのうちディザをかけた場合のカラーマップをメタで返すようにする */
3332
+ uint8_t* sp;
3333
+ uint8_t* dp;
1180
3334
 
1181
- ret = rb_obj_alloc( meta_klass);
1182
- cinfo = &ptr->cinfo;
3335
+ st = wd;
3336
+ wd /= 2;
1183
3337
 
1184
- rb_ivar_set(ret, id_width, INT2FIX(cinfo->output_width));
1185
- rb_ivar_set(ret, id_height, INT2FIX(cinfo->output_height));
1186
- rb_ivar_set(ret, id_orig_cs, get_colorspace_str(cinfo->jpeg_color_space));
3338
+ sp = (uint8_t*)img;
3339
+ dp = (uint8_t*)img + (st - 1);
1187
3340
 
1188
- if (ptr->format == FMT_YVU) {
1189
- rb_ivar_set(ret, id_out_cs, rb_str_new_cstr("YCrCb"));
1190
- } else {
1191
- rb_ivar_set(ret, id_out_cs, get_colorspace_str(cinfo->out_color_space));
1192
- }
3341
+ for (y = 0; y < ht; y++) {
3342
+ while (sp < dp) {
3343
+ SWAP(*sp, *dp, uint8_t);
1193
3344
 
1194
- rb_ivar_set(ret, id_ncompo, INT2FIX(cinfo->output_components));
3345
+ sp++;
3346
+ dp--;
3347
+ }
1195
3348
 
1196
- return ret;
3349
+ sp = sp - wd + st;
3350
+ dp = sp + (st - 1);
3351
+ }
1197
3352
  }
1198
3353
 
1199
- static VALUE
1200
- do_read_header(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
3354
+ static void
3355
+ do_flip_horizon16(void* img, int wd, int ht)
1201
3356
  {
1202
- VALUE ret;
1203
-
1204
- switch (ptr->format) {
1205
- case FMT_YUV422:
1206
- case FMT_RGB565:
1207
- RUNTIME_ERROR( "Not implement");
1208
- break;
1209
- }
3357
+ int y;
3358
+ int st;
1210
3359
 
1211
- jpeg_create_decompress(&ptr->cinfo);
3360
+ uint16_t* sp;
3361
+ uint16_t* dp;
1212
3362
 
1213
- ptr->cinfo.err = jpeg_std_error(&ptr->err_mgr.jerr);
1214
- ptr->err_mgr.jerr.output_message = decode_output_message;
1215
- ptr->err_mgr.jerr.emit_message = decode_emit_message;
1216
- ptr->err_mgr.jerr.error_exit = decode_error_exit;
3363
+ st = wd;
3364
+ wd /= 2;
1217
3365
 
1218
- ptr->cinfo.raw_data_out = FALSE;
1219
- ptr->cinfo.dct_method = JDCT_FLOAT;
3366
+ sp = (uint16_t*)img;
3367
+ dp = (uint16_t*)img + (st - 1);
1220
3368
 
1221
- if (setjmp(ptr->err_mgr.jmpbuf)) {
1222
- jpeg_destroy_decompress(&ptr->cinfo);
1223
- rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
1224
- } else {
1225
- jpeg_mem_src(&ptr->cinfo, jpg, jpg_sz);
1226
- jpeg_read_header(&ptr->cinfo, TRUE);
1227
- jpeg_calc_output_dimensions(&ptr->cinfo);
3369
+ for (y = 0; y < ht; y++) {
3370
+ while (sp < dp) {
3371
+ SWAP(*sp, *dp, uint16_t);
1228
3372
 
1229
- ret = create_meta(ptr);
3373
+ sp++;
3374
+ dp--;
3375
+ }
1230
3376
 
1231
- jpeg_destroy_decompress(&ptr->cinfo);
3377
+ sp = sp - wd + st;
3378
+ dp = sp + (st - 1);
1232
3379
  }
1233
-
1234
- return ret;
1235
3380
  }
1236
3381
 
1237
- static VALUE
1238
- rb_decoder_read_header(VALUE self, VALUE data)
3382
+ static void
3383
+ do_flip_horizon24(void* img, int wd, int ht)
1239
3384
  {
1240
- VALUE ret;
1241
- jpeg_decode_t* ptr;
3385
+ int y;
3386
+ int st;
1242
3387
 
1243
- /*
1244
- * initialize
1245
- */
1246
- Data_Get_Struct(self, jpeg_decode_t, ptr);
3388
+ uint8_t* sp;
3389
+ uint8_t* dp;
1247
3390
 
1248
- /*
1249
- * argument check
1250
- */
1251
- Check_Type(data, T_STRING);
3391
+ st = wd * 3;
3392
+ wd /= 2;
1252
3393
 
1253
- /*
1254
- * do encode
1255
- */
1256
- ret = do_read_header(ptr, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
3394
+ sp = (uint8_t*)img;
3395
+ dp = (uint8_t*)img + (st - 3);
1257
3396
 
1258
- return ret;
1259
- }
3397
+ for (y = 0; y < ht; y++) {
3398
+ while (sp < dp) {
3399
+ SWAP(sp[0], dp[0], uint8_t);
3400
+ SWAP(sp[1], dp[1], uint8_t);
3401
+ SWAP(sp[2], dp[2], uint8_t);
1260
3402
 
1261
- static VALUE
1262
- rb_decode_result_meta(VALUE self)
1263
- {
1264
- return rb_ivar_get(self, id_meta);
3403
+ sp += 3;
3404
+ dp -= 3;
3405
+ }
3406
+
3407
+ sp = (sp - (wd * 3)) + st;
3408
+ dp = sp + (st - 3);
3409
+ }
1265
3410
  }
1266
3411
 
1267
3412
  static void
1268
- add_meta(VALUE obj, jpeg_decode_t* ptr)
3413
+ do_flip_horizon32(void* img, int wd, int ht)
1269
3414
  {
1270
- VALUE meta;
3415
+ int y;
3416
+ int st;
1271
3417
 
1272
- meta = create_meta(ptr);
3418
+ uint32_t* sp;
3419
+ uint32_t* dp;
1273
3420
 
1274
- rb_ivar_set(obj, id_meta, meta);
1275
- rb_define_singleton_method(obj, "meta", rb_decode_result_meta, 0);
1276
- }
3421
+ st = wd;
3422
+ wd /= 2;
1277
3423
 
1278
- static VALUE
1279
- expand_colormap(struct jpeg_decompress_struct* cinfo, uint8_t* src)
1280
- {
1281
- /*
1282
- * 本関数はcinfo->out_color_componentsが1または3であることを前提に
1283
- * 作成されています。
1284
- */
3424
+ sp = (uint32_t*)img;
3425
+ dp = (uint32_t*)img + (st - 1);
1285
3426
 
1286
- VALUE ret;
1287
- int i;
1288
- int n;
1289
- uint8_t* dst;
1290
- JSAMPARRAY map;
3427
+ for (y = 0; y < ht; y++) {
3428
+ while (sp < dp) {
3429
+ SWAP(*sp, *dp, uint32_t);
1291
3430
 
1292
- n = cinfo->output_width * cinfo->output_height;
1293
- ret = rb_str_buf_new(n * cinfo->out_color_components);
1294
- dst = (uint8_t*)RSTRING_PTR(ret);
1295
- map = cinfo->colormap;
3431
+ sp++;
3432
+ dp--;
3433
+ }
1296
3434
 
1297
- switch (cinfo->out_color_components) {
3435
+ sp = sp - wd + st;
3436
+ dp = sp + (st - 1);
3437
+ }
3438
+ }
3439
+
3440
+ static void
3441
+ do_flip_horizon(void* img, int wd, int ht, int nc)
3442
+ {
3443
+ switch (nc) {
1298
3444
  case 1:
1299
- for (i = 0; i < n; i++) {
1300
- dst[i] = map[0][src[i]];
1301
- }
3445
+ do_flip_horizon8(img, wd, ht);
3446
+ break;
3447
+
3448
+ case 2:
3449
+ do_flip_horizon16(img, wd, ht);
1302
3450
  break;
1303
3451
 
1304
3452
  case 3:
1305
- for (i = 0; i < n; i++) {
1306
- dst[0] = map[0][src[i]];
1307
- dst[1] = map[1][src[i]];
1308
- dst[2] = map[2][src[i]];
3453
+ do_flip_horizon24(img, wd, ht);
3454
+ break;
1309
3455
 
1310
- dst += 3;
1311
- }
3456
+ case 4:
3457
+ do_flip_horizon32(img, wd, ht);
1312
3458
  break;
3459
+ }
3460
+ }
1313
3461
 
1314
- default:
1315
- RUNTIME_ERROR("Really?");
3462
+ static VALUE
3463
+ shift_orientation_buffer(jpeg_decode_t* ptr, VALUE img)
3464
+ {
3465
+ VALUE ret;
3466
+ int len;
3467
+
3468
+ ret = ptr->orientation.buf;
3469
+ len = RSTRING_LEN(img);
3470
+
3471
+ if (ret == Qnil || RSTRING_LEN(ret) != len) {
3472
+ ret = rb_str_buf_new(len);
3473
+ rb_str_set_len(ret, len);
1316
3474
  }
1317
3475
 
1318
- rb_str_set_len(ret, n * cinfo->out_color_components);
3476
+ ptr->orientation.buf = img;
1319
3477
 
1320
3478
  return ret;
1321
3479
  }
1322
3480
 
1323
- static void
1324
- swap_cbcr(uint8_t* p, size_t size)
3481
+ static VALUE
3482
+ apply_orientation(jpeg_decode_t* ptr, VALUE img)
1325
3483
  {
1326
- int i;
1327
- uint8_t tmp;
3484
+ struct jpeg_decompress_struct* cinfo;
3485
+ int wd;
3486
+ int ht;
3487
+ int nc;
3488
+ VALUE tmp;
1328
3489
 
1329
- for (i = 0; i < size; i++) {
1330
- tmp = p[1];
1331
- p[1] = p[2];
1332
- p[2] = tmp;
3490
+ cinfo = &ptr->cinfo;
3491
+ wd = cinfo->output_width;
3492
+ ht = cinfo->output_height;
3493
+ nc = cinfo->output_components;
3494
+
3495
+ if (ptr->orientation.value & 4) {
3496
+ /* 転置は交換アルゴリズムでは実装できないので新規バッファを
3497
+ 用意する */
3498
+ tmp = img;
3499
+ img = shift_orientation_buffer(ptr, tmp);
3500
+ SWAP(wd, ht, int);
3501
+
3502
+ do_transpose(RSTRING_PTR(tmp), ht, wd, nc, RSTRING_PTR(img));
3503
+ }
3504
+
3505
+ if (ptr->orientation.value & 2) {
3506
+ do_upside_down(RSTRING_PTR(img), wd, ht, nc);
3507
+ }
3508
+
3509
+ if (ptr->orientation.value & 1) {
3510
+ do_flip_horizon(RSTRING_PTR(img), wd, ht, nc);
1333
3511
  }
3512
+
3513
+ return img;
1334
3514
  }
1335
3515
 
1336
3516
  static VALUE
1337
- do_decode(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
3517
+ do_decode(VALUE _ptr)
1338
3518
  {
1339
3519
  VALUE ret;
3520
+
3521
+ jpeg_decode_t* ptr;
3522
+ uint8_t* data;
3523
+ size_t size;
3524
+
1340
3525
  struct jpeg_decompress_struct* cinfo;
1341
3526
  JSAMPARRAY array;
1342
3527
 
@@ -1346,118 +3531,148 @@ do_decode(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
1346
3531
  int i;
1347
3532
  int j;
1348
3533
 
1349
- ret = Qundef; // warning対策
3534
+ /*
3535
+ * initialize
3536
+ */
3537
+ ret = Qnil; // warning対策
3538
+ ptr = (jpeg_decode_t*)_ptr;
3539
+ data = (uint8_t*)RSTRING_PTR(ptr->data);
3540
+ size = RSTRING_LEN(ptr->data);
1350
3541
  cinfo = &ptr->cinfo;
1351
- array = ALLOC_ARRAY();
1352
-
1353
- switch (ptr->format) {
1354
- case FMT_YUV422:
1355
- case FMT_RGB565:
1356
- RUNTIME_ERROR( "Not implement");
1357
- break;
1358
-
1359
- case FMT_GRAYSCALE:
1360
- case FMT_YUV:
1361
- case FMT_RGB:
1362
- case FMT_BGR:
1363
- case FMT_YVU:
1364
- case FMT_RGB32:
1365
- case FMT_BGR32:
1366
- jpeg_create_decompress(cinfo);
1367
-
1368
- cinfo->err = jpeg_std_error(&ptr->err_mgr.jerr);
1369
- ptr->err_mgr.jerr.output_message = decode_output_message;
1370
- ptr->err_mgr.jerr.emit_message = decode_emit_message;
1371
- ptr->err_mgr.jerr.error_exit = decode_error_exit;
3542
+ array = ptr->array;
1372
3543
 
1373
- if (setjmp(ptr->err_mgr.jmpbuf)) {
1374
- jpeg_abort_decompress(cinfo);
1375
- jpeg_destroy_decompress(&ptr->cinfo);
3544
+ /*
3545
+ * do decode
3546
+ */
3547
+ if (setjmp(ptr->err_mgr.jmpbuf)) {
3548
+ /*
3549
+ * when error occurred
3550
+ */
3551
+ rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
1376
3552
 
1377
- free(array);
1378
- rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
3553
+ } else {
3554
+ /*
3555
+ * normal path
3556
+ */
3557
+ jpeg_mem_src(cinfo, data, size);
1379
3558
 
1380
- } else {
1381
- jpeg_mem_src(cinfo, jpg, jpg_sz);
1382
- jpeg_read_header(cinfo, TRUE);
1383
-
1384
- cinfo->raw_data_out = FALSE;
1385
- cinfo->dct_method = ptr->dct_method;
1386
-
1387
- cinfo->out_color_space = ptr->out_color_space;
1388
- cinfo->out_color_components = ptr->out_color_components;
1389
- cinfo->scale_num = ptr->scale_num;
1390
- cinfo->scale_denom = ptr->scale_denom;
1391
- cinfo->output_gamma = ptr->output_gamma;
1392
- cinfo->do_fancy_upsampling = ptr->do_fancy_upsampling;
1393
- cinfo->do_block_smoothing = ptr->do_block_smoothing;
1394
- cinfo->quantize_colors = ptr->quantize_colors;
1395
- cinfo->dither_mode = ptr->dither_mode;
1396
- cinfo->two_pass_quantize = ptr->two_pass_quantize;
1397
- cinfo->desired_number_of_colors = ptr->desired_number_of_colors;
1398
- cinfo->enable_1pass_quant = ptr->enable_1pass_quant;
1399
- cinfo->enable_external_quant = ptr->enable_external_quant;
1400
- cinfo->enable_2pass_quant = ptr->enable_2pass_quant;
1401
-
1402
- jpeg_calc_output_dimensions(cinfo);
1403
- jpeg_start_decompress(cinfo);
1404
-
1405
- stride = cinfo->output_components * cinfo->output_width;
1406
- raw_sz = stride * cinfo->output_height;
1407
- ret = rb_str_buf_new(raw_sz);
1408
- raw = (uint8_t*)RSTRING_PTR(ret);
1409
-
1410
-
1411
- while (cinfo->output_scanline < cinfo->output_height) {
1412
- for (i = 0, j = cinfo->output_scanline; i < UNIT_LINES; i++, j++) {
1413
- array[i] = raw + (j * stride);
1414
- }
3559
+ if (TEST_FLAG(ptr, F_PARSE_EXIF | F_APPLY_ORIENTATION)) {
3560
+ jpeg_save_markers(&ptr->cinfo, JPEG_APP1, 0xFFFF);
3561
+ }
1415
3562
 
1416
- jpeg_read_scanlines(cinfo, array, UNIT_LINES);
3563
+ jpeg_read_header(cinfo, TRUE);
3564
+ jpeg_calc_output_dimensions(cinfo);
3565
+
3566
+ cinfo->raw_data_out = FALSE;
3567
+ cinfo->dct_method = ptr->dct_method;
3568
+
3569
+ cinfo->out_color_space = ptr->out_color_space;
3570
+ cinfo->out_color_components = ptr->out_color_components;
3571
+ cinfo->scale_num = ptr->scale_num;
3572
+ cinfo->scale_denom = ptr->scale_denom;
3573
+ cinfo->output_gamma = ptr->output_gamma;
3574
+ cinfo->do_fancy_upsampling = ptr->do_fancy_upsampling;
3575
+ cinfo->do_block_smoothing = ptr->do_block_smoothing;
3576
+ cinfo->quantize_colors = ptr->quantize_colors;
3577
+ cinfo->dither_mode = ptr->dither_mode;
3578
+ cinfo->two_pass_quantize = ptr->two_pass_quantize;
3579
+ cinfo->desired_number_of_colors = ptr->desired_number_of_colors;
3580
+ cinfo->enable_1pass_quant = ptr->enable_1pass_quant;
3581
+ cinfo->enable_external_quant = ptr->enable_external_quant;
3582
+ cinfo->enable_2pass_quant = ptr->enable_2pass_quant;
3583
+
3584
+ jpeg_start_decompress(cinfo);
3585
+ SET_FLAG(ptr, F_START);
3586
+
3587
+ stride = cinfo->output_components * cinfo->output_width;
3588
+ raw_sz = stride * cinfo->output_height;
3589
+ ret = rb_str_buf_new(raw_sz);
3590
+ raw = (uint8_t*)RSTRING_PTR(ret);
3591
+
3592
+ while (cinfo->output_scanline < cinfo->output_height) {
3593
+ for (i = 0, j = cinfo->output_scanline; i < UNIT_LINES; i++, j++) {
3594
+ array[i] = raw + (j * stride);
1417
3595
  }
1418
3596
 
1419
- if (ptr->expand_colormap && IS_COLORMAPPED( cinfo)) {
1420
- ret = expand_colormap(cinfo, raw);
1421
- } else {
1422
- rb_str_set_len( ret, raw_sz);
1423
- }
3597
+ jpeg_read_scanlines(cinfo, array, UNIT_LINES);
3598
+ }
3599
+
3600
+ if (TEST_FLAG(ptr, F_EXPAND_COLORMAP) && IS_COLORMAPPED(cinfo)) {
3601
+ ret = expand_colormap(cinfo, raw);
3602
+ } else {
3603
+ rb_str_set_len(ret, raw_sz);
3604
+ }
1424
3605
 
1425
- if (ptr->need_meta) add_meta(ret, ptr);
1426
- if (ptr->format == FMT_YVU) swap_cbcr(raw, raw_sz);
3606
+ if (ptr->format == FMT_YVU) swap_cbcr(raw, raw_sz);
1427
3607
 
1428
- jpeg_finish_decompress(cinfo);
1429
- jpeg_destroy_decompress(&ptr->cinfo);
3608
+ if (TEST_FLAG(ptr, F_APPLY_ORIENTATION)) {
3609
+ pick_exif_orientation(ptr);
3610
+ ret = apply_orientation(ptr, ret);
1430
3611
  }
1431
- break;
1432
- }
1433
3612
 
1434
- free(array);
3613
+ if (TEST_FLAG(ptr, F_NEED_META)) add_meta(ret, ptr);
3614
+ }
1435
3615
 
1436
3616
  return ret;
1437
3617
  }
1438
3618
 
3619
+ /**
3620
+ * decode JPEG data
3621
+ *
3622
+ * @overload decode(jpeg)
3623
+ *
3624
+ * @param jpeg [String] JPEG data to decode.
3625
+ *
3626
+ * @return [String] decoded raw image data.
3627
+ */
1439
3628
  static VALUE
1440
3629
  rb_decoder_decode(VALUE self, VALUE data)
1441
3630
  {
1442
- VALUE ret;
1443
- jpeg_decode_t* ptr;
3631
+ VALUE ret;
3632
+ jpeg_decode_t* ptr;
3633
+ int state;
1444
3634
 
1445
- /*
1446
- * initialize
1447
- */
1448
- Data_Get_Struct(self, jpeg_decode_t, ptr);
3635
+ /*
3636
+ * initialize
3637
+ */
3638
+ ret = Qnil;
3639
+ state = 0;
1449
3640
 
1450
- /*
1451
- * argument check
1452
- */
1453
- Check_Type(data, T_STRING);
3641
+ TypedData_Get_Struct(self, jpeg_decode_t, &jpeg_decoder_data_type, ptr);
1454
3642
 
1455
- /*
1456
- * do encode
1457
- */
1458
- ret = do_decode(ptr, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
3643
+ /*
3644
+ * argument check
3645
+ */
3646
+ Check_Type(data, T_STRING);
3647
+
3648
+ /*
3649
+ * prepare
3650
+ */
3651
+ SET_DATA(ptr, data);
3652
+
3653
+ /*
3654
+ * do decode
3655
+ */
3656
+ ret = rb_protect(do_decode, (VALUE)ptr, &state);
3657
+
3658
+ /*
3659
+ * post process
3660
+ */
3661
+ if (TEST_FLAG(ptr, F_START)) {
3662
+ if (state == 0) {
3663
+ jpeg_finish_decompress(&ptr->cinfo);
3664
+ } else {
3665
+ jpeg_abort_decompress(&ptr->cinfo);
3666
+ }
3667
+
3668
+ CLR_FLAG(ptr, F_START);
3669
+ }
1459
3670
 
1460
- return ret;
3671
+ CLR_DATA(ptr);
3672
+
3673
+ if (state != 0) rb_jump_tag(state);
3674
+
3675
+ return ret;
1461
3676
  }
1462
3677
 
1463
3678
  static VALUE
@@ -1467,28 +3682,19 @@ rb_test_image(VALUE self, VALUE data)
1467
3682
  struct jpeg_decompress_struct cinfo;
1468
3683
  ext_error_t err_mgr;
1469
3684
 
1470
- jpeg_create_decompress(&cinfo);
1471
-
1472
- cinfo.err = jpeg_std_error(&err_mgr.jerr);
1473
-
1474
- err_mgr.jerr.output_message = decode_output_message;
1475
- err_mgr.jerr.emit_message = decode_emit_message;
1476
- err_mgr.jerr.error_exit = decode_error_exit;
1477
-
1478
- cinfo.raw_data_out = FALSE;
1479
- cinfo.dct_method = JDCT_FLOAT;
3685
+ cinfo.raw_data_out = FALSE;
3686
+ cinfo.dct_method = JDCT_FLOAT;
1480
3687
 
1481
3688
  if (setjmp(err_mgr.jmpbuf)) {
1482
- ret = Qtrue;
1483
- } else {
1484
3689
  ret = Qfalse;
1485
3690
 
1486
- jpeg_mem_src(&cinfo, RSTRING_PTR(data), RSTRING_LEN(data));
3691
+ } else {
3692
+ jpeg_mem_src(&cinfo, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
1487
3693
  jpeg_read_header(&cinfo, TRUE);
1488
3694
  jpeg_calc_output_dimensions(&cinfo);
1489
- }
1490
3695
 
1491
- jpeg_destroy_decompress(&cinfo);
3696
+ ret = Qtrue;
3697
+ }
1492
3698
 
1493
3699
  return ret;
1494
3700
  }
@@ -1522,10 +3728,12 @@ Init_jpeg()
1522
3728
 
1523
3729
  meta_klass = rb_define_class_under(module, "Meta", rb_cObject);
1524
3730
  rb_define_attr(meta_klass, "width", 1, 0);
3731
+ rb_define_attr(meta_klass, "stride", 1, 0);
1525
3732
  rb_define_attr(meta_klass, "height", 1, 0);
1526
3733
  rb_define_attr(meta_klass, "original_colorspace", 1, 0);
1527
3734
  rb_define_attr(meta_klass, "output_colorspace", 1, 0);
1528
3735
  rb_define_attr(meta_klass, "num_components", 1, 0);
3736
+ rb_define_attr(meta_klass, "colormap", 1, 0);
1529
3737
 
1530
3738
  decerr_klass = rb_define_class_under(module,
1531
3739
  "DecodeError", rb_eRuntimeError);
@@ -1543,10 +3751,13 @@ Init_jpeg()
1543
3751
  decoder_opts_ids[i] = rb_intern_const(decoder_opts_keys[i]);
1544
3752
  }
1545
3753
 
1546
- id_meta = rb_intern_const("@meta");
1547
- id_width = rb_intern_const("@width");
1548
- id_height = rb_intern_const("@height");
1549
- id_orig_cs = rb_intern_const("@original_colorspace");
1550
- id_out_cs = rb_intern_const("@output_colorspace");
1551
- id_ncompo = rb_intern_const("@num_components");
3754
+ id_meta = rb_intern_const("@meta");
3755
+ id_width = rb_intern_const("@width");
3756
+ id_stride = rb_intern_const("@stride");
3757
+ id_height = rb_intern_const("@height");
3758
+ id_orig_cs = rb_intern_const("@original_colorspace");
3759
+ id_out_cs = rb_intern_const("@output_colorspace");
3760
+ id_ncompo = rb_intern_const("@num_components");
3761
+ id_exif_tags = rb_intern_const("@exif_tags");
3762
+ id_colormap = rb_intern_const("@colormap");
1552
3763
  }