libjpeg-ruby 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/ext/jpeg/jpeg.c +899 -163
  4. data/lib/jpeg/version.rb +1 -1
  5. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fbc3ef237e2de37ab66acc9d4688f2e9c40eb400fecc806aaafa3fdb6cff2c92
4
- data.tar.gz: 2c112043c71e0c4f04760cf25c708e9bd6e2098eaed5b2a5fc588785cc802743
3
+ metadata.gz: 7117f5dece9f78e847213078d1cba56591a30c01ea4b9de58cb4886647d5c530
4
+ data.tar.gz: 7bb5c400d519e4958fb9522c8a3af313931dc033a45c404a288d0d5020f02b7c
5
5
  SHA512:
6
- metadata.gz: a68965a542eee203bca65df1e88ba0dddf6a39a9dd62499e4f1ddb56813f879b47626ffc6bcc5dd14bb54fb83a095161ac340d7506a3cf475c370adf925f118f
7
- data.tar.gz: 3083edd573718ff0d5b5ed6d25dc00efd90c64235c70e10436205a13822b54f967335d1c128eac24985791f63e4fc0f7a58634473a0291fa108a0b0bc55bcf74
6
+ metadata.gz: 457f1b3f55ba6c164a40e66303a9c34df6e9ec590137d161c98cee69bbac1385aa4b309c60feb853637c0c392afabdb356996b6809adefd0ed5827051eb318f6
7
+ data.tar.gz: 9427246e376ff7a9464b0e4c8cf22b0dff47e9036649f13a49a213b769f7ceab7d3e76dbbd258d65c6c65e5c03bda362cf06acc1b921c83bde74bd49d0c8c85f
data/README.md CHANGED
@@ -50,6 +50,7 @@ IO.binwrite("test.bgr", raw)
50
50
  | :expand_colormap | Booblean | T.B.D |
51
51
  | :scale | Rational or Float | T.B.D |
52
52
  | :dct_method | String or Symbol | T.B.D |
53
+ | :with_exif | Boolean | Specify whether to read Exif tag. When set to true, the content of Exif tag will included in the meta information. |
53
54
 
54
55
  #### supported output format
55
56
  RGB RGB24 YUV422 YUYV RGB565 YUV444 YCbCr BGR BGR24 RGBX RGB32 BGRX BGR32
data/ext/jpeg/jpeg.c CHANGED
@@ -22,46 +22,49 @@
22
22
  #include <jpeglib.h>
23
23
 
24
24
  #include "ruby.h"
25
+ #include "ruby/encoding.h"
25
26
 
26
- #define UNIT_LINES 10
27
+ #define UNIT_LINES 10
27
28
 
28
29
  #ifdef DEFAULT_QUALITY
29
30
  #undef DEFAULT_QUALITY
30
31
  #endif /* defined(DEFAULT_QUALITY) */
31
32
 
32
- #define DEFAULT_QUALITY 75
33
- #define DEFAULT_INPUT_COLOR_SPACE JCS_YCbCr
34
- #define DEFAULT_INPUT_COMPONENTS 2
33
+ #define DEFAULT_QUALITY 75
34
+ #define DEFAULT_INPUT_COLOR_SPACE JCS_YCbCr
35
+ #define DEFAULT_INPUT_COMPONENTS 2
35
36
 
36
- #define FMT_YUV422 1
37
- #define FMT_RGB565 2
38
- #define FMT_GRAYSCALE 3
39
- #define FMT_YUV 4
40
- #define FMT_RGB 5
41
- #define FMT_BGR 6
42
- #define FMT_RGB32 7
43
- #define FMT_BGR32 8
37
+ #define FMT_YUV422 1
38
+ #define FMT_RGB565 2
39
+ #define FMT_GRAYSCALE 3
40
+ #define FMT_YUV 4
41
+ #define FMT_RGB 5
42
+ #define FMT_BGR 6
43
+ #define FMT_RGB32 7
44
+ #define FMT_BGR32 8
44
45
 
45
- #define FMT_YVU 20 /* original extend */
46
+ #define FMT_YVU 20 /* original extend */
46
47
 
47
- #define N(x) (sizeof(x)/sizeof(*x))
48
+ #define JPEG_APP1 0xe1 /* Exif marker */
48
49
 
49
- #define RUNTIME_ERROR(msg) rb_raise(rb_eRuntimeError, (msg))
50
- #define ARGUMENT_ERROR(msg) rb_raise(rb_eArgError, (msg))
50
+ #define N(x) (sizeof(x)/sizeof(*x))
51
51
 
52
- #define IS_COLORMAPPED(ci) (((ci)->actual_number_of_colors > 0) &&\
53
- ((ci)->colormap != NULL) && \
54
- ((ci)->output_components == 1) && \
55
- (((ci)->out_color_components == 1) || \
56
- ((ci)->out_color_components == 3)))
52
+ #define RUNTIME_ERROR(msg) rb_raise(rb_eRuntimeError, (msg))
53
+ #define ARGUMENT_ERROR(msg) rb_raise(rb_eArgError, (msg))
54
+
55
+ #define IS_COLORMAPPED(ci) (((ci)->actual_number_of_colors > 0) &&\
56
+ ((ci)->colormap != NULL) && \
57
+ ((ci)->output_components == 1) && \
58
+ (((ci)->out_color_components == 1) || \
59
+ ((ci)->out_color_components == 3)))
57
60
 
58
61
  #define ALLOC_ARRAY() \
59
62
  ((JSAMPARRAY)xmalloc(sizeof(JSAMPROW) * UNIT_LINES))
60
63
  #define ALLOC_ROWS(w,c) \
61
64
  ((JSAMPROW)xmalloc(sizeof(JSAMPLE) * (w) * (c) * UNIT_LINES))
62
65
 
63
- #define EQ_STR(val,str) (rb_to_id(val) == rb_intern(str))
64
- #define EQ_INT(val,n) (FIX2INT(val) == n)
66
+ #define EQ_STR(val,str) (rb_to_id(val) == rb_intern(str))
67
+ #define EQ_INT(val,n) (FIX2INT(val) == n)
65
68
 
66
69
  static VALUE module;
67
70
  static VALUE encoder_klass;
@@ -77,6 +80,168 @@ static ID id_height;
77
80
  static ID id_orig_cs;
78
81
  static ID id_out_cs;
79
82
  static ID id_ncompo;
