axon 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGELOG.rdoc +9 -3
  2. data/README.rdoc +29 -36
  3. data/Rakefile +26 -21
  4. data/TODO.rdoc +1 -6
  5. data/ext/axon/axon.c +6 -15
  6. data/ext/axon/extconf.rb +19 -9
  7. data/ext/axon/interpolation.c +147 -0
  8. data/ext/axon/jpeg.c +1207 -0
  9. data/ext/axon/png.c +542 -0
  10. data/lib/axon.rb +235 -32
  11. data/lib/axon/cropper.rb +80 -18
  12. data/lib/axon/fit.rb +69 -19
  13. data/lib/axon/generators.rb +109 -0
  14. data/lib/axon/scalers.rb +160 -0
  15. data/test/helper.rb +151 -6
  16. data/test/reader_tests.rb +37 -82
  17. data/test/scaler_tests.rb +102 -0
  18. data/test/stress_helper.rb +58 -0
  19. data/test/stress_tests.rb +8 -5
  20. data/test/test_bilinear_scaler.rb +60 -2
  21. data/test/test_cropper.rb +68 -1
  22. data/test/test_fit.rb +35 -0
  23. data/test/test_generators.rb +21 -0
  24. data/test/test_image.rb +61 -0
  25. data/test/test_jpeg_reader.rb +96 -94
  26. data/test/test_jpeg_writer.rb +95 -8
  27. data/test/test_nearest_neighbor_scaler.rb +28 -4
  28. data/test/test_png_reader.rb +12 -8
  29. data/test/test_png_writer.rb +8 -6
  30. data/test/writer_tests.rb +129 -111
  31. metadata +71 -128
  32. data/.gemtest +0 -0
  33. data/ext/axon/bilinear_interpolation.c +0 -115
  34. data/ext/axon/interpolation.h +0 -7
  35. data/ext/axon/jpeg_common.c +0 -118
  36. data/ext/axon/jpeg_common.h +0 -37
  37. data/ext/axon/jpeg_native_writer.c +0 -248
  38. data/ext/axon/jpeg_reader.c +0 -774
  39. data/ext/axon/nearest_neighbor_interpolation.c +0 -50
  40. data/ext/axon/png_common.c +0 -21
  41. data/ext/axon/png_common.h +0 -18
  42. data/ext/axon/png_native_writer.c +0 -166
  43. data/ext/axon/png_reader.c +0 -381
  44. data/lib/axon/axon.so +0 -0
  45. data/lib/axon/bilinear_scaler.rb +0 -60
  46. data/lib/axon/jpeg_writer.rb +0 -41
  47. data/lib/axon/nearest_neighbor_scaler.rb +0 -39
  48. data/lib/axon/png_writer.rb +0 -35
  49. data/lib/axon/scaler.rb +0 -41
  50. data/lib/axon/solid.rb +0 -23
  51. data/test/_test_readme.rb +0 -34
  52. data/test/test_exif.rb +0 -39
  53. data/test/test_generator.rb +0 -10
  54. data/test/test_icc.rb +0 -18
  55. data/test/test_jpeg.rb +0 -9
  56. data/test/test_png.rb +0 -9
