libjpeg-ruby 0.6.2 → 0.7.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.
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