83
+ static ID id_exif;
84
+
85
+ typedef struct {
86
+ int tag;
87
+ const char* name;
88
+ } tag_entry_t;
89
+
90
+ tag_entry_t tag_tiff[] = {
91
+ /* 0th IFD */
92
+ {0x0100, "image_width", },
93
+ {0x0101, "image_length", },
94
+ {0x0102, "bits_per_sample", },
95
+ {0x0103, "compression", },
96
+ {0x0106, "photometric_interpretation", },
97
+ {0x010e, "image_description", },
98
+ {0x010f, "maker", },
99
+ {0x0110, "model", },
100
+ {0x0111, "strip_offsets", },
101
+ {0x0112, "orientation", },
102
+ {0x0115, "sample_per_pixel", },
103
+ {0x0116, "rows_per_strip", },
104
+ {0x0117, "strip_byte_counts", },
105
+ {0x011a, "x_resolution", },
106
+ {0x011b, "y_resolution", },
107
+ {0x011c, "planer_configuration", },
108
+ {0x0128, "resolution_unit", },
109
+ {0x012d, "transfer_function", },
110
+ {0x0131, "software", },
111
+ {0x0132, "date_time", },
112
+ {0x013b, "artist", },
113
+ {0x013e, "white_point", },
114
+ {0x013f, "primary_chromaticities", },
115
+ {0x0201, "jpeg_interchange_format", },
116
+ {0x0202, "jpeg_interchange_format_length"},
117
+ {0x0211, "ycbcr_coefficients", },
118
+ {0x0212, "ycbcr_sub_sampling", },
119
+ {0x0213, "ycbcr_positioning", },
120
+ {0x0214, "reference_black_white", },
121
+ {0x0d68, "copyright", },
122
+ {0x8298, "copyright", },
123
+ {0x8769, NULL, }, /* ExifIFDPointer */
124
+ {0x8825, NULL, }, /* GPSInfoIFDPointer */
125
+ {0xc4a5, "print_im", },
126
+ };
127
+
128
+ tag_entry_t tag_exif[] = {
129
+ /* Exif IFD */
130
+ {0x829a, "exposure_time", },
131
+ {0x829d, "f_number", },
132
+ {0x8822, "exposure_program", },
133
+ {0x8824, "spectral_sensitivity", },
134
+ {0x8827, "iso_speed_ratings", },
135
+ {0x8828, "oecf", },
136
+ {0x882a, "time_zone_offset", },
137
+ {0x882b, "self_timer_mode", },
138
+ {0x8830, "sensitivity_type", },
139
+ {0x8831, "standard_output_sensitivity", },
140
+ {0x8832, "recommended_exposure_index", },
141
+ {0x9000, "exif_version", },
142
+ {0x9003, "data_time_original", },
143
+ {0x9004, "data_time_digitized", },
144
+ {0x9010, "offset_time", },
145
+ {0x9011, "offset_time_original", },
146
+ {0x9012, "offset_time_digitized", },
147
+ {0x9101, "color_space", },
148
+ {0x9102, "components_configuration", },
149
+ {0x9201, "shutter_speed_value", },
150
+ {0x9202, "apertutre_value", },
151
+ {0x9203, "brightness_value", },
152
+ {0x9204, "exposure_bias_value", },
153
+ {0x9205, "max_aperture_value", },
154
+ {0x9206, "subject_distance", },
155
+ {0x9207, "metering_mode", },
156
+ {0x9208, "light_source", },
157
+ {0x9209, "flash", },
158
+ {0x920a, "focal_length", },
159
+ {0x927c, "marker_note", },
160
+ {0x9286, "user_comment", },
161
+ {0x9290, "sub_sec_time", },
162
+ {0x9291, "sub_sec_time_original", },
163
+ {0x9292, "sub_sec_time_digitized", },
164
+ {0xa000, "flash_pix_version", },
165
+ {0xa001, "color_space", },
166
+ {0xa002, "pixel_x_dimension", },
167
+ {0xa003, "pixel_y_dimension", },
168
+ {0xa004, "related_sound_file", },
169
+ {0xa005, NULL, }, /* InteroperabilityIFDPointer */
170
+ {0xa20b, "flash_energy", },
171
+ {0xa20b, "flash_energy", },
172
+ {0xa20c, "spatial_frequency_response", },
173
+ {0xa20e, "focal_panel_x_resolution", },
174
+ {0xa20f, "focal_panel_y_resolution", },
175
+ {0xa210, "focal_panel_resolution_unit", },
176
+ {0xa214, "subject_location", },
177
+ {0xa215, "exposure_index", },
178
+ {0xa217, "sensing_method", },
179
+ {0xa300, "file_source", },
180
+ {0xa301, "scene_type", },
181
+ {0xa302, "cfa_pattern", },
182
+ {0xa401, "custom_rendered", },
183
+ {0xa402, "exposure_mode", },
184
+ {0xa403, "white_balance", },
185
+ {0xa404, "digital_zoom_ratio", },
186
+ {0xa405, "focal_length_in_35mm_film", },
187
+ {0xa406, "scene_capture_type", },
188
+ {0xa407, "gain_control", },
189
+ {0xa408, "contrast", },
190
+ {0xa409, "sturation", },
191
+ {0xa40a, "sharpness", },
192
+ {0xa40b, "device_setting_description", },
193
+ {0xa40c, "subject_distance_range", },
194
+ {0xa420, "image_unique_id", },
195
+ {0xa430, "owner_name", },
196
+ {0xa431, "serial_number", },
197
+ {0xa432, "lens_info", },
198
+ {0xa433, "lens_make", },
199
+ {0xa434, "lens_model", },
200
+ {0xa435, "lens_serial_number", },
201
+ };
202
+
203
+ tag_entry_t tag_gps[] = {
204
+ /* GPS IFD */
205
+ {0x0000, "version_id", },
206
+ {0x0001, "latitude_ref", },
207
+ {0x0002, "latitude", },
208
+ {0x0003, "longitude_ref", },
209
+ {0x0004, "longitude", },
210
+ {0x0005, "altitude_ref", },
211
+ {0x0006, "altitude", },
212
+ {0x0007, "timestamp", },
213
+ {0x0008, "satellites", },
214
+ {0x0009, "status", },
215
+ {0x000a, "measure_mode", },
216
+ {0x000b, "dop", },
217
+ {0x000c, "speed_ref", },
218
+ {0x000d, "speed", },
219
+ {0x000e, "track_ref", },
220
+ {0x000f, "track", },
221
+ {0x0010, "img_direction_ref", },
222
+ {0x0011, "img_direction", },
223
+ {0x0012, "map_datum", },
224
+ {0x0013, "dest_latitude_ref", },
225
+ {0x0014, "dest_latitude", },
226
+ {0x0015, "dest_longitude_ref", },
227
+ {0x0016, "dest_longitude", },
228
+ {0x0017, "bearing_ref", },
229
+ {0x0018, "bearing", },
230
+ {0x0019, "dest_distance_ref", },
231
+ {0x001a, "dest_distance", },
232
+ {0x001b, "processing_method", },
233
+ {0x001c, "area_infotmation", },
234
+ {0x001d, "date_stamp", },
235
+ {0x001e, "differential", },
236
+ };
237
+
238
+ tag_entry_t tag_i14y[] = {
239
+ /* Interoperability IFD */
240
+ {0x0001, "interoperability_index", },
241
+ {0x0002, "interoperability_version", },
242
+ {0x1000, "related_image_file_format", },
243
+ {0x1001, "related_image_width", },
244
+ };
80
245
 