@@ -1,37 +0,0 @@
1
- #ifndef AXON_JPEG_COMMON_H
2
- #define AXON_JPEG_COMMON_H
3
-
4
- #include <ruby.h>
5
- #include <jpeglib.h>
6
-
7
- #ifndef HAVE_RB_BLOCK_CALL
8
- #define rb_block_call(arg1, arg2, arg3, arg4, arg5, arg6) rb_iterate(rb_each, arg1, arg5, arg6)
9
- #endif
10
-
11
- /*
12
- * Marker size is defined by two bytes, so the maximum is 65,535 bytes.
13
- * Two of those bytes are used by the size indicator bytes themselves, leaving
14
- * 65,533 bytes.
15
- */
16
-
17
- #define MAX_MARKER_LEN 65533
18
-
19
- /*
20
- * The Exif marker eats 4 bytes for "Exif", and 2 bytes for NULL terminators.
21
- */
22
-
23
- #define EXIF_OVERHEAD_LEN 6
24
- #define MAX_EXIF_DATA_LEN MAX_MARKER_LEN - EXIF_OVERHEAD_LEN
25
- #define EXIF_MARKER (JPEG_APP0 + 1)
26
-
27
- extern struct jpeg_error_mgr jerr;
28
-
29
- ID j_color_space_to_id(J_COLOR_SPACE cs);
30
- J_COLOR_SPACE id_to_j_color_space(ID rb);
31
- int sym_to_marker_code(ID rb);
32
-
33
- void Init_jpeg();
34
- void Init_jpeg_native_writer();
35
- void Init_jpeg_native_reader();
36
-
37
- #endif
@@ -1,248 +0,0 @@
1
- #include "jpeg_common.h"
2
- #include "iccjpeg.h"
3
-
4
- static ID id_write, id_io, id_each, id_width, id_height, id_color_model,
5
- id_components, id_icc_profile, id_exif, id_quality, id_bufsize,
6
- id_image;
7
-
8
- struct buf_dest_mgr {
9
- struct jpeg_destination_mgr pub;
10
-
11
- VALUE io;
12
-
13
- JOCTET *buffer;
14
- size_t alloc;
15
- };
16
-
17
- static void
18
- reset_buffer(struct buf_dest_mgr *dest)
19
- {
20
- dest->pub.next_output_byte = dest->buffer;
21
- dest->pub.free_in_buffer = dest->alloc;
22
- }
23
-
24
- static void
25
- init_destination(j_compress_ptr cinfo)
26
- {
27
- struct buf_dest_mgr *dest = (struct buf_dest_mgr *) cinfo->dest;
28
- size_t size = dest->alloc * sizeof(JOCTET);
29
-
30
- /* Allocate the output buffer --- it will be released when done */
31
- dest->buffer = (JOCTET *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
32
- JPOOL_IMAGE, size);
33
- reset_buffer(dest);
34
- }
35
-
36
- static boolean
37
- empty_output_buffer(j_compress_ptr cinfo)
38
- {
39
- VALUE str, write_len;
40
- struct buf_dest_mgr *dest = (struct buf_dest_mgr *) cinfo->dest;
41
- size_t write_len_i;
42
-
43
- str = rb_str_new(dest->buffer, dest->alloc);
44
-
45
- write_len = rb_funcall(dest->io, id_write, 1, str);
46
- write_len_i = (size_t)FIX2INT(write_len);
47
- if (write_len_i != dest->alloc)
48
- rb_raise(rb_eRuntimeError, "Write Error. Wrote %d instead of %d bytes.",
49
- (int)write_len_i, (int)dest->alloc);
50
-
51
- reset_buffer(dest);
52
-
53
- return TRUE;
54
- }
55
-
56
- static void
57
- term_destination(j_compress_ptr cinfo)
58
- {
59
- struct buf_dest_mgr *dest = (struct buf_dest_mgr *) cinfo->dest;
60
- size_t len = dest->alloc - dest->pub.free_in_buffer;
61
- VALUE str;
62
-
63
- if (len > 0) {
64
- str = rb_str_new(dest->buffer, len);
65
- rb_funcall(dest->io, id_write, 1, str);
66
- }
67
- }
68
-
69
- static VALUE
70
- write_scanline(VALUE scan_line, VALUE data2)
71
- {
72
- JSAMPROW row_pointer[1];
73
- j_compress_ptr cinfo = (j_compress_ptr)data2;
74
-
75
- if (TYPE(scan_line) != T_STRING)
76
- scan_line = rb_obj_as_string(scan_line);
77
-
78
- if (RSTRING_LEN(scan_line) != cinfo->image_width * cinfo->num_components)
79
- rb_raise(rb_eRuntimeError, "Scanline has a bad size. Expected %d but got %d.",
80
- (int)(cinfo->image_width * cinfo->num_components),
81
- (int)RSTRING_LEN(scan_line));
82
-
83
- row_pointer[0] = (JSAMPLE *)RSTRING_PTR(scan_line);
84
- jpeg_write_scanlines(cinfo, row_pointer, 1);
85
- return Qnil;
86
- }
87
-
88
- static int
89
- write_exif(j_compress_ptr cinfo, char *str, int len)
90
- {
91
- if (len > MAX_EXIF_DATA_LEN) {
92
- rb_raise(rb_eRuntimeError, "Exif data is too large. Max is %d.",
93
- MAX_EXIF_DATA_LEN);
94
- }
95
-
96
- jpeg_write_m_header(cinfo, EXIF_MARKER,
97
- (unsigned int) (len + EXIF_OVERHEAD_LEN));
98
-
99
- jpeg_write_m_byte(cinfo, 0x45);
100
- jpeg_write_m_byte(cinfo, 0x78);
101
- jpeg_write_m_byte(cinfo, 0x69);
102
- jpeg_write_m_byte(cinfo, 0x66);
103
- jpeg_write_m_byte(cinfo, 0x0);
104
- jpeg_write_m_byte(cinfo, 0x0);
105
-
106
- /* Add the profile data */
107
- while (len--) {
108
- jpeg_write_m_byte(cinfo, *str);
109
- str++;
110
- }
111
- }
112
-
113
- static void
114
- configure(VALUE self, j_compress_ptr cinfo)
115
- {
116
- VALUE image, width, height, color_model, components, quality;
117
-
118
- quality = rb_funcall(self, id_quality, 0);
119
-
120
- image = rb_funcall(self, id_image, 0);
121
- width = rb_funcall(image, id_width, 0);
122
- height = rb_funcall(image, id_height, 0);
123
- components = rb_funcall(image, id_components, 0);
124
- color_model = rb_funcall(image, id_color_model, 0);
125
-
126
- cinfo->image_width = FIX2INT(width);
127
- cinfo->image_height = FIX2INT(height);
128
- cinfo->input_components = FIX2INT(components);
129
- cinfo->in_color_space = id_to_j_color_space(SYM2ID(color_model));
130
-
131
- jpeg_set_defaults(cinfo);
132
-
133
- if(!NIL_P(quality))
134
- jpeg_set_quality(cinfo, FIX2INT(quality), TRUE);
135
- }
136
-
137
- static void
138
- write_header(VALUE self, j_compress_ptr cinfo)
139
- {
140
- VALUE icc, exif;
141
-
142
- icc = rb_funcall(self, id_icc_profile, 0);
143
- if(!NIL_P(icc)) {
144
- StringValue(icc);
145
- write_icc_profile(cinfo, RSTRING_PTR(icc), RSTRING_LEN(icc));
146
- }
147
-
148
- exif = rb_funcall(self, id_exif, 0);
149
- if (!NIL_P(exif)) {
150
- StringValue(exif);
151
- write_exif(cinfo, RSTRING_PTR(exif), RSTRING_LEN(exif));
152
- }
153
- }
154
-
155
- static VALUE
156
- write2(VALUE *args)
157
- {
158
- VALUE image, self;
159
-
160
- self = args[0];
161
- image = rb_funcall(self, id_image, 0);
162
- j_compress_ptr cinfo = (j_compress_ptr) args[1];
163
-
164
- configure(self, cinfo);
165
-
166
- jpeg_start_compress(cinfo, TRUE);
167
-
168
- write_header(self, cinfo);
169
- rb_block_call(image, id_each, 0, 0, write_scanline, (VALUE)cinfo);
170
-
171
- jpeg_finish_compress(cinfo);
172
-
173
- return Qnil;
174
- }
175
-
176
- static VALUE
177
- write2_ensure(VALUE *args)
178
- {
179
- jpeg_destroy_compress((j_compress_ptr) args[1]);
180
- return Qnil;
181
- }
182
-
183
- /*
184
- * call-seq:
185
- * writer.write -> nil
186
- *
187
- * Compress image and write the jpeg.
188
- */
189
-
190
- static VALUE
191
- jpeg_native_write(VALUE self)
192
- {
193
- struct jpeg_compress_struct cinfo;
194
- struct buf_dest_mgr mgr;
195
- VALUE io, rb_bufsize, ensure_args[2];
196
- int bufsize;
197
-
198
- io = rb_funcall(self, id_io, 0);
199
- rb_bufsize = rb_funcall(self, id_bufsize, 0);
200
- bufsize = FIX2INT(rb_bufsize);
201
-
202
- if (bufsize < 1)
203
- rb_raise(rb_eRuntimeError, "Buffer size must be greater than zero");
204
-
205
- cinfo.err = &jerr;
206
-
207
- jpeg_create_compress(&cinfo);
208
-
209
- mgr.pub.init_destination = init_destination;
210
- mgr.pub.empty_output_buffer = empty_output_buffer;
211
- mgr.pub.term_destination = term_destination;
212
- mgr.alloc = bufsize;
213
- mgr.io = io;
214
- cinfo.dest = (struct jpeg_destination_mgr *)&mgr;
215
-
216
- ensure_args[0] = self;
217
- ensure_args[1] = (VALUE)&cinfo;
218
-
219
- return rb_ensure(write2, (VALUE)ensure_args, write2_ensure,
220
- (VALUE)ensure_args);
221
- }
222
-
223
- /* This module provides a single method #jpeg_native_write. It requires that
224
- * the including class respond to #io, #image, #quality, #exif, #icc_profile,
225
- * and #bufsize.
226
- */
227
-
228
- void
229
- Init_jpeg_native_writer()
230
- {
231
- VALUE mAxon = rb_define_module("Axon");
232
- VALUE mNativeWriter = rb_define_module_under(mAxon, "JPEGNativeWriter");
233
-
234
- rb_define_method(mNativeWriter, "jpeg_native_write", jpeg_native_write, 0);
235
-
236
- id_write = rb_intern("write");
237
- id_each = rb_intern("each");
238
- id_io = rb_intern("io");
239
- id_width = rb_intern("width");
240
- id_height = rb_intern("height");
241
- id_color_model = rb_intern("color_model");
242
- id_components = rb_intern("components");
243
- id_icc_profile = rb_intern("icc_profile");
244
- id_exif = rb_intern("exif");
245
- id_quality = rb_intern("quality");
246
- id_bufsize = rb_intern("bufsize");
247
- id_image = rb_intern("image");
248
- }
@@ -1,774 +0,0 @@
1
- #include "jpeg_common.h"
2
-
3
- static ID id_read, id_rewind, id_ISLOW, id_IFAST, id_FLOAT, id_DEFAULT,
4
- id_FASTEST;
5
-
6
- struct readerdata {
7
- struct jpeg_decompress_struct cinfo;
8
- struct jpeg_source_mgr mgr;
9
-
10
- int header_read;
11
- int locked;
12
- int rewind_after_scanlines;
13
-
14
- VALUE source_io;
15
- VALUE buffer;
16
- };
17
-
18
- static void
19
- raise_if_locked(struct readerdata *reader)
20
- {
21
- if (reader->locked)
22
- rb_raise(rb_eRuntimeError, "Can't modify a locked Reader");
23
- }
24
-
25
- static void
26
- deallocate(struct readerdata *reader)
27
- {
28
- jpeg_destroy_decompress(&reader->cinfo);
29
- free(reader);
30
- }
31
-
32
- static void
33
- mark(struct readerdata *reader)
34
- {
35
- if (!NIL_P(reader->source_io))
36
- rb_gc_mark(reader->source_io);
37
-
38
- if (!NIL_P(reader->buffer))
39
- rb_gc_mark(reader->buffer);
40
- }
41
-
42
- /* Data Source Callbacks */
43
-
44
- static void
45
- init_source(j_decompress_ptr cinfo)
46
- {
47
- /* do nothing */
48
- }
49
-
50
- static void
51
- term_source(j_decompress_ptr cinfo)
52
- {
53
- /* do nothing */
54
- }
55
-
56
- static void
57
- set_input_buffer(struct readerdata *reader, VALUE string)
58
- {
59
- size_t nbytes = 0;
60
- JOCTET *buffer;
61
-
62
- if (!NIL_P(string)) {
63
- StringValue(string);
64
- OBJ_FREEZE(string);
65
- nbytes = (size_t)RSTRING_LEN(string);
66
- buffer = (JOCTET *)RSTRING_PTR(string);
67
- reader->buffer = string;
68
- }
69
-
70
- if (!nbytes) {
71
- nbytes = 2;
72
- reader->buffer = rb_str_new(0, 2);
73
-
74
- buffer = (JOCTET *)RSTRING_PTR(reader->buffer);
75
- buffer[0] = (JOCTET) 0xFF;
76
- buffer[1] = (JOCTET) JPEG_EOI;
77
- }
78
-
79
- reader->mgr.next_input_byte = buffer;
80
- reader->mgr.bytes_in_buffer = nbytes;
81
- }
82
-
83
- static boolean
84
- fill_input_buffer(j_decompress_ptr cinfo)
85
- {
86
- VALUE string;
87
- struct readerdata *reader;
88
-
89
- reader = (struct readerdata *)cinfo;
90
- string = rb_funcall(reader->source_io, id_read, 0);
91
- set_input_buffer(reader, string);
92
-
93
- return TRUE;
94
- }
95
-
96
- static void
97
- skip_input_data(j_decompress_ptr cinfo, long num_bytes)
98
- {
99
- struct jpeg_source_mgr * src = cinfo->src;
100
-
101
- if (num_bytes > 0) {
102
- while (num_bytes > (long) src->bytes_in_buffer) {
103
- num_bytes -= (long) src->bytes_in_buffer;
104
- (void) (*src->fill_input_buffer) (cinfo);
105
- }
106
- src->next_input_byte += (size_t) num_bytes;
107
- src->bytes_in_buffer -= (size_t) num_bytes;
108
- }
109
- }
110
-
111
- static VALUE
112
- allocate(VALUE klass)
113
- {
114
- struct readerdata *reader;
115
- VALUE self;
116
-
117
- self = Data_Make_Struct(klass, struct readerdata, mark, deallocate, reader);
118
-
119
- reader->cinfo.err = &jerr;
120
- jpeg_create_decompress(&reader->cinfo);
121
-
122
- reader->cinfo.src = &reader->mgr;
123
- reader->mgr.init_source = init_source;
124
- reader->mgr.fill_input_buffer = fill_input_buffer;
125
- reader->mgr.skip_input_data = skip_input_data;
126
- reader->mgr.resync_to_restart = jpeg_resync_to_restart;
127
- reader->mgr.term_source = term_source;
128
-
129
- return self;
130
- }
131
-
132
- static VALUE
133
- read_header2(VALUE arg)
134
- {
135
- struct readerdata *reader;
136
-
137
- reader = (struct readerdata *)arg;
138
- jpeg_read_header(&reader->cinfo, TRUE);
139
- reader->header_read = 1;
140
-
141
- return Qnil;
142
- }
143
-
144
- static void
145
- read_header(struct readerdata *reader, VALUE markers)
146
- {
147
- int i, marker_code, state;
148
- j_decompress_ptr cinfo;
149
-
150
- cinfo = &reader->cinfo;
151
-
152
- if (!NIL_P(markers)) {
153
- Check_Type(markers, T_ARRAY);
154
- for (i = 0; i < RARRAY_LEN(markers); i++) {
155
- marker_code = sym_to_marker_code(RARRAY_PTR(markers)[i]);
156
- jpeg_save_markers(cinfo, marker_code, 0xFFFF);
157
- }
158
- }
159
-
160
- rb_protect(read_header2, (VALUE)reader, &state);
161
-
162
- if(state) {
163
- jpeg_abort_decompress(&reader->cinfo);
164
- rb_jump_tag(state);
165
- }
166
-
167
- jpeg_calc_output_dimensions(cinfo);
168
- }
169
-
170
- /*
171
- * call-seq:
172
- * Reader.new(io[, markers, rewind_after_scanlines]) -> reader
173
- *
174
- * Create a new JPEG Reader. string_or_io may be an object that responds to
175
- * read or a string.
176
- *
177
- * markers should be an array of valid JPEG header marker symbols. Valid
178
- * symbols are :APP0 through :APP15 and :COM.
179
- *
180
- * If performance is important, you can avoid reading all header markers by
181
- * supplying an empty array, [].
182
- *
183
- * When markers are not specified, we read all known JPEG markers.
184
- */
185
- static VALUE
186
- initialize(int argc, VALUE *argv, VALUE self)
187
- {
188
- struct readerdata *reader;
189
- j_decompress_ptr cinfo;
190
- VALUE io, markers, rewind_after_scanlines;
191
- int i;
192
-
193
- Data_Get_Struct(self, struct readerdata, reader);
194
- raise_if_locked(reader);
195
- cinfo = &reader->cinfo;
196
-
197
- rb_scan_args(argc, argv, "12", &io, &markers, &rewind_after_scanlines);
198
-
199
- reader->source_io = io;
200
- reader->mgr.bytes_in_buffer = 0;
201
-
202
- if(NIL_P(markers)) {
203
- jpeg_save_markers(cinfo, JPEG_COM, 0xFFFF);
204
-
205
- for (i = 0; i < 16; i++)
206
- jpeg_save_markers(cinfo, JPEG_APP0 + i, 0xFFFF);
207
- }
208
-
209
- reader->rewind_after_scanlines = RTEST(rewind_after_scanlines);
210
- read_header(reader, markers);
211
-
212
- return self;
213
- }
214
-
215
- /*
216
- * call-seq:
217
- * reader.num_components -> number
218
- *
219
- * Retrieve the number of components as stored in the JPEG image.
220
- */
221
- static VALUE
222
- components(VALUE self)
223
- {
224
- struct jpeg_decompress_struct * cinfo;
225
-
226
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
227
-
228
- return INT2FIX(cinfo->num_components);
229
- }
230
-
231
- /*
232
- * call-seq:
233
- * reader.in_color_model -> symbol
234
- *
235
- * Returns a symbol representing the color space in which the JPEG is stored.
236
- *
237
- * This does not have to be set explicitly and can be relied upon when the file
238
- * conforms to JFIF or Adobe conventions. Otherwise it is guessed.
239
- *
240
- * Possible color spaces are: GRAYSCALE, RGB, YCbCr, CMYK, and YCCK. This method
241
- * will return nil if the color space is not recognized.
242
- */
243
- static VALUE
244
- in_color_model(VALUE self)
245
- {
246
- struct jpeg_decompress_struct * cinfo;
247
- ID id;
248
-
249
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
250
- id = j_color_space_to_id(cinfo->jpeg_color_space);
251
-
252
- return ID2SYM(id);
253
- }
254
-
255
- /*
256
- * call-seq:
257
- * reader.color_space = symbol
258
- *
259
- * Explicitly sets the color space the JPEG will be read in. This will override
260
- * the guessed color space.
261
- */
262
- static VALUE
263
- set_in_color_model(VALUE self, VALUE cs)
264
- {
265
- struct readerdata *reader;
266
-
267
- Data_Get_Struct(self, struct readerdata, reader);
268
- raise_if_locked(reader);
269
- reader->cinfo.jpeg_color_space = id_to_j_color_space(SYM2ID(cs));
270
-
271
- return cs;
272
- }
273
-
274
- /*
275
- * call-seq:
276
- * reader.color_model -> symbol
277
- *
278
- * Returns a symbol representing the color space into which the JPEG will be
279
- * transformed as it is read.
280
- *
281
- * By default this color space is based on Reader#color_space.
282
- *
283
- * Possible color spaces are: GRAYSCALE, RGB, YCbCr, CMYK, and YCCK. This method
284
- * will return nil if the color space is not recognized.
285
- */
286
- static VALUE
287
- color_model(VALUE self)
288
- {
289
- ID id;
290
- struct jpeg_decompress_struct * cinfo;
291
-
292
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
293
-
294
- id = j_color_space_to_id(cinfo->out_color_space);
295
- return ID2SYM(id);
296
- }
297
-
298
- /*
299
- * call-seq:
300
- * reader.color_model = symbol
301
- *
302
- * Explicitly sets the color space to which the JPEG will be transformed as it
303
- * is read.
304
- *
305
- * Legal transformations are:
306
- * YCbCr to GRAYSCALE, YCbCr to RGB, GRAYSCALE to RGB, and YCCK to CMYK
307
- */
308
- static VALUE
309
- set_color_model(VALUE self, VALUE cs)
310
- {
311
- struct readerdata *reader;
312
-
313
- Data_Get_Struct(self, struct readerdata, reader);
314
- raise_if_locked(reader);
315
-
316
- reader->cinfo.out_color_space = id_to_j_color_space(SYM2ID(cs));
317
- return cs;
318
- }
319
-
320
- /*
321
- * call-seq:
322
- * reader.scale_num -> number
323
- *
324
- * Retrieve the numerator of the fraction by which the JPEG will be scaled as
325
- * it is read. This is always 1 for libjpeg version 6b. In version 8b this can
326
- * be 1 to 16.
327
- */
328
- static VALUE
329
- scale_num(VALUE self)
330
- {
331
- struct jpeg_decompress_struct * cinfo;
332
-
333
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
334
- return INT2FIX(cinfo->scale_num);
335
- }
336
-
337
- /*
338
- * call-seq:
339
- * reader.scale_num = number
340
- *
341
- * Set the numerator of the fraction by which the JPEG will be scaled as it is
342
- * read. This must always be 1 for libjpeg version 6b. In version 8b this can
343
- * be set to 1 through 16.
344
- */
345
- static VALUE
346
- set_scale_num(VALUE self, VALUE scale_num)
347
- {
348
- struct readerdata *reader;
349
-
350
- Data_Get_Struct(self, struct readerdata, reader);
351
- raise_if_locked(reader);
352
-
353
- reader->cinfo.scale_num = FIX2INT(scale_num);
354
- jpeg_calc_output_dimensions(&reader->cinfo);
355
- return scale_num;
356
- }
357
-
358
- /*
359
- * call-seq:
360
- * reader.scale_denom -> number
361
- *
362
- * Retrieve the denominator of the fraction by which the JPEG will be scaled as
363
- * it is read. This is 1, 2, 4, or 8 for libjpeg version 6b. In version 8b this
364
- * is always the source DCT size, which is 8 for baseline JPEG.
365
- */
366
- static VALUE
367
- scale_denom(VALUE self)
368
- {
369
- struct jpeg_decompress_struct * cinfo;
370
-
371
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
372
-
373
- return INT2FIX(cinfo->scale_denom);
374
- }
375
-
376
- /*
377
- * call-seq:
378
- * reader.scale_denom = number
379
- *
380
- * Set the denominator of the fraction by which the JPEG will be scaled as it is
381
- * read. This can be set to 1, 2, 4, or 8 for libjpeg version 6b. In version 8b
382
- * this must always be the source DCT size, which is 8 for baseline JPEG.
383
- */
384
- static VALUE
385
- set_scale_denom(VALUE self, VALUE scale_denom)
386
- {
387
- struct readerdata *reader;
388
-
389
- Data_Get_Struct(self, struct readerdata, reader);
390
- raise_if_locked(reader);
391
-
392
- reader->cinfo.scale_denom = FIX2INT(scale_denom);
393
- jpeg_calc_output_dimensions(&reader->cinfo);
394
- return scale_denom;
395
- }
396
-
397
- static ID
398
- j_dct_method_to_id(J_DCT_METHOD dct_method)
399
- {
400
- switch (dct_method) {
401
- case JDCT_ISLOW: return id_ISLOW;
402
- case JDCT_IFAST: return id_IFAST;
403
- case JDCT_FLOAT: return id_FLOAT;
404
- }
405
-
406
- return Qnil;
407
- }
408
-
409
- static J_DCT_METHOD
410
- id_to_j_dct_method(ID rb)
411
- {
412
- if (rb == id_ISLOW) return JDCT_ISLOW;
413
- else if (rb == id_IFAST) return JDCT_IFAST;
414
- else if (rb == id_FLOAT) return JDCT_FLOAT;
415
-
416
- return (J_DCT_METHOD)NULL;
417
- }
418
-
419
- /*
420
- * call-seq:
421
- * reader.dct_method -> symbol
422
- *
423
- * Returns a symbol representing the algorithm used for the DCT (discrete cosine
424
- * transform) step in JPEG encoding.
425
- *
426
- * Possible DCT algorithms are: ISLOW, IFAST, and IFLOAT.
427
- */
428
- static VALUE
429
- dct_method(VALUE self)
430
- {
431
- struct jpeg_decompress_struct * cinfo;
432
- ID id;
433
-
434
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
435
-
436
- id = j_dct_method_to_id(cinfo->dct_method);
437
-
438
- if (NIL_P(id))
439
- return Qnil;
440
- else
441
- return ID2SYM(id);
442
- }
443
-
444
- /*
445
- * call-seq:
446
- * reader.dct_method = symbol
447
- *
448
- * Sets the algorithm used for the DCT step in JPEG encoding.
449
- */
450
- static VALUE
451
- set_dct_method(VALUE self, VALUE dct_method)
452
- {
453
- struct readerdata *reader;
454
- J_DCT_METHOD val;
455
-
456
- Data_Get_Struct(self, struct readerdata, reader);
457
- raise_if_locked(reader);
458
-
459
- val = id_to_j_dct_method(SYM2ID(dct_method));
460
- if (val == (J_DCT_METHOD)NULL) {
461
- return Qnil;
462
- } else {
463
- reader->cinfo.dct_method = val;
464
- return dct_method;
465
- }
466
- }
467
-
468
- static VALUE
469
- each3(VALUE arg)
470
- {
471
- struct jpeg_decompress_struct * cinfo;
472
- struct readerdata *reader;
473
- VALUE sl;
474
- int width, height, components, sl_width, i;
475
- JSAMPROW ijg_buffer;
476
-
477
- reader = (struct readerdata *)arg;
478
- cinfo = &reader->cinfo;
479
-
480
- width = cinfo->output_width;
481
- height = cinfo->output_height;
482
- components = cinfo->output_components;
483
-
484
- sl_width = width * components;
485
-
486
- for (i = 0; i < height; i++) {
487
- sl = rb_str_new(0, sl_width);
488
- ijg_buffer = (JSAMPROW)RSTRING_PTR(sl);
489
- jpeg_read_scanlines(cinfo, &ijg_buffer, 1);
490
-
491
- if (rb_block_given_p())
492
- rb_yield(sl);
493
- }
494
-
495
- jpeg_finish_decompress(cinfo);
496
-
497
- return Qnil;
498
- }
499
-
500
- static VALUE
501
- each3_rescue(VALUE arg)
502
- {
503
- struct readerdata *reader;
504
-
505
- reader = (struct readerdata *)arg;
506
- jpeg_abort_decompress(&reader->cinfo);
507
-
508
- return Qnil;
509
- }
510
-
511
- static VALUE
512
- each2(VALUE arg)
513
- {
514
- rb_rescue(each3, arg, each3_rescue, arg);
515
- }
516
-
517
- static VALUE
518
- each2_ensure(VALUE arg)
519
- {
520
- struct readerdata *reader;
521
-
522
- reader = (struct readerdata *)arg;
523
- reader->locked = 0;
524
- reader->header_read = 0;
525
- if (reader->rewind_after_scanlines)
526
- rb_funcall(reader->source_io, id_rewind, 0);
527
-
528
- return Qnil;
529
- }
530
-
531
- /*
532
- * call-seq:
533
- * reader.each_scanline(&block)
534
- *
535
- * Iterate over each decoded scanline in the JPEG image. During this operation
536
- * the reader is locked, and you can't change any decoding parameters or re
537
- * initialize the reader.
538
- *
539
- * Should a major exception occur (anything other than a StandardError), then
540
- * the reader will be left in a locked state.
541
- */
542
- static VALUE
543
- each(VALUE self)
544
- {
545
- struct jpeg_decompress_struct * cinfo;
546
- struct readerdata *reader;
547
-
548
- Data_Get_Struct(self, struct readerdata, reader);
549
- raise_if_locked(reader);
550
-
551
- if (!reader->header_read)
552
- read_header(reader, Qnil);
553
-
554
- reader->locked = 1;
555
- jpeg_start_decompress(&reader->cinfo);
556
-
557
- rb_ensure(each2, (VALUE)reader, each2_ensure, (VALUE)reader);
558
-
559
- return self;
560
- }
561
-
562
- /*
563
- * call-seq:
564
- * reader.width -> number
565
- *
566
- * Retrieve the width of the image as it will be written out. This is primarily
567
- * affected by scale_num and scale_denom if they are set.
568
- *
569
- * Note that this value is not automatically calculated unless you call
570
- * Reader#calc_output_dimensions or after Reader#each_scanline has been called.
571
- */
572
- static VALUE
573
- width(VALUE self)
574
- {
575
- struct jpeg_decompress_struct * cinfo;
576
-
577
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
578
-
579
- return INT2FIX(cinfo->output_width);
580
- }
581
-
582
- /*
583
- * call-seq:
584
- * reader.height -> number
585
- *
586
- * Retrieve the height of the image as it will be written out. This is primarily
587
- * affected by scale_num and scale_denom if they are set.
588
- *
589
- * Note that this value is not automatically calculated unless you call
590
- * Reader#calc_output_dimensions or after Reader#each_scanline has been called.
591
- */
592
- static VALUE
593
- height(VALUE self)
594
- {
595
- struct jpeg_decompress_struct * cinfo;
596
-
597
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
598
-
599
- return INT2FIX(cinfo->output_height);
600
- }
601
-
602
- /*
603
- * call-seq:
604
- * reader.icc_profile -> string
605
- *
606
- * Read the icc_profile from the JPEG. This requires that the APP2 segment
607
- * has been selected by save_markers (this is the default behaviour).
608
- */
609
- static VALUE
610
- icc_profile(VALUE self)
611
- {
612
- struct jpeg_decompress_struct * cinfo;
613
- JOCTET *icc_embed_buffer;
614
- unsigned int icc_embed_len;
615
- VALUE str;
616
-
617
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
618
- read_icc_profile(cinfo, &icc_embed_buffer, &icc_embed_len);
619
-
620
- if (icc_embed_len <= 0) {
621
- return Qnil;
622
- } else {
623
- str = rb_str_new(icc_embed_buffer, icc_embed_len);
624
- free(icc_embed_buffer);
625
- return str;
626
- }
627
- }
628
-
629
- static boolean
630
- marker_is_exif(jpeg_saved_marker_ptr marker)
631
- {
632
- return marker->marker == EXIF_MARKER &&
633
- marker->data_length >= EXIF_OVERHEAD_LEN &&
634
- /* verify the identifying string */
635
- GETJOCTET(marker->data[0]) == 0x45 &&
636
- GETJOCTET(marker->data[1]) == 0x78 &&
637
- GETJOCTET(marker->data[2]) == 0x69 &&
638
- GETJOCTET(marker->data[3]) == 0x66 &&
639
- GETJOCTET(marker->data[4]) == 0x0 &&
640
- GETJOCTET(marker->data[5]) == 0x0;
641
- }
642
-
643
- /*
644
- * call-seq:
645
- * reader.exif -> string
646
- *
647
- * Read the Exif data from the JPEG. This requires that the APP1 segment
648
- * has been selected by save_markers (this is the default behaviour).
649
- */
650
- static VALUE
651
- exif(VALUE self)
652
- {
653
- struct jpeg_decompress_struct * cinfo;
654
- jpeg_saved_marker_ptr marker;
655
- int len;
656
-
657
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
658
-
659
- for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
660
- if (marker_is_exif(marker)) {
661
- len = marker->data_length - EXIF_OVERHEAD_LEN;
662
- return rb_str_new(marker->data + EXIF_OVERHEAD_LEN, len);
663
- }
664
- }
665
-
666
- return Qnil;
667
- }
668
-
669
- /*
670
- * call-seq:
671
- * reader[marker] -> array
672
- *
673
- * Read raw data from the given JPEG header marker. Note that the marker must
674
- * have been specified by Reader#save_markers prior to the call to
675
- * Reader#read_header.
676
- *
677
- * The return from this method is an array, since there may be multiple
678
- * instances of a single marker in a JPEG header.
679
- */
680
- static VALUE
681
- aref(VALUE self, VALUE marker_sym)
682
- {
683
- struct jpeg_decompress_struct * cinfo;
684
- jpeg_saved_marker_ptr marker;
685
- VALUE ary = rb_ary_new();
686
- int marker_i = sym_to_marker_code(marker_sym);
687
-
688
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
689
-
690
- for (marker = cinfo->marker_list; marker != NULL; marker = marker->next)
691
- if (marker->marker == marker_i)
692
- rb_ary_push(ary, rb_str_new(marker->data, marker->data_length));
693
-
694
- return ary;
695
- }
696
-
697
- /*
698
- * call-seq:
699
- * reader.saw_jfif_marker -> boolean
700
- *
701
- * Indicate that a JFIF marker was found in the header.
702
- */
703
- static VALUE
704
- saw_jfif_marker(VALUE self)
705
- {
706
- struct jpeg_decompress_struct * cinfo;
707
-
708
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
709
-
710
- return cinfo->saw_JFIF_marker ? Qtrue : Qfalse;
711
- }
712
-
713
- /*
714
- * call-seq:
715
- * reader.saw_adobe_marker -> boolean
716
- *
717
- * Indicate that an Adobe marker was found in the header.
718
- */
719
- static VALUE
720
- saw_adobe_marker(VALUE self)
721
- {
722
- struct jpeg_decompress_struct * cinfo;
723
-
724
- Data_Get_Struct(self, struct jpeg_decompress_struct, cinfo);
725
-
726
- return cinfo->saw_Adobe_marker ? Qtrue : Qfalse;
727
- }
728
-
729
- void
730
- Init_jpeg_reader()
731
- {
732
- VALUE mAxon = rb_define_module("Axon");
733
- VALUE cJPEGReader = rb_define_class_under(mAxon, "JPEGReader", rb_cObject);
734
- VALUE mImage = rb_define_module_under(mAxon, "Image");
735
-
736
- rb_include_module(cJPEGReader, mImage);
737
- rb_include_module(cJPEGReader, rb_mEnumerable);
738
-
739
- rb_define_alloc_func(cJPEGReader, allocate);
740
-
741
- rb_define_method(cJPEGReader, "initialize", initialize, -1);
742
- rb_define_method(cJPEGReader, "icc_profile", icc_profile, 0);
743
- rb_define_method(cJPEGReader, "exif", exif, 0);
744
- rb_define_method(cJPEGReader, "saw_jfif_marker", saw_jfif_marker, 0);
745
- rb_define_method(cJPEGReader, "saw_adobe_marker", saw_adobe_marker, 0);
746
- rb_define_method(cJPEGReader, "[]", aref, 1);
747
- rb_define_method(cJPEGReader, "in_color_model", in_color_model, 0);
748
- rb_define_method(cJPEGReader, "in_color_model=", set_in_color_model, 1);
749
- rb_define_method(cJPEGReader, "color_model", color_model, 0);
750
- rb_define_method(cJPEGReader, "color_model=", set_color_model, 1);
751
- rb_define_method(cJPEGReader, "components", components, 0);
752
- rb_define_method(cJPEGReader, "scale_num", scale_num, 0);
753
- rb_define_method(cJPEGReader, "scale_num=", set_scale_num, 1);
754
- rb_define_method(cJPEGReader, "scale_denom", scale_denom, 0);
755
- rb_define_method(cJPEGReader, "scale_denom=", set_scale_denom, 1);
756
- rb_define_method(cJPEGReader, "dct_method", dct_method, 0);
757
- rb_define_method(cJPEGReader, "dct_method=", set_dct_method, 1);
758
- rb_define_method(cJPEGReader, "width", width, 0);
759
- rb_define_method(cJPEGReader, "height", height, 0);
760
- rb_define_method(cJPEGReader, "each", each, 0);
761
-
762
- id_read = rb_intern("read");
763
- id_rewind = rb_intern("rewind");
764
- id_IFAST = rb_intern("IFAST");
765
- id_ISLOW = rb_intern("ISLOW");
766
- id_FLOAT = rb_intern("FLOAT");
767
- id_DEFAULT = rb_intern("DEFAULT");
768
- id_FASTEST = rb_intern("FASTEST");
769
-
770
- rb_const_set(cJPEGReader, rb_intern("DEFAULT_DCT"),
771
- ID2SYM(j_dct_method_to_id(JDCT_DEFAULT)));
772
- rb_const_set(cJPEGReader, rb_intern("FASTEST_DCT"),
773
- ID2SYM(j_dct_method_to_id(JDCT_FASTEST)));
774
- }