libjpeg-ruby 0.6.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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
  }