libjpeg-ruby 0.6.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +8 -0
- data/README.md +3 -0
- data/ext/jpeg/extconf.rb +11 -0
- data/ext/jpeg/jpeg.c +3179 -968
- data/lib/jpeg/version.rb +1 -1
- data/libjpeg-ruby.gemspec +4 -3
- metadata +18 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8bd107f31f10ef4251f056cfc06e2c16082b1d5e42b98a6b810385a171f92991
|
4
|
+
data.tar.gz: eef3261d6619e567a5b063ccd5c72468ab975b4fc80d693ebe49bc3531c76139
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8d4ce1bd5e96f70f26cc167282f1761c5085c0eb901df9c5b948d2ce6bd9aac8cb3006e4d17a28bbed1a7d6ef597dcbbb028529075839aca992ce2e5dd5e55a
|
7
|
+
data.tar.gz: 4e4f0fc6e9a9ec579e50ad00f6f5558caf1753f689e1a5aea8fe7fe11bb188863cbd77f1706591a14532d77be92316b2eb16b912a835ac80bf18ae74952deb57
|
data/.gitignore
ADDED
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
|
|
data/ext/jpeg/extconf.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
require 'optparse'
|
3
|
+
require 'rbconfig'
|
3
4
|
|
4
5
|
OptionParser.new { |opt|
|
5
6
|
opt.on('--with-jpeg-include=PATH', String) { |path|
|
@@ -16,4 +17,14 @@ OptionParser.new { |opt|
|
|
16
17
|
have_library( "jpeg")
|
17
18
|
have_header( "jpeglib.h")
|
18
19
|
|
20
|
+
RbConfig::CONFIG.instance_eval {
|
21
|
+
flag = false
|
22
|
+
|
23
|
+
if /gcc/ =~ self['CC']
|
24
|
+
flag = ['CFLAGS', 'CPPFLAGS'].any? {|s| /-D_FORTIFY_SOURCE/ =~ self[s]}
|
25
|
+
end
|
26
|
+
|
27
|
+
have_library( "ssp") if flag
|
28
|
+
}
|
29
|
+
|
19
30
|
create_makefile( "jpeg/jpeg")
|
data/ext/jpeg/jpeg.c
CHANGED
@@ -4,16 +4,6 @@
|
|
4
4
|
* Copyright (C) 2015 Hiroshi Kuwagata <kgt9221@gmail.com>
|
5
5
|
*/
|
6
6
|
|
7
|
-
/*
|
8
|
-
* $Id: jpeg.c 159 2017-12-17 18:40:28Z pi $
|
9
|
-
*/
|
10
|
-
|
11
|
-
/*
|
12
|
-
* TODO
|
13
|
-
* libjpegのエラーハンドリングを全くやっていないので
|
14
|
-
* いずれ修正する事
|
15
|
-
*/
|
16
|
-
|
17
7
|
#include <stdio.h>
|
18
8
|
#include <stdint.h>
|
19
9
|
#include <strings.h>
|
@@ -22,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
|
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
|
33
|
-
#define DEFAULT_INPUT_COLOR_SPACE
|
34
|
-
#define DEFAULT_INPUT_COMPONENTS
|
35
|
-
|
36
|
-
#define
|
37
|
-
|
38
|
-
#define
|
39
|
-
#define
|
40
|
-
#define
|
41
|
-
#define
|
42
|
-
#define
|
43
|
-
#define
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
#define
|
48
|
-
|
49
|
-
#define
|
50
|
-
|
51
|
-
|
52
|
-
#define
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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)
|
76
|
+
((JSAMPARRAY)malloc(sizeof(JSAMPROW) * UNIT_LINES))
|
60
77
|
#define ALLOC_ROWS(w,c) \
|
61
|
-
((JSAMPROW)
|
78
|
+
((JSAMPROW)malloc(sizeof(JSAMPLE) * (w) * (c) * UNIT_LINES))
|
62
79
|
|
63
|
-
#define EQ_STR(val,str)
|
64
|
-
#define EQ_INT(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
|
-
"
|
85
|
-
"
|
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
|
-
|
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
|
-
|
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"
|
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
|
-
|
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
|
-
|
156
|
-
|
363
|
+
#if 0
|
364
|
+
static VALUE
|
365
|
+
create_runtime_error(const char* fmt, ...)
|
157
366
|
{
|
158
|
-
|
367
|
+
VALUE ret;
|
368
|
+
va_list ap;
|
159
369
|
|
160
|
-
(
|
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
|
164
|
-
|
378
|
+
static VALUE
|
379
|
+
create_argument_error(const char* fmt, ...)
|
165
380
|
{
|
166
|
-
|
381
|
+
VALUE ret;
|
382
|
+
va_list ap;
|
167
383
|
|
168
|
-
(
|
384
|
+
va_start(ap, fmt);
|
385
|
+
ret = rb_exc_new_str(rb_eArgError, rb_vsprintf(fmt, ap));
|
386
|
+
va_end(ap);
|
169
387
|
|
170
|
-
|
171
|
-
rb_raise(encerr_klass, "%s", msg);
|
388
|
+
return ret;
|
172
389
|
}
|
173
390
|
|
174
|
-
|
175
|
-
|
176
|
-
rb_encoder_free( void* _ptr)
|
391
|
+
static VALUE
|
392
|
+
create_type_error(const char* fmt, ...)
|
177
393
|
{
|
178
|
-
|
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
|
-
|
397
|
+
va_start(ap, fmt);
|
398
|
+
ret = rb_exc_new_str(rb_eTypeError, rb_vsprintf(fmt, ap));
|
399
|
+
va_end(ap);
|
186
400
|
|
187
|
-
|
401
|
+
return ret;
|
188
402
|
}
|
189
403
|
|
190
404
|
static VALUE
|
191
|
-
|
405
|
+
create_range_error(const char* fmt, ...)
|
192
406
|
{
|
193
|
-
|
194
|
-
|
195
|
-
ptr = ALLOC(jpeg_encode_t);
|
196
|
-
memset(ptr, 0, sizeof(*ptr));
|
407
|
+
VALUE ret;
|
408
|
+
va_list ap;
|
197
409
|
|
198
|
-
|
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
|
414
|
+
return ret;
|
201
415
|
}
|
202
416
|
|
203
|
-
static
|
204
|
-
|
417
|
+
static VALUE
|
418
|
+
create_not_implement_error(const char* fmt, ...)
|
205
419
|
{
|
206
|
-
VALUE
|
207
|
-
|
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
|
-
|
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
|
-
|
231
|
-
|
232
|
-
color_space = JCS_RGB;
|
233
|
-
components = 3;
|
234
|
-
data_size = (wd * ht * 2);
|
427
|
+
return ret;
|
428
|
+
}
|
235
429
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
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
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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
|
-
|
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
|
-
|
255
|
-
|
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
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
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
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
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
|
-
|
275
|
-
|
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
|
-
|
280
|
-
|
281
|
-
if (opts[1] == Qundef) {
|
282
|
-
quality = DEFAULT_QUALITY;
|
488
|
+
ret = Qundef;
|
489
|
+
l = 0;
|
490
|
+
r = n - 1;
|
283
491
|
|
284
|
-
|
285
|
-
|
286
|
-
|
492
|
+
while (r >= l) {
|
493
|
+
i = (l + r) / 2;
|
494
|
+
p = tbl + i;
|
287
495
|
|
288
|
-
|
289
|
-
|
496
|
+
if (p->tag < tag) {
|
497
|
+
l = i + 1;
|
498
|
+
continue;
|
290
499
|
}
|
291
500
|
|
292
|
-
if (
|
293
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
378
|
-
|
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
|
-
|
525
|
+
if (ptr->data != Qnil) {
|
526
|
+
rb_gc_mark(ptr->data);
|
527
|
+
}
|
405
528
|
}
|
406
529
|
|
407
|
-
static
|
408
|
-
|
530
|
+
static void
|
531
|
+
rb_encoder_free(void* _ptr)
|
409
532
|
{
|
410
|
-
|
411
|
-
int i;
|
412
|
-
|
413
|
-
size = wd * nrow;
|
533
|
+
jpeg_encode_t* ptr;
|
414
534
|
|
415
|
-
|
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
|
-
|
424
|
-
|
537
|
+
if (ptr->array != NULL) {
|
538
|
+
free(ptr->array);
|
425
539
|
}
|
426
540
|
|
427
|
-
|
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
|
-
|
439
|
-
|
440
|
-
|
441
|
-
rows[2] = (data[0] << 3) & 0xf8;
|
545
|
+
if (ptr->buf.mem != NULL) {
|
546
|
+
free(ptr->buf.mem);
|
547
|
+
}
|
442
548
|
|
443
|
-
|
444
|
-
|
549
|
+
if (TEST_FLAG(ptr, F_CREAT)) {
|
550
|
+
jpeg_destroy_compress(&ptr->cinfo);
|
445
551
|
}
|
446
552
|
|
447
|
-
|
553
|
+
free(ptr);
|
448
554
|
}
|
449
555
|
|
450
|
-
static
|
451
|
-
|
556
|
+
static size_t
|
557
|
+
rb_encoder_size(const void* _ptr)
|
452
558
|
{
|
453
|
-
|
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
|
-
|
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
|
-
|
467
|
-
|
564
|
+
ret = sizeof(jpeg_encode_t);
|
565
|
+
ret += sizeof(JSAMPROW) * UNIT_LINES;
|
566
|
+
ret += sizeof(JSAMPLE) * ptr->stride * UNIT_LINES;
|
468
567
|
|
469
|
-
return
|
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
|
-
|
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
|
-
|
603
|
+
jpeg_encode_t* ptr;
|
604
|
+
|
605
|
+
ptr = ALLOC(jpeg_encode_t);
|
606
|
+
memset(ptr, 0, sizeof(*ptr));
|
478
607
|
|
479
|
-
|
480
|
-
memcpy(rows, data, size);
|
608
|
+
ptr->flags = DEFAULT_ENCODE_FLAGS;
|
481
609
|
|
482
|
-
return
|
610
|
+
return TypedData_Wrap_Struct(encoder_klass, &jpeg_encoder_data_type, ptr);
|
483
611
|
}
|
484
612
|
|
485
|
-
static
|
486
|
-
|
613
|
+
static VALUE
|
614
|
+
eval_encoder_pixel_format_opt(jpeg_encode_t* ptr, VALUE opt)
|
487
615
|
{
|
488
|
-
|
616
|
+
VALUE ret;
|
617
|
+
int format;
|
618
|
+
int color_space;
|
619
|
+
int components;
|
489
620
|
|
490
|
-
|
491
|
-
case FMT_YUV422:
|
492
|
-
ret = push_rows_yuv422(ptr->rows, ptr->width, data, nrow);
|
493
|
-
break;
|
621
|
+
ret = Qnil;
|
494
622
|
|
495
|
-
|
496
|
-
|
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
|
500
|
-
case
|
501
|
-
|
502
|
-
|
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
|
-
|
506
|
-
|
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
|
-
|
511
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
527
|
-
|
528
|
-
|
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
|
-
|
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
|
-
|
819
|
+
ret = Qnil;
|
534
820
|
|
535
|
-
|
821
|
+
switch (TYPE(opt)) {
|
822
|
+
case T_UNDEF:
|
823
|
+
stride = ptr->width * ptr->components;
|
824
|
+
break;
|
536
825
|
|
537
|
-
|
538
|
-
|
539
|
-
if (
|
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
|
-
|
542
|
-
|
833
|
+
default:
|
834
|
+
ret = create_type_error("unsupportd :stride option type");
|
543
835
|
}
|
544
836
|
|
545
|
-
|
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
|
-
*
|
918
|
+
* set the rest context parameter
|
549
919
|
*/
|
550
|
-
|
551
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1017
|
+
do {
|
1018
|
+
if (TYPE(wd) != T_FIXNUM) {
|
1019
|
+
exc = create_argument_error("invalid width");
|
1020
|
+
break;
|
1021
|
+
}
|
578
1022
|
|
579
|
-
|
580
|
-
|
581
|
-
|
1023
|
+
if (TYPE(ht) != T_FIXNUM) {
|
1024
|
+
exc = create_argument_error("invalid height");
|
1025
|
+
break;
|
1026
|
+
}
|
1027
|
+
} while (0);
|
582
1028
|
|
583
|
-
|
584
|
-
|
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
|
-
*
|
1037
|
+
* post process
|
589
1038
|
*/
|
590
|
-
|
1039
|
+
if (RTEST(exc)) rb_exc_raise(exc);
|
591
1040
|
|
592
|
-
return
|
1041
|
+
return Qtrue;
|
593
1042
|
}
|
594
1043
|
|
595
1044
|
static void
|
596
|
-
|
1045
|
+
push_rows_yuv422(JSAMPROW dst, int wd, int st, uint8_t* data, int nrow)
|
597
1046
|
{
|
598
|
-
|
1047
|
+
uint8_t* src;
|
1048
|
+
int i;
|
1049
|
+
int j;
|
599
1050
|
|
600
|
-
|
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
|
-
|
1071
|
+
push_rows_rgb565(JSAMPROW dst, int wd, int st, uint8_t* data, int nrow)
|
605
1072
|
{
|
606
|
-
|
1073
|
+
uint8_t* src;
|
1074
|
+
int i;
|
1075
|
+
int j;
|
607
1076
|
|
608
|
-
|
1077
|
+
for (i = 0; i < nrow; i++) {
|
1078
|
+
src = data;
|
609
1079
|
|
610
|
-
|
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
|
-
|
1094
|
+
push_rows_comp3(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
|
615
1095
|
{
|
616
|
-
|
1096
|
+
int size;
|
1097
|
+
int i;
|
617
1098
|
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
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
|
-
|
1110
|
+
push_rows_comp4(JSAMPROW rows, int wd, int st, uint8_t* data, int nrow)
|
637
1111
|
{
|
638
|
-
|
1112
|
+
int size;
|
1113
|
+
int i;
|
639
1114
|
|
640
|
-
|
641
|
-
|
642
|
-
|
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
|
-
|
1199
|
+
do_encode(VALUE _ptr)
|
647
1200
|
{
|
648
|
-
|
1201
|
+
VALUE ret;
|
1202
|
+
jpeg_encode_t* ptr;
|
1203
|
+
uint8_t* data;
|
1204
|
+
int nrow;
|
649
1205
|
|
650
|
-
|
651
|
-
|
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->
|
654
|
-
|
655
|
-
ptr->expand_colormap = 0;
|
1320
|
+
if (ptr->buf.mem != NULL) {
|
1321
|
+
free(ptr->buf.mem);
|
656
1322
|
|
657
|
-
|
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
|
660
|
-
ptr->scale_denom = 1;
|
1337
|
+
ptr = (jpeg_decode_t*)_ptr;
|
661
1338
|
|
662
|
-
ptr->
|
663
|
-
|
664
|
-
|
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
|
-
|
1343
|
+
if (ptr->data != Qnil) {
|
1344
|
+
rb_gc_mark(ptr->data);
|
1345
|
+
}
|
676
1346
|
}
|
677
1347
|
|
678
1348
|
static void
|
679
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
case T_UNDEF:
|
746
|
-
// Nothing
|
747
|
-
break;
|
3005
|
+
/*
|
3006
|
+
* argument check
|
3007
|
+
*/
|
3008
|
+
Check_Type(data, T_STRING);
|
748
3009
|
|
749
|
-
|
750
|
-
|
751
|
-
|
3010
|
+
/*
|
3011
|
+
* prepare
|
3012
|
+
*/
|
3013
|
+
SET_DATA(ptr, data);
|
752
3014
|
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
}
|
3015
|
+
/*
|
3016
|
+
* do encode
|
3017
|
+
*/
|
3018
|
+
ret = rb_protect(do_read_header, (VALUE)ptr, &state);
|
758
3019
|
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
case T_UNDEF:
|
764
|
-
// Nothing
|
765
|
-
break;
|
3020
|
+
/*
|
3021
|
+
* post process
|
3022
|
+
*/
|
3023
|
+
CLR_DATA(ptr);
|
766
3024
|
|
767
|
-
|
768
|
-
ptr->do_fancy_upsampling = TRUE;
|
769
|
-
break;
|
3025
|
+
if (state != 0) rb_jump_tag(state);
|
770
3026
|
|
771
|
-
|
772
|
-
|
773
|
-
break;
|
3027
|
+
return ret;
|
3028
|
+
}
|
774
3029
|
|
775
|
-
|
776
|
-
|
777
|
-
|
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
|
-
|
3037
|
+
add_meta(VALUE obj, jpeg_decode_t* ptr)
|
783
3038
|
{
|
784
|
-
|
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
|
-
|
794
|
-
ptr->do_block_smoothing = FALSE;
|
795
|
-
break;
|
3041
|
+
meta = create_meta(ptr);
|
796
3042
|
|
797
|
-
|
798
|
-
|
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
|
804
|
-
|
3047
|
+
static VALUE
|
3048
|
+
expand_colormap(struct jpeg_decompress_struct* cinfo, uint8_t* src)
|
805
3049
|
{
|
806
|
-
|
807
|
-
|
808
|
-
|
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
|
-
|
816
|
-
|
817
|
-
|
3055
|
+
VALUE ret;
|
3056
|
+
volatile int i; // volatileを外すとaarch64のgcc6でクラッシュする場合がある
|
3057
|
+
int n;
|
3058
|
+
uint8_t* dst;
|
3059
|
+
JSAMPARRAY map;
|
818
3060
|
|
819
|
-
|
820
|
-
|
821
|
-
|
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
|
-
|
828
|
-
|
829
|
-
|
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
|
-
|
832
|
-
|
833
|
-
|
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
|
-
|
836
|
-
ARGUMENT_ERROR("dither mode is illeagal value.");
|
3078
|
+
dst += 2;
|
837
3079
|
}
|
3080
|
+
break;
|
838
3081
|
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
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
|
-
|
849
|
-
ARGUMENT_ERROR( "2pass quantize flag is illeagal value.");
|
3088
|
+
dst += 3;
|
850
3089
|
}
|
3090
|
+
break;
|
851
3091
|
|
852
|
-
|
853
|
-
|
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
|
-
|
3102
|
+
swap_cbcr(uint8_t* p, size_t size)
|
862
3103
|
{
|
863
|
-
|
864
|
-
|
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
|
-
|
878
|
-
|
879
|
-
|
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
|
-
|
3115
|
+
do_transpose8(uint8_t* img, int wd, int ht, void* dst)
|
885
3116
|
{
|
886
|
-
|
887
|
-
|
888
|
-
// Nothing
|
889
|
-
break;
|
3117
|
+
int x;
|
3118
|
+
int y;
|
890
3119
|
|
891
|
-
|
892
|
-
|
893
|
-
ptr->buffered_image = TRUE;
|
894
|
-
break;
|
3120
|
+
uint8_t* sp;
|
3121
|
+
uint8_t* dp;
|
895
3122
|
|
896
|
-
|
897
|
-
ptr->enable_external_quant = FALSE;
|
898
|
-
break;
|
3123
|
+
sp = (uint8_t*)img;
|
899
3124
|
|
900
|
-
|
901
|
-
|
902
|
-
|
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
|
-
|
3138
|
+
do_transpose16(void* img, int wd, int ht, void* dst)
|
908
3139
|
{
|
909
|
-
|
910
|
-
|
911
|
-
// Nothing
|
912
|
-
break;
|
3140
|
+
int x;
|
3141
|
+
int y;
|
913
3142
|
|
914
|
-
|
915
|
-
|
916
|
-
ptr->buffered_image = TRUE;
|
917
|
-
break;
|
3143
|
+
uint16_t* sp;
|
3144
|
+
uint16_t* dp;
|
918
3145
|
|
919
|
-
|
920
|
-
ptr->enable_2pass_quant = FALSE;
|
921
|
-
break;
|
3146
|
+
sp = (uint16_t*)img;
|
922
3147
|
|
923
|
-
|
924
|
-
|
925
|
-
|
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
|
-
|
3161
|
+
do_transpose24(void* img, int wd, int ht, void* dst)
|
931
3162
|
{
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
break;
|
3163
|
+
int x;
|
3164
|
+
int y;
|
3165
|
+
int st;
|
936
3166
|
|
937
|
-
|
938
|
-
|
939
|
-
break;
|
3167
|
+
uint8_t* sp;
|
3168
|
+
uint8_t* dp;
|
940
3169
|
|
941
|
-
|
942
|
-
|
943
|
-
break;
|
3170
|
+
sp = (uint8_t*)img;
|
3171
|
+
st = ht * 3;
|
944
3172
|
|
945
|
-
|
946
|
-
|
947
|
-
|
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
|
-
|
3188
|
+
do_transpose32(void* img, int wd, int ht, void* dst)
|
953
3189
|
{
|
954
|
-
|
955
|
-
|
956
|
-
// Nothing
|
957
|
-
break;
|
3190
|
+
int x;
|
3191
|
+
int y;
|
958
3192
|
|
959
|
-
|
960
|
-
|
961
|
-
break;
|
3193
|
+
uint32_t* sp;
|
3194
|
+
uint32_t* dp;
|
962
3195
|
|
963
|
-
|
964
|
-
ptr->expand_colormap = 0;
|
965
|
-
break;
|
3196
|
+
sp = (uint32_t*)img;
|
966
3197
|
|
967
|
-
|
968
|
-
|
969
|
-
|
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
|
-
|
3211
|
+
do_transpose(void* img, int wd, int ht, int nc, void* dst)
|
975
3212
|
{
|
976
|
-
switch (
|
977
|
-
case
|
978
|
-
|
3213
|
+
switch (nc) {
|
3214
|
+
case 1:
|
3215
|
+
do_transpose8(img, wd, ht, dst);
|
979
3216
|
break;
|
980
3217
|
|
981
|
-
case
|
982
|
-
|
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
|
987
|
-
|
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
|
-
|
992
|
-
|
3226
|
+
case 4:
|
3227
|
+
do_transpose32(img, wd, ht, dst);
|
993
3228
|
break;
|
994
3229
|
}
|
995
3230
|
}
|
996
3231
|
|
997
3232
|
static void
|
998
|
-
|
3233
|
+
do_upside_down8(void* img, int wd, int ht)
|
999
3234
|
{
|
1000
|
-
|
1001
|
-
|
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
|
-
|
1008
|
-
|
3238
|
+
sp = (uint8_t*)img;
|
3239
|
+
dp = (uint8_t*)img + ((wd * ht) - 1);
|
1009
3240
|
|
1010
|
-
|
1011
|
-
|
3241
|
+
while (sp < dp) {
|
3242
|
+
SWAP(*sp, *dp, uint8_t);
|
1012
3243
|
|
1013
|
-
|
1014
|
-
|
1015
|
-
}
|
3244
|
+
sp++;
|
3245
|
+
dp--;
|
1016
3246
|
}
|
1017
3247
|
}
|
1018
3248
|
|
1019
3249
|
static void
|
1020
|
-
|
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
|
-
|
1076
|
-
|
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
|
-
|
1085
|
-
*/
|
1086
|
-
Check_Type( opt, T_HASH);
|
3255
|
+
sp = (uint16_t*)img;
|
3256
|
+
dp = (uint16_t*)img + ((wd * ht) - 1);
|
1087
3257
|
|
1088
|
-
|
1089
|
-
|
1090
|
-
*/
|
1091
|
-
set_decoder_context(ptr, opt);
|
3258
|
+
while (sp < dp) {
|
3259
|
+
SWAP(*sp, *dp, uint8_t);
|
1092
3260
|
|
1093
|
-
|
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
|
-
|
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
|
-
|
1121
|
-
|
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
|
-
|
1129
|
-
|
1130
|
-
|
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
|
-
|
1133
|
-
|
1134
|
-
|
3280
|
+
sp += 3;
|
3281
|
+
dp -= 3;
|
3282
|
+
}
|
3283
|
+
}
|
1135
3284
|
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
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
|
-
|
1141
|
-
|
1142
|
-
break;
|
3291
|
+
sp = (uint32_t*)img;
|
3292
|
+
dp = (uint32_t*)img + ((wd * ht) - 1);
|
1143
3293
|
|
1144
|
-
|
1145
|
-
cstr = "XRGB";
|
1146
|
-
break;
|
3294
|
+
ht /= 2;
|
1147
3295
|
|
1148
|
-
|
1149
|
-
|
1150
|
-
break;
|
3296
|
+
while (sp < dp) {
|
3297
|
+
SWAP(*sp, *dp, uint32_t);
|
1151
3298
|
|
1152
|
-
|
1153
|
-
|
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
|
1157
|
-
|
3312
|
+
case 2:
|
3313
|
+
do_upside_down16(img, wd, ht);
|
1158
3314
|
break;
|
1159
3315
|
|
1160
|
-
case
|
1161
|
-
|
3316
|
+
case 3:
|
3317
|
+
do_upside_down24(img, wd, ht);
|
1162
3318
|
break;
|
1163
|
-
#endif /* JPEG_LIB_VERSION < 90 */
|
1164
3319
|
|
1165
|
-
|
1166
|
-
|
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
|
1174
|
-
|
3326
|
+
static void
|
3327
|
+
do_flip_horizon8(void* img, int wd, int ht)
|
1175
3328
|
{
|
1176
|
-
|
1177
|
-
|
3329
|
+
int y;
|
3330
|
+
int st;
|
1178
3331
|
|
1179
|
-
|
3332
|
+
uint8_t* sp;
|
3333
|
+
uint8_t* dp;
|
1180
3334
|
|
1181
|
-
|
1182
|
-
|
3335
|
+
st = wd;
|
3336
|
+
wd /= 2;
|
1183
3337
|
|
1184
|
-
|
1185
|
-
|
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
|
-
|
1189
|
-
|
1190
|
-
|
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
|
-
|
3345
|
+
sp++;
|
3346
|
+
dp--;
|
3347
|
+
}
|
1195
3348
|
|
1196
|
-
|
3349
|
+
sp = sp - wd + st;
|
3350
|
+
dp = sp + (st - 1);
|
3351
|
+
}
|
1197
3352
|
}
|
1198
3353
|
|
1199
|
-
static
|
1200
|
-
|
3354
|
+
static void
|
3355
|
+
do_flip_horizon16(void* img, int wd, int ht)
|
1201
3356
|
{
|
1202
|
-
|
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
|
-
|
3360
|
+
uint16_t* sp;
|
3361
|
+
uint16_t* dp;
|
1212
3362
|
|
1213
|
-
|
1214
|
-
|
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
|
-
|
1219
|
-
|
3366
|
+
sp = (uint16_t*)img;
|
3367
|
+
dp = (uint16_t*)img + (st - 1);
|
1220
3368
|
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
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
|
-
|
3373
|
+
sp++;
|
3374
|
+
dp--;
|
3375
|
+
}
|
1230
3376
|
|
1231
|
-
|
3377
|
+
sp = sp - wd + st;
|
3378
|
+
dp = sp + (st - 1);
|
1232
3379
|
}
|
1233
|
-
|
1234
|
-
return ret;
|
1235
3380
|
}
|
1236
3381
|
|
1237
|
-
static
|
1238
|
-
|
3382
|
+
static void
|
3383
|
+
do_flip_horizon24(void* img, int wd, int ht)
|
1239
3384
|
{
|
1240
|
-
|
1241
|
-
|
3385
|
+
int y;
|
3386
|
+
int st;
|
1242
3387
|
|
1243
|
-
|
1244
|
-
|
1245
|
-
*/
|
1246
|
-
Data_Get_Struct(self, jpeg_decode_t, ptr);
|
3388
|
+
uint8_t* sp;
|
3389
|
+
uint8_t* dp;
|
1247
3390
|
|
1248
|
-
|
1249
|
-
|
1250
|
-
*/
|
1251
|
-
Check_Type(data, T_STRING);
|
3391
|
+
st = wd * 3;
|
3392
|
+
wd /= 2;
|
1252
3393
|
|
1253
|
-
|
1254
|
-
|
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
|
-
|
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
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
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
|
-
|
3413
|
+
do_flip_horizon32(void* img, int wd, int ht)
|
1269
3414
|
{
|
1270
|
-
|
3415
|
+
int y;
|
3416
|
+
int st;
|
1271
3417
|
|
1272
|
-
|
3418
|
+
uint32_t* sp;
|
3419
|
+
uint32_t* dp;
|
1273
3420
|
|
1274
|
-
|
1275
|
-
|
1276
|
-
}
|
3421
|
+
st = wd;
|
3422
|
+
wd /= 2;
|
1277
3423
|
|
1278
|
-
|
1279
|
-
|
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
|
-
|
1287
|
-
|
1288
|
-
|
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
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
map = cinfo->colormap;
|
3431
|
+
sp++;
|
3432
|
+
dp--;
|
3433
|
+
}
|
1296
3434
|
|
1297
|
-
|
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
|
-
|
1300
|
-
|
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
|
-
|
1306
|
-
|
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
|
-
|
1311
|
-
|
3456
|
+
case 4:
|
3457
|
+
do_flip_horizon32(img, wd, ht);
|
1312
3458
|
break;
|
3459
|
+
}
|
3460
|
+
}
|
1313
3461
|
|
1314
|
-
|
1315
|
-
|
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
|
-
|
3476
|
+
ptr->orientation.buf = img;
|
1319
3477
|
|
1320
3478
|
return ret;
|
1321
3479
|
}
|
1322
3480
|
|
1323
|
-
static
|
1324
|
-
|
3481
|
+
static VALUE
|
3482
|
+
apply_orientation(jpeg_decode_t* ptr, VALUE img)
|
1325
3483
|
{
|
1326
|
-
|
1327
|
-
|
3484
|
+
struct jpeg_decompress_struct* cinfo;
|
3485
|
+
int wd;
|
3486
|
+
int ht;
|
3487
|
+
int nc;
|
3488
|
+
VALUE tmp;
|
1328
3489
|
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
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(
|
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
|
-
|
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 =
|
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
|
-
|
1374
|
-
|
1375
|
-
|
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
|
-
|
1378
|
-
|
3553
|
+
} else {
|
3554
|
+
/*
|
3555
|
+
* normal path
|
3556
|
+
*/
|
3557
|
+
jpeg_mem_src(cinfo, data, size);
|
1379
3558
|
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
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
|
-
|
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
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
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
|
-
|
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
|
-
|
1429
|
-
|
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
|
-
|
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
|
-
|
1443
|
-
|
3631
|
+
VALUE ret;
|
3632
|
+
jpeg_decode_t* ptr;
|
3633
|
+
int state;
|
1444
3634
|
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
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
|
-
|
1457
|
-
|
1458
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
1547
|
-
id_width
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
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
|
}
|