81
246
  static const char* encoder_opts_keys[] = {
82
247
  "pixel_format", // {str}
@@ -114,7 +279,8 @@ static const char* decoder_opts_keys[] = {
114
279
  "without_meta", // {bool}
115
280
  "expand_colormap", // {bool}
116
281
  "scale", // {rational} or {float}
117
- "dct_method" // {str}
282
+ "dct_method", // {str}
283
+ "with_exif" // {bool}
118
284
  };
119
285
 
120
286
  static ID decoder_opts_ids[N(decoder_opts_keys)];
@@ -130,6 +296,7 @@ typedef struct {
130
296
  int format;
131
297
  int need_meta;
132
298
  int expand_colormap;
299
+ int parse_exif;
133
300
 
134
301
  J_COLOR_SPACE out_color_space;
135
302
  int scale_num;
@@ -152,6 +319,47 @@ typedef struct {
152
319
  ext_error_t err_mgr;
153
320
  } jpeg_decode_t;
154
321
 
322
+
323
+ static VALUE
324
+ lookup_tag_symbol(tag_entry_t* tbl, size_t n, int tag)
325
+ {
326
+ VALUE ret;
327
+ int l;
328
+ int r;
329
+ int i;
330
+ tag_entry_t* p;
331
+ char buf[16];
332
+
333
+ ret = Qundef;
334
+ l = 0;
335
+ r = n - 1;
336
+
337
+ while (r >= l) {
338
+ i = (l + r) / 2;
339
+ p = tbl + i;
340
+
341
+ if (p->tag < tag) {
342
+ l = i + 1;
343
+ continue;
344
+ }
345
+
346
+ if (p->tag > tag) {
347
+ r = i - 1;
348
+ continue;
349
+ }
350
+
351
+ ret = (p->name)? ID2SYM(rb_intern(p->name)): Qnil;
352
+ break;
353
+ }
354
+
355
+ if (ret == Qundef) {
356
+ sprintf(buf, "tag_%04x", tag);
357
+ ret = ID2SYM(rb_intern(buf));
358
+ }
359
+
360
+ return ret;
361
+ }
362
+
155
363
  static void
156
364
  encode_output_message(j_common_ptr cinfo)
157
365
  {
@@ -300,6 +508,9 @@ set_encoder_context(jpeg_encode_t* ptr, int wd, int ht, VALUE opt)
300
508
  /*
301
509
  * eval scale option
302
510
  */
511
+ (void)scale_num;
512
+ (void)scale_denom;
513
+
303
514
  switch (TYPE(opts[2])) {
304
515
  case T_UNDEF:
305
516
  // Nothing
@@ -653,6 +864,7 @@ rb_decoder_alloc(VALUE self)
653
864
  ptr->format = FMT_RGB;
654
865
  ptr->need_meta = !0;
655
866
  ptr->expand_colormap = 0;
867
+ ptr->parse_exif = 0;
656
868
 
657
869
  ptr->out_color_space = JCS_RGB;
658
870
 
@@ -759,44 +971,16 @@ eval_decoder_opt_output_gamma(jpeg_decode_t* ptr, VALUE opt)
759
971
  static void
760
972
  eval_decoder_opt_do_fancy_upsampling(jpeg_decode_t* ptr, VALUE opt)
761
973
  {
762
- switch (TYPE(opt)) {
763
- case T_UNDEF:
764
- // Nothing
765
- break;
766
-
767
- case T_TRUE:
768
- ptr->do_fancy_upsampling = TRUE;
769
- break;
770
-
771
- case T_FALSE:
772
- ptr->do_fancy_upsampling = FALSE;
773
- break;
774
-
775
- default:
776
- ARGUMENT_ERROR("Unsupportd :do_fancy_up_sampling option value.");
777
- break;
974
+ if (opt != Qundef) {
975
+ ptr->do_fancy_upsampling = (RTEST(opt))? TRUE: FALSE;
778
976
  }
779
977
  }
780
978
 
781
979
  static void
782
980
  eval_decoder_opt_do_smoothing(jpeg_decode_t* ptr, VALUE opt)
783
981
  {
784
- switch (TYPE(opt)) {
785
- case T_UNDEF:
786
- // Nothing
787
- break;
788
-
789
- case T_TRUE:
790
- ptr->do_block_smoothing = TRUE;
791
- break;
792
-
793
- case T_FALSE:
794
- ptr->do_block_smoothing = FALSE;
795
- break;
796
-
797
- default:
798
- ARGUMENT_ERROR("Unsupportd :do_smoothing option value.");
799
- break;
982
+ if (opt != Qundef) {
983
+ ptr->do_block_smoothing = (RTEST(opt))? TRUE: FALSE;
800
984
  }
801
985
  }
802
986
 
@@ -836,18 +1020,7 @@ eval_decoder_opt_dither( jpeg_decode_t* ptr, VALUE opt)
836
1020
  ARGUMENT_ERROR("dither mode is illeagal value.");
837
1021
  }
838
1022
 
839
- switch (TYPE(pass2)) {
840
- case T_TRUE:
841
- ptr->two_pass_quantize = TRUE;
842
- break;
843
-
844
- case T_FALSE:
845
- ptr->two_pass_quantize = FALSE;
846
- break;
847
-
848
- default:
849
- ARGUMENT_ERROR( "2pass quantize flag is illeagal value.");
850
- }
1023
+ ptr->two_pass_quantize = (RTEST(pass2))? TRUE: FALSE;
851
1024
 
852
1025
  if (TYPE(n_col) == T_FIXNUM) {
853
1026
  ptr->desired_number_of_colors = FIX2INT(n_col);
@@ -860,113 +1033,55 @@ eval_decoder_opt_dither( jpeg_decode_t* ptr, VALUE opt)
860
1033
  static void
861
1034
  eval_decoder_opt_use_1pass_quantizer(jpeg_decode_t* ptr, VALUE opt)
862
1035
  {
863
- switch (TYPE(opt)) {
864
- case T_UNDEF:
865
- // Nothing
866
- break;
867
-
868
- case T_TRUE:
869
- ptr->enable_1pass_quant = TRUE;
870
- ptr->buffered_image = TRUE;
871
- break;
872
-
873
- case T_FALSE:
874
- ptr->enable_1pass_quant = FALSE;
875
- break;
876
-
877
- default:
878
- ARGUMENT_ERROR("Unsupportd :use_1pass_quantizer option value.");
879
- break;
1036
+ if (opt != Qundef) {
1037
+ if (RTEST(opt)) {
1038
+ ptr->enable_1pass_quant = TRUE;
1039
+ ptr->buffered_image = TRUE;
1040
+ } else {
1041
+ ptr->enable_1pass_quant = FALSE;
1042
+ }
880
1043
  }
881
1044
  }
882
1045
 
883
1046
  static void
884
1047
  eval_decoder_opt_use_external_colormap(jpeg_decode_t* ptr, VALUE opt)
885
1048
  {
886
- switch (TYPE(opt)) {
887
- case T_UNDEF:
888
- // Nothing
889
- break;
890
-
891
- case T_TRUE:
892
- ptr->enable_external_quant = TRUE;
893
- ptr->buffered_image = TRUE;
894
- break;
895
-
896
- case T_FALSE:
897
- ptr->enable_external_quant = FALSE;
898
- break;
899
-
900
- default:
901
- ARGUMENT_ERROR("Unsupportd :use_external_colormap option value.");
902
- break;
1049
+ if (opt != Qundef) {
1050
+ if (RTEST(opt)) {
1051
+ ptr->enable_external_quant = TRUE;
1052
+ ptr->buffered_image = TRUE;
1053
+ } else {
1054
+ ptr->enable_external_quant = FALSE;
1055
+ }
903
1056
  }
904
1057
  }
905
1058
 
906
1059
  static void
907
1060
  eval_decoder_opt_use_2pass_quantizer(jpeg_decode_t* ptr, VALUE opt)
908
1061
  {
909
- switch (TYPE(opt)) {
910
- case T_UNDEF:
911
- // Nothing
912
- break;
913
-
914
- case T_TRUE:
915
- ptr->enable_2pass_quant = TRUE;
916
- ptr->buffered_image = TRUE;
917
- break;
918
-
919
- case T_FALSE:
920
- ptr->enable_2pass_quant = FALSE;
921
- break;
922
-
923
- default:
924
- ARGUMENT_ERROR("Unsupportd :use_2pass_quantizer option value.");
925
- break;
1062
+ if (opt != Qundef) {
1063
+ if (RTEST(opt)) {
1064
+ ptr->enable_2pass_quant = TRUE;
1065
+ ptr->buffered_image = TRUE;
1066
+ } else {
1067
+ ptr->enable_2pass_quant = FALSE;
1068
+ }
926
1069
  }
927
1070
  }
928
1071
 
929
1072
  static void
930
1073
  eval_decoder_opt_without_meta(jpeg_decode_t* ptr, VALUE opt)
931
1074
  {
932
- switch (TYPE(opt)) {
933
- case T_UNDEF:
934
- // Nothing
935
- break;
936
-
937
- case T_TRUE:
938
- ptr->need_meta = 0;
939
- break;
940
-
941
- case T_FALSE:
942
- ptr->need_meta = !0;
943
- break;
944
-
945
- default:
946
- ARGUMENT_ERROR("Unsupportd :without_meta option value.");
947
- break;
1075
+ if (opt != Qundef) {
1076
+ ptr->need_meta = RTEST(opt);
948
1077
  }
949
1078
  }
950
1079
 
951
1080
  static void
952
1081
  eval_decoder_opt_expand_colormap(jpeg_decode_t* ptr, VALUE opt)
953
1082
  {
954
- switch (TYPE(opt)) {
955
- case T_UNDEF:
956
- // Nothing
957
- break;
958
-
959
- case T_TRUE:
960
- ptr->expand_colormap = !0;
961
- break;
962
-
963
- case T_FALSE:
964
- ptr->expand_colormap = 0;
965
- break;
966
-
967
- default:
968
- ARGUMENT_ERROR("Unsupportd :exapnd_colormap option value.");
969
- break;
1083
+ if (opt != Qundef) {
1084
+ ptr->expand_colormap = RTEST(opt);
970
1085
  }
971
1086
  }
972
1087
 
@@ -1016,6 +1131,14 @@ eval_decoder_opt_dct_method(jpeg_decode_t* ptr, VALUE opt)
1016
1131
  }
1017
1132
  }
1018
1133
 
1134
+ static void
1135
+ eval_decoder_opt_with_exif(jpeg_decode_t* ptr, VALUE opt)
1136
+ {
1137
+ if (opt != Qundef) {
1138
+ ptr->parse_exif = RTEST(opt);
1139
+ }
1140
+ }
1141
+
1019
1142
  static void
1020
1143
  set_decoder_context( jpeg_decode_t* ptr, VALUE opt)
1021
1144
  {
@@ -1024,7 +1147,7 @@ set_decoder_context( jpeg_decode_t* ptr, VALUE opt)
1024
1147
  /*
1025
1148
  * parse options
1026
1149
  */
1027
- rb_get_kwargs( opt, decoder_opts_ids, 0, N(decoder_opts_ids), opts);
1150
+ rb_get_kwargs(opt, decoder_opts_ids, 0, N(decoder_opts_ids), opts);
1028
1151
 
1029
1152
  /*
1030
1153
  * set context
@@ -1041,6 +1164,7 @@ set_decoder_context( jpeg_decode_t* ptr, VALUE opt)
1041
1164
  eval_decoder_opt_expand_colormap(ptr, opts[9]);
1042
1165
  eval_decoder_opt_scale(ptr, opts[10]);
1043
1166
  eval_decoder_opt_dct_method(ptr, opts[11]);
1167
+ eval_decoder_opt_with_exif(ptr, opts[12]);
1044
1168
  }
1045
1169
 
1046
1170
  static VALUE
@@ -1072,7 +1196,6 @@ rb_decoder_initialize( int argc, VALUE *argv, VALUE self)
1072
1196
  static VALUE
1073
1197
  rb_decoder_set(VALUE self, VALUE opt)
1074
1198
  {
1075
- VALUE ret;
1076
1199
  jpeg_decode_t* ptr;
1077
1200
 
1078
1201
  /*
@@ -1083,7 +1206,7 @@ rb_decoder_set(VALUE self, VALUE opt)
1083
1206
  /*
1084
1207
  * check argument
1085
1208
  */
1086
- Check_Type( opt, T_HASH);
1209
+ Check_Type(opt, T_HASH);
1087
1210
 
1088
1211
  /*
1089
1212
  * set context
@@ -1170,6 +1293,608 @@ get_colorspace_str( J_COLOR_SPACE cs)
1170
1293
  return rb_str_new_cstr(cstr);
1171
1294
  }
1172
1295
 
1296
+ typedef struct {
1297
+ int be;
1298
+ uint8_t* head;
1299
+ uint8_t* cur;
1300
+ size_t size;
1301
+
1302
+ struct {
1303
+ tag_entry_t* tbl;
1304
+ size_t n;
1305
+ } tags;
1306
+
1307
+ int next;
1308
+ } exif_t;
1309
+
1310
+ static uint16_t
1311
+ get_u16(uint8_t* src, int be)
1312
+ {
1313
+ uint16_t ret;
1314
+
1315
+ if (be) {
1316
+ ret = (((src[0] << 8) & 0xff00)|
1317
+ ((src[1] << 0) & 0x00ff));
1318
+ } else {
1319
+ ret = (((src[1] << 8) & 0xff00)|
1320
+ ((src[0] << 0) & 0x00ff));
1321
+ }
1322
+
1323
+ return ret;
1324
+ }
1325
+
1326
+ /*
1327
+ static int16_t
1328
+ get_s16(uint8_t* src, int be)
1329
+ {
1330
+ int16_t ret;
1331
+
1332
+ if (be) {
1333
+ ret = (((src[0] << 8) & 0xff00)|
1334
+ ((src[1] << 0) & 0x00ff));
1335
+ } else {
1336
+ ret = (((src[1] << 8) & 0xff00)|
1337
+ ((src[0] << 0) & 0x00ff));
1338
+ }
1339
+
1340
+ return ret;
1341
+ }
1342
+ */
1343
+
1344
+ static uint32_t
1345
+ get_u32(uint8_t* src, int be)
1346
+ {
1347
+ uint32_t ret;
1348
+
1349
+ if (be) {
1350
+ ret = (((src[0] << 24) & 0xff000000)|
1351
+ ((src[1] << 16) & 0x00ff0000)|
1352
+ ((src[2] << 8) & 0x0000ff00)|
1353
+ ((src[3] << 0) & 0x000000ff));
1354
+ } else {
1355
+ ret = (((src[3] << 24) & 0xff000000)|
1356
+ ((src[2] << 16) & 0x00ff0000)|
1357
+ ((src[1] << 8) & 0x0000ff00)|
1358
+ ((src[0] << 0) & 0x000000ff));
1359
+ }
1360
+
1361
+ return ret;
1362
+ }
1363
+
1364
+ static int32_t
1365
+ get_s32(uint8_t* src, int be)
1366
+ {
1367
+ int32_t ret;
1368
+
1369
+ if (be) {
1370
+ ret = (((src[0] << 24) & 0xff000000)|
1371
+ ((src[1] << 16) & 0x00ff0000)|
1372
+ ((src[2] << 8) & 0x0000ff00)|
1373
+ ((src[3] << 0) & 0x000000ff));
1374
+ } else {
1375
+ ret = (((src[3] << 24) & 0xff000000)|
1376
+ ((src[2] << 16) & 0x00ff0000)|
1377
+ ((src[1] << 8) & 0x0000ff00)|
1378
+ ((src[0] << 0) & 0x000000ff));
1379
+ }
1380
+
1381
+ return ret;
1382
+ }
1383
+
1384
+ static void
1385
+ exif_increase(exif_t* ptr, size_t size)
1386
+ {
1387
+ ptr->cur += size;
1388
+ ptr->size -= size;
1389
+ }
1390
+
1391
+ static void
1392
+ exif_init(exif_t* ptr, uint8_t* src, size_t size)
1393
+ {
1394
+ int be;
1395
+ uint16_t ident;
1396
+ uint32_t off;
1397
+
1398
+ /*
1399
+ * Check Exif idntifier
1400
+ */
1401
+ if (memcmp(src, "Exif\0\0", 6)) {
1402
+ rb_raise(decerr_klass, "invalid exif identifier");
1403
+ }
1404
+
1405
+ /*
1406
+ * Check TIFF header and judge endian
1407
+ */
1408
+ do {
1409
+ if (!memcmp(src + 6, "MM", 2)) {
1410
+ be = !0;
1411
+ break;
1412
+ }
1413
+
1414
+ if (!memcmp(src + 6, "II", 2)) {
1415
+ be = 0;
1416
+ break;
1417
+ }
1418
+
1419
+ rb_raise(decerr_klass, "invalid tiff header");
1420
+ } while (0);
1421
+
1422
+ /*
1423
+ * Check TIFF identifier
1424
+ */
1425
+ ident = get_u16(src + 8, be);
1426
+ if (ident != 0x002a) {
1427
+ rb_raise(decerr_klass, "invalid tiff identifier");
1428
+ }
1429
+
1430
+ /*
1431
+ * get offset for 0th IFD
1432
+ */
1433
+ off = get_u32(src + 10, be);
1434
+ if (off < 8 || off >= size - 6) {
1435
+ rb_raise(decerr_klass, "invalid offset dentifier");
1436
+ }
1437
+
1438
+ /*
1439
+ * initialize Exif context
1440
+ */
1441
+ ptr->be = be;
1442
+ ptr->head = src + 6;
1443
+ ptr->cur = ptr->head + off;
1444
+ ptr->size = size - (6 + off);
1445
+ ptr->tags.tbl = tag_tiff;
1446
+ ptr->tags.n = N(tag_tiff);
1447
+ ptr->next = 0;
1448
+ }
1449
+
1450
+ static void
1451
+ exif_fetch_tag_header(exif_t* ptr, uint16_t* tag, uint16_t* type)
1452
+ {
1453
+ *tag = get_u16(ptr->cur + 0, ptr->be);
1454
+ *type = get_u16(ptr->cur + 2, ptr->be);
1455
+ }
1456
+
1457
+
1458
+ static void
1459
+ exif_fetch_byte_data(exif_t* ptr, VALUE* dst)
1460
+ {
1461
+ VALUE obj;
1462
+
1463
+ int i;
1464
+ uint32_t n;
1465
+ uint8_t* p;
1466
+
1467
+ n = get_u32(ptr->cur + 4, ptr->be);
1468
+ p = ptr->cur + 8;
1469
+
1470
+ switch (n) {
1471
+ case 0:
1472
+ obj = Qnil;
1473
+ break;
1474
+
1475
+ case 1:
1476
+ obj = INT2FIX(*p);
1477
+ break;
1478
+
1479
+ default:
1480
+ p = ptr->head + get_u32(p, ptr->be);
1481
+
1482
+ case 2:
1483
+ case 3:
1484
+ case 4:
1485
+ obj = rb_ary_new_capa(n);
1486
+ for (i = 0; i < (int)n; i++) {
1487
+ rb_ary_push(obj, INT2FIX(p[i]));
1488
+ }
1489
+ break;
1490
+ }
1491
+
1492
+ *dst = obj;
1493
+ }
1494
+
1495
+ static void
1496
+ exif_fetch_ascii_data(exif_t* ptr, VALUE* dst)
1497
+ {
1498
+ VALUE obj;
1499
+
1500
+ uint32_t n;
1501
+ uint8_t* p;
1502
+
1503
+ n = get_u32(ptr->cur + 4, ptr->be);
1504
+ p = ptr->cur + 8;
1505
+
1506
+ if (n > 4) {
1507
+ p = ptr->head + get_u32(p, ptr->be);
1508
+ }
1509
+
1510
+ obj = rb_utf8_str_new((char*)p, n);
1511
+ rb_funcall(obj, rb_intern("strip!"), 0);
1512
+
1513
+ *dst = obj;
1514
+ }
1515
+
1516
+ static void
1517
+ exif_fetch_short_data(exif_t* ptr, VALUE* dst)
1518
+ {
1519
+ VALUE obj;
1520
+
1521
+ int i;
1522
+ uint32_t n;
1523
+ uint8_t* p;
1524
+
1525
+ n = get_u32(ptr->cur + 4, ptr->be);
1526
+ p = ptr->cur + 8;
1527
+
1528
+ switch (n) {
1529
+ case 0:
1530
+ obj = Qnil;
1531
+ break;
1532
+
1533
+ case 1:
1534
+ obj = INT2FIX(get_u16(p, ptr->be));
1535
+ break;
1536
+
1537
+ default:
1538
+ p = ptr->head + get_u32(p, ptr->be);
1539
+
1540
+ case 2:
1541
+ obj = rb_ary_new_capa(n);
1542
+ for (i = 0; i < (int)n; i++) {
1543
+ rb_ary_push(obj, INT2FIX(get_u16(p, ptr->be)));
1544
+ p += 2;
1545
+ }
1546
+ break;
1547
+ }
1548
+
1549
+ *dst = obj;
1550
+ }
1551
+
1552
+ static void
1553
+ exif_fetch_long_data(exif_t* ptr, VALUE* dst)
1554
+ {
1555
+ VALUE obj;
1556
+
1557
+ int i;
1558
+ uint32_t n;
1559
+ uint8_t* p;
1560
+
1561
+ n = get_u32(ptr->cur + 4, ptr->be);
1562
+ p = ptr->cur + 8;
1563
+
1564
+ switch (n) {
1565
+ case 0:
1566
+ obj = Qnil;
1567
+ break;
1568
+
1569
+ case 1:
1570
+ obj = INT2FIX(get_u32(p, ptr->be));
1571
+ break;
1572
+
1573
+ default:
1574
+ p = ptr->head + get_u32(p, ptr->be);
1575
+ obj = rb_ary_new_capa(n);
1576
+ for (i = 0; i < (int)n; i++) {
1577
+ rb_ary_push(obj, INT2FIX(get_u32(p, ptr->be)));
1578
+ p += 4;
1579
+ }
1580
+ break;
1581
+ }
1582
+
1583
+ *dst = obj;
1584
+ }
1585
+
1586
+ static void
1587
+ exif_fetch_rational_data(exif_t* ptr, VALUE* dst)
1588
+ {
1589
+ VALUE obj;
1590
+
1591
+ int i;
1592
+ uint32_t n;
1593
+ uint8_t* p;
1594
+ uint32_t deno;
1595
+ uint32_t num;
1596
+
1597
+ n = get_u32(ptr->cur + 4, ptr->be);
1598
+ p = ptr->head + get_u32(ptr->cur + 8, ptr->be);
1599
+
1600
+ switch (n) {
1601
+ case 0:
1602
+ obj = Qnil;
1603
+ break;
1604
+
1605
+ case 1:
1606
+ num = get_u32(p + 0, ptr->be);
1607
+ deno = get_u32(p + 4, ptr->be);
1608
+ if (num == 0 && deno == 0) {
1609
+ deno = 1;
1610
+ }
1611
+ obj = rb_rational_new(INT2FIX(num), INT2FIX(deno));
1612
+ break;
1613
+
1614
+ default:
1615
+ obj = rb_ary_new_capa(n);
1616
+ for (i = 0; i < (int)n; i++) {
1617
+ num = get_u32(p + 0, ptr->be);
1618
+ deno = get_u32(p + 4, ptr->be);
1619
+ if (num == 0 && deno == 0) {
1620
+ deno = 1;
1621
+ }
1622
+ rb_ary_push(obj, rb_rational_new(INT2FIX(num), INT2FIX(deno)));
1623
+ p += 8;
1624
+ }
1625
+ break;
1626
+ }
1627
+
1628
+ *dst = obj;
1629
+ }
1630
+
1631
+ static void
1632
+ exif_fetch_undefined_data(exif_t* ptr, VALUE* dst)
1633
+ {
1634
+ VALUE obj;
1635
+
1636
+ uint32_t n;
1637
+ uint8_t* p;
1638
+
1639
+ n = get_u32(ptr->cur + 4, ptr->be);
1640
+ p = ptr->cur + 8;
1641
+
1642
+ if (n > 4) {
1643
+ p = ptr->head + get_u32(p, ptr->be);
1644
+ }
1645
+
1646
+ obj = rb_enc_str_new((char*)p, n, rb_ascii8bit_encoding());
1647
+
1648
+ *dst = obj;
1649
+ }
1650
+
1651
+ static void
1652
+ exif_fetch_slong_data(exif_t* ptr, VALUE* dst)
1653
+ {
1654
+ VALUE obj;
1655
+
1656
+ int i;
1657
+ uint32_t n;
1658
+ uint8_t* p;
1659
+
1660
+ n = get_u32(ptr->cur + 4, ptr->be);
1661
+ p = ptr->cur + 8;
1662
+
1663
+ switch (n) {
1664
+ case 0:
1665
+ obj = Qnil;
1666
+ break;
1667
+
1668
+ case 1:
1669
+ obj = INT2FIX(get_s32(p, ptr->be));
1670
+ break;
1671
+
1672
+ default:
1673
+ p = ptr->head + get_u32(p, ptr->be);
1674
+ obj = rb_ary_new_capa(n);
1675
+ for (i = 0; i < (int)n; i++) {
1676
+ rb_ary_push(obj, INT2FIX(get_s32(p, ptr->be)));
1677
+ p += 4;
1678
+ }
1679
+ break;
1680
+ }
1681
+
1682
+ *dst = obj;
1683
+ }
1684
+
1685
+ static void
1686
+ exif_fetch_srational_data(exif_t* ptr, VALUE* dst)
1687
+ {
1688
+ VALUE obj;
1689
+
1690
+ int i;
1691
+ uint32_t n;
1692
+ uint8_t* p;
1693
+ uint32_t deno;
1694
+ uint32_t num;
1695
+
1696
+ n = get_u32(ptr->cur + 4, ptr->be);
1697
+ p = ptr->head + get_u32(ptr->cur + 8, ptr->be);
1698
+
1699
+ switch (n) {
1700
+ case 0:
1701
+ obj = Qnil;
1702
+ break;
1703
+
1704
+ case 1:
1705
+ num = get_s32(p + 0, ptr->be);
1706
+ deno = get_s32(p + 4, ptr->be);
1707
+ if (num == 0 && deno == 0) {
1708
+ deno = 1;
1709
+ }
1710
+ obj = rb_rational_new(INT2FIX(num), INT2FIX(deno));
1711
+ break;
1712
+
1713
+ default:
1714
+ obj = rb_ary_new_capa(n);
1715
+ for (i = 0; i < (int)n; i++) {
1716
+ num = get_s32(p + 0, ptr->be);
1717
+ deno = get_s32(p + 4, ptr->be);
1718
+ if (num == 0 && deno == 0) {
1719
+ deno = 1;
1720
+ }
1721
+ rb_ary_push(obj, rb_rational_new(INT2FIX(num), INT2FIX(deno)));
1722
+ p += 8;
1723
+ }
1724
+ break;
1725
+ }
1726
+
1727
+ *dst = obj;
1728
+ }
1729
+
1730
+ static void
1731
+ exif_fetch_child_ifd(exif_t* ptr, tag_entry_t* tbl, size_t n, exif_t* dst)
1732
+ {
1733
+ uint32_t off;
1734
+
1735
+ off = get_u32(ptr->cur + 8, ptr->be);
1736
+
1737
+ dst->be = ptr->be;
1738
+ dst->head = ptr->head;
1739
+ dst->cur = ptr->head + off;
1740
+ dst->size = ptr->size - off;
1741
+ dst->tags.tbl = tbl;
1742
+ dst->tags.n = n;
1743
+ dst->next = 0;
1744
+ }
1745
+
1746
+ static int
1747
+ exif_read(exif_t* ptr, VALUE dst)
1748
+ {
1749
+ int ret;
1750
+ int i;
1751
+ uint16_t ntag;
1752
+ uint16_t tag;
1753
+ uint16_t type;
1754
+ uint32_t off;
1755
+
1756
+ exif_t child;
1757
+
1758
+ VALUE key;
1759
+ VALUE val;
1760
+
1761
+ ntag = get_u16(ptr->cur, ptr->be);
1762
+ exif_increase(ptr, 2);
1763
+
1764
+ for (i = 0; i < ntag; i++) {
1765
+ exif_fetch_tag_header(ptr, &tag, &type);
1766
+
1767
+ switch (tag) {
1768
+ case 34665: // ExifIFDPointer
1769
+ key = ID2SYM(rb_intern("exif"));
1770
+ val = rb_hash_new();
1771
+
1772
+ exif_fetch_child_ifd(ptr, tag_exif, N(tag_exif), &child);
1773
+ exif_read(&child, val);
1774
+ break;
1775
+
1776
+ case 34853: // GPSInfoIFDPointer
1777
+ key = ID2SYM(rb_intern("gps"));
1778
+ val = rb_hash_new();
1779
+
1780
+ exif_fetch_child_ifd(ptr, tag_gps, N(tag_gps), &child);
1781
+ exif_read(&child, val);
1782
+ break;
1783
+
1784
+ case 40965: // InteroperabilityIFDPointer
1785
+ key = ID2SYM(rb_intern("interoperability"));
1786
+ val = rb_hash_new();
1787
+
1788
+ exif_fetch_child_ifd(ptr, tag_i14y, N(tag_i14y), &child);
1789
+ exif_read(&child, val);
1790
+ break;
1791
+
1792
+ default:
1793
+ key = lookup_tag_symbol(ptr->tags.tbl, ptr->tags.n, tag);
1794
+
1795
+ switch (type) {
1796
+ case 1: // when BYTE
1797
+ exif_fetch_byte_data(ptr, &val);
1798
+ break;
1799
+
1800
+ case 2: // when ASCII
1801
+ exif_fetch_ascii_data(ptr, &val);
1802
+ break;
1803
+
1804
+ case 3: // when SHORT
1805
+ exif_fetch_short_data(ptr, &val);
1806
+ break;
1807
+
1808
+ case 4: // when LONG
1809
+ exif_fetch_long_data(ptr, &val);
1810
+ break;
1811
+
1812
+ case 5: // when RATIONAL
1813
+ exif_fetch_rational_data(ptr, &val);
1814
+ break;
1815
+
1816
+ case 7: // when UNDEFINED
1817
+ exif_fetch_undefined_data(ptr, &val);
1818
+ break;
1819
+
1820
+ case 9: // when SLONG
1821
+ exif_fetch_slong_data(ptr, &val);
1822
+ break;
1823
+
1824
+ case 10: // when SRATIONAL
1825
+ exif_fetch_srational_data(ptr, &val);
1826
+ break;
1827
+
1828
+ default:
1829
+ rb_raise(decerr_klass, "invalid tag data type");
1830
+ }
1831
+ }
1832
+
1833
+ rb_hash_aset(dst, key, val);
1834
+ exif_increase(ptr, 12);
1835
+ }
1836
+
1837
+ off = get_u32(ptr->cur, ptr->be);
1838
+ if (off != 0) {
1839
+ ptr->cur = ptr->head + off;
1840
+ ptr->next = !0;
1841
+ }
1842
+
1843
+ return ret;
1844
+ }
1845
+
1846
+ #define THUMBNAIL_OFFSET ID2SYM(rb_intern("jpeg_interchange_format"))
1847
+ #define THUMBNAIL_SIZE ID2SYM(rb_intern("jpeg_interchange_format_length"))
1848
+
1849
+ static VALUE
1850
+ create_exif_hash(jpeg_decode_t* ptr)
1851
+ {
1852
+ VALUE ret;
1853
+ jpeg_saved_marker_ptr marker;
1854
+ exif_t exif;
1855
+
1856
+ ret = rb_hash_new();
1857
+
1858
+ for (marker = ptr->cinfo.marker_list;
1859
+ marker != NULL; marker = marker->next) {
1860
+
1861
+ if (marker->data_length < 14) continue;
1862
+ if (memcmp(marker->data, "Exif\0\0", 6)) continue;
1863
+
1864
+ /* 0th IFD */
1865
+ exif_init(&exif, marker->data, marker->data_length);
1866
+ exif_read(&exif, ret);
1867
+
1868
+ if (exif.next) {
1869
+ /* when 1th IFD (tumbnail) exist */
1870
+ VALUE info;
1871
+ VALUE off;
1872
+ VALUE size;
1873
+ VALUE data;
1874
+
1875
+ info = rb_hash_new();
1876
+
1877
+ exif_read(&exif, info);
1878
+
1879
+ off = rb_hash_lookup(info, THUMBNAIL_OFFSET);
1880
+ size = rb_hash_lookup(info, THUMBNAIL_SIZE);
1881
+
1882
+ if (TYPE(off) == T_FIXNUM && TYPE(size) == T_FIXNUM) {
1883
+ data = rb_enc_str_new((char*)exif.head + FIX2INT(off),
1884
+ FIX2INT(size), rb_ascii8bit_encoding());
1885
+
1886
+ rb_hash_lookup(info, THUMBNAIL_OFFSET);
1887
+ rb_hash_lookup(info, THUMBNAIL_SIZE);
1888
+ rb_hash_aset(info, ID2SYM(rb_intern("jpeg_interchange")), data);
1889
+ rb_hash_aset(ret, ID2SYM(rb_intern("thumbnail")), info);
1890
+ }
1891
+ }
1892
+ break;
1893
+ }
1894
+
1895
+ return ret;
1896
+ }
1897
+
1173
1898
  static VALUE
1174
1899
  create_meta(jpeg_decode_t* ptr)
1175
1900
  {
@@ -1178,7 +1903,7 @@ create_meta(jpeg_decode_t* ptr)
1178
1903
 
1179
1904
  /* TODO: そのうちディザをかけた場合のカラーマップをメタで返すようにする */
1180
1905
 
1181
- ret = rb_obj_alloc( meta_klass);
1906
+ ret = rb_obj_alloc(meta_klass);
1182
1907
  cinfo = &ptr->cinfo;
1183
1908
 
1184
1909
  rb_ivar_set(ret, id_width, INT2FIX(cinfo->output_width));
@@ -1193,6 +1918,10 @@ create_meta(jpeg_decode_t* ptr)
1193
1918
 
1194
1919
  rb_ivar_set(ret, id_ncompo, INT2FIX(cinfo->output_components));
1195
1920
 
1921
+ if (ptr->parse_exif) {
1922
+ rb_ivar_set(ret, id_exif, create_exif_hash(ptr));
1923
+ }
1924
+
1196
1925
  return ret;
1197
1926
  }
1198
1927
 
@@ -1223,6 +1952,11 @@ do_read_header(jpeg_decode_t* ptr, uint8_t* jpg, size_t jpg_sz)
1223
1952
  rb_raise(decerr_klass, "%s", ptr->err_mgr.msg);
1224
1953
  } else {
1225
1954
  jpeg_mem_src(&ptr->cinfo, jpg, jpg_sz);
1955
+
1956
+ if (ptr->parse_exif) {
1957
+ jpeg_save_markers(&ptr->cinfo, JPEG_APP1, 0xFFFF);
1958
+ }
1959
+
1226
1960
  jpeg_read_header(&ptr->cinfo, TRUE);
1227
1961
  jpeg_calc_output_dimensions(&ptr->cinfo);
1228
1962
 
@@ -1326,7 +2060,7 @@ swap_cbcr(uint8_t* p, size_t size)
1326
2060
  int i;
1327
2061
  uint8_t tmp;
1328
2062
 
1329
- for (i = 0; i < size; i++) {
2063
+ for (i = 0; i < (int)size; i++) {
1330
2064
  tmp = p[1];
1331
2065
  p[1] = p[2];
1332
2066
  p[2] = tmp;
@@ -1483,7 +2217,7 @@ rb_test_image(VALUE self, VALUE data)
1483
2217
  } else {
1484
2218
  ret = Qfalse;
1485
2219
 
1486
- jpeg_mem_src(&cinfo, RSTRING_PTR(data), RSTRING_LEN(data));
2220
+ jpeg_mem_src(&cinfo, (uint8_t*)RSTRING_PTR(data), RSTRING_LEN(data));
1487
2221
  jpeg_read_header(&cinfo, TRUE);
1488
2222
  jpeg_calc_output_dimensions(&cinfo);
1489
2223
  }
@@ -1526,6 +2260,7 @@ Init_jpeg()
1526
2260
  rb_define_attr(meta_klass, "original_colorspace", 1, 0);
1527
2261
  rb_define_attr(meta_klass, "output_colorspace", 1, 0);
1528
2262
  rb_define_attr(meta_klass, "num_components", 1, 0);
2263
+ rb_define_attr(meta_klass, "exif", 1, 0);
1529
2264
 
1530
2265
  decerr_klass = rb_define_class_under(module,
1531
2266
  "DecodeError", rb_eRuntimeError);
@@ -1543,10 +2278,11 @@ Init_jpeg()
1543
2278
  decoder_opts_ids[i] = rb_intern_const(decoder_opts_keys[i]);
1544
2279
  }
1545
2280
 
1546
- id_meta = rb_intern_const("@meta");
1547
- id_width = rb_intern_const("@width");
1548
- id_height = rb_intern_const("@height");
1549
- id_orig_cs = rb_intern_const("@original_colorspace");
1550
- id_out_cs = rb_intern_const("@output_colorspace");
1551
- id_ncompo = rb_intern_const("@num_components");
2281
+ id_meta = rb_intern_const("@meta");
2282
+ id_width = rb_intern_const("@width");
2283
+ id_height = rb_intern_const("@height");
2284
+ id_orig_cs = rb_intern_const("@original_colorspace");
2285
+ id_out_cs = rb_intern_const("@output_colorspace");
2286
+ id_ncompo = rb_intern_const("@num_components");
2287
+ id_exif = rb_intern_const("@exif");
1552
2288
  }
data/lib/jpeg/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module JPEG
2
- VERSION = "0.6.2"
2
+ VERSION = "0.7.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libjpeg-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroshi Kuwagata
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-05 00:00:00.000000000 Z
11
+ date: 2019-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  requirements: []
91
- rubygems_version: 3.0.1
91
+ rubygems_version: 3.0.3
92
92
  signing_key:
93
93
  specification_version: 4
94
94
  summary: libjpeg interface for ruby