oil 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.rdoc +0 -6
- data/Rakefile +1 -1
- data/ext/oil/jpeg.c +115 -29
- data/ext/oil/png.c +110 -64
- data/ext/oil/yscaler.c +29 -0
- data/ext/oil/yscaler.h +3 -1
- data/lib/oil.rb +59 -33
- data/test/helper.rb +0 -16
- data/test/test_jpeg.rb +101 -17
- data/test/test_png.rb +20 -15
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b39dd91704802e2731a0f67da4743ae67c0535ed
|
4
|
+
data.tar.gz: 9f7767d654f542c11a9fec84f3dc4c097004755c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a862073a15ee977727398689263311dd9868c6c66d518cc840a1e5c7a81f638246b62b1d5d32a4dc2a28d8205a36f4327463a025b4dcb67f491711c19f5d2d5
|
7
|
+
data.tar.gz: 14da2b6aea208767826869a19c6fe8ba4824f15fba435ca1e8862adfe8d19603ce3e7e5a48e66cd693a3afa65c9ee923f6834ac49515c7a6751cd8f23b4e12dd
|
data/README.rdoc
CHANGED
@@ -27,8 +27,6 @@ performance and low memory use.
|
|
27
27
|
|
28
28
|
== REQUIREMENTS:
|
29
29
|
|
30
|
-
These requirements do not apply to the JRuby gem.
|
31
|
-
|
32
30
|
* libjpeg-turbo
|
33
31
|
* libpng
|
34
32
|
|
@@ -48,10 +46,6 @@ Valgrind should not complain (ruby-1.9.3p125, compiled with -O3):
|
|
48
46
|
$ valgrind /path/to/ruby -Iext:test test/test_jpeg.rb
|
49
47
|
$ valgrind /path/to/ruby -Iext:test test/test_png.rb
|
50
48
|
|
51
|
-
Tests should not leak memory:
|
52
|
-
|
53
|
-
$ ruby -Iext:test -e "require 'test_jpeg.rb'; require 'test_png.rb'; loop{ MiniTest.run }"
|
54
|
-
|
55
49
|
Changes to the interpolator should be analyzed using ResampleScope:
|
56
50
|
|
57
51
|
https://github.com/jsummers/resamplescope
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ Rake::ExtensionTask.new('oil') do |ext|
|
|
6
6
|
ext.lib_dir = 'lib/oil'
|
7
7
|
end
|
8
8
|
|
9
|
-
s = Gem::Specification.new('oil', '0.1.
|
9
|
+
s = Gem::Specification.new('oil', '0.1.2') do |s|
|
10
10
|
s.license = 'MIT'
|
11
11
|
s.summary = 'Resize JPEG and PNG images.'
|
12
12
|
s.description = 'Resize JPEG and PNG images, aiming for fast performance and low memory use.'
|
data/ext/oil/jpeg.c
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
#define READ_SIZE 1024
|
8
8
|
#define WRITE_SIZE 1024
|
9
9
|
|
10
|
-
static ID id_GRAYSCALE, id_RGB, id_YCbCr, id_CMYK, id_YCCK, id_UNKNOWN;
|
10
|
+
static ID id_GRAYSCALE, id_RGB, id_YCbCr, id_CMYK, id_YCCK, id_RGBX, id_UNKNOWN;
|
11
11
|
static ID id_APP0, id_APP1, id_APP2, id_APP3, id_APP4, id_APP5, id_APP6,
|
12
12
|
id_APP7, id_APP8, id_APP9, id_APP10, id_APP11, id_APP12, id_APP13,
|
13
13
|
id_APP14, id_APP15, id_COM;
|
@@ -49,6 +49,8 @@ static J_COLOR_SPACE sym_to_j_color_space(VALUE sym)
|
|
49
49
|
return JCS_CMYK;
|
50
50
|
} else if (rb == id_YCCK) {
|
51
51
|
return JCS_YCCK;
|
52
|
+
} else if (rb == id_RGBX) {
|
53
|
+
return JCS_EXT_RGBX;
|
52
54
|
}
|
53
55
|
rb_raise(rb_eRuntimeError, "Color space not recognized.");
|
54
56
|
}
|
@@ -293,10 +295,11 @@ static VALUE initialize(int argc, VALUE *argv, VALUE self)
|
|
293
295
|
*/
|
294
296
|
if (reader->source_io) {
|
295
297
|
jpeg_abort_decompress(dinfo);
|
298
|
+
} else {
|
299
|
+
jpeg_create_decompress(dinfo);
|
296
300
|
}
|
297
301
|
|
298
|
-
|
299
|
-
reader->dinfo.src = &reader->mgr;
|
302
|
+
dinfo->src = &reader->mgr;
|
300
303
|
|
301
304
|
rb_scan_args(argc, argv, "11", &io, &markers);
|
302
305
|
reader->source_io = io;
|
@@ -305,13 +308,16 @@ static VALUE initialize(int argc, VALUE *argv, VALUE self)
|
|
305
308
|
if(!NIL_P(markers)) {
|
306
309
|
Check_Type(markers, T_ARRAY);
|
307
310
|
for (i=0; i<RARRAY_LEN(markers); i++) {
|
311
|
+
if (!SYMBOL_P(RARRAY_PTR(markers)[i])) {
|
312
|
+
rb_raise(rb_eTypeError, "Marker code is not a symbol.");
|
313
|
+
}
|
308
314
|
marker_code = sym_to_marker_code(RARRAY_PTR(markers)[i]);
|
309
315
|
jpeg_save_markers(dinfo, marker_code, 0xFFFF);
|
310
316
|
}
|
311
317
|
}
|
312
318
|
|
313
319
|
/* Be warned that this can raise a ruby exception and longjmp away. */
|
314
|
-
jpeg_read_header(
|
320
|
+
jpeg_read_header(dinfo, TRUE);
|
315
321
|
|
316
322
|
jpeg_calc_output_dimensions(dinfo);
|
317
323
|
|
@@ -320,12 +326,16 @@ static VALUE initialize(int argc, VALUE *argv, VALUE self)
|
|
320
326
|
|
321
327
|
/*
|
322
328
|
* call-seq:
|
323
|
-
* reader.
|
329
|
+
* reader.num_components -> number
|
324
330
|
*
|
325
|
-
* Retrieve the number of components as
|
331
|
+
* Retrieve the number of components per pixel as indicated by the image
|
332
|
+
* header.
|
333
|
+
*
|
334
|
+
* This may differ from the number of components that will be returned by the
|
335
|
+
* decompressor if we ask for a color space transformation.
|
326
336
|
*/
|
327
337
|
|
328
|
-
static VALUE
|
338
|
+
static VALUE num_components(VALUE self)
|
329
339
|
{
|
330
340
|
struct jpeg_decompress_struct * dinfo;
|
331
341
|
Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
|
@@ -334,18 +344,53 @@ static VALUE components(VALUE self)
|
|
334
344
|
|
335
345
|
/*
|
336
346
|
* call-seq:
|
337
|
-
* reader.
|
347
|
+
* reader.output_components -> number
|
348
|
+
*
|
349
|
+
* Retrieve the number of bytes per pixel that will be in the output image.
|
338
350
|
*
|
339
|
-
*
|
351
|
+
* Not all bytes will necessarily have data, since some color spaces have
|
352
|
+
* padding.
|
353
|
+
*/
|
354
|
+
|
355
|
+
static VALUE output_components(VALUE self)
|
356
|
+
{
|
357
|
+
struct jpeg_decompress_struct * dinfo;
|
358
|
+
Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
|
359
|
+
return INT2FIX(dinfo->output_components);
|
360
|
+
}
|
361
|
+
|
362
|
+
/*
|
363
|
+
* call-seq:
|
364
|
+
* reader.out_color_components -> number
|
340
365
|
*
|
341
|
-
*
|
342
|
-
*
|
366
|
+
* Retrieve the number of components in the output color space.
|
367
|
+
*
|
368
|
+
* Some color spaces have padding, so this may not accurately represent the
|
369
|
+
* size of output pixels.
|
370
|
+
*/
|
371
|
+
|
372
|
+
static VALUE out_color_components(VALUE self)
|
373
|
+
{
|
374
|
+
struct jpeg_decompress_struct * dinfo;
|
375
|
+
Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
|
376
|
+
return INT2FIX(dinfo->out_color_components);
|
377
|
+
}
|
378
|
+
|
379
|
+
/*
|
380
|
+
* call-seq:
|
381
|
+
* reader.jpeg_color_space -> symbol
|
382
|
+
*
|
383
|
+
* Returns a symbol representing the color model in which the JPEG is stored,
|
384
|
+
* as indicated by the image header.
|
343
385
|
*
|
344
386
|
* Possible color models are: :GRAYSCALE, :RGB, :YCbCr, :CMYK, and :YCCK. This
|
345
387
|
* method will return :UNKNOWN if the color model is not recognized.
|
388
|
+
*
|
389
|
+
* This may differ from the color space that will be returned by the
|
390
|
+
* decompressor if we ask for a color space transformation.
|
346
391
|
*/
|
347
392
|
|
348
|
-
static VALUE
|
393
|
+
static VALUE jpeg_color_space(VALUE self)
|
349
394
|
{
|
350
395
|
struct jpeg_decompress_struct * dinfo;
|
351
396
|
ID id;
|
@@ -370,7 +415,7 @@ static VALUE out_color_space(VALUE self)
|
|
370
415
|
ID id;
|
371
416
|
|
372
417
|
Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
|
373
|
-
id = j_color_space_to_id(dinfo->
|
418
|
+
id = j_color_space_to_id(dinfo->out_color_space);
|
374
419
|
|
375
420
|
return ID2SYM(id);
|
376
421
|
}
|
@@ -379,7 +424,7 @@ static VALUE out_color_space(VALUE self)
|
|
379
424
|
* call-seq:
|
380
425
|
* reader.out_color_space = symbol
|
381
426
|
*
|
382
|
-
* Set the color model to which
|
427
|
+
* Set the color model to which the image will be converted on decompress.
|
383
428
|
*/
|
384
429
|
|
385
430
|
static VALUE set_out_color_space(VALUE self, VALUE cs)
|
@@ -389,19 +434,22 @@ static VALUE set_out_color_space(VALUE self, VALUE cs)
|
|
389
434
|
Data_Get_Struct(self, struct readerdata, reader);
|
390
435
|
raise_if_locked(reader);
|
391
436
|
|
392
|
-
reader->dinfo.
|
437
|
+
reader->dinfo.out_color_space = sym_to_j_color_space(cs);
|
393
438
|
jpeg_calc_output_dimensions(&reader->dinfo);
|
394
439
|
return cs;
|
395
440
|
}
|
396
441
|
|
397
442
|
/*
|
398
443
|
* call-seq:
|
399
|
-
* reader.
|
444
|
+
* reader.image_width -> number
|
400
445
|
*
|
401
|
-
*
|
446
|
+
* The width of the of the image as indicated by the header.
|
447
|
+
*
|
448
|
+
* This may differ from the width of the image that will be returned by the
|
449
|
+
* decompressor if we request DCT scaling.
|
402
450
|
*/
|
403
451
|
|
404
|
-
static VALUE
|
452
|
+
static VALUE image_width(VALUE self)
|
405
453
|
{
|
406
454
|
struct jpeg_decompress_struct * dinfo;
|
407
455
|
Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
|
@@ -410,18 +458,49 @@ static VALUE width(VALUE self)
|
|
410
458
|
|
411
459
|
/*
|
412
460
|
* call-seq:
|
413
|
-
* reader.
|
461
|
+
* reader.image_height -> number
|
462
|
+
*
|
463
|
+
* The height of the image as indicated by the header.
|
414
464
|
*
|
415
|
-
*
|
465
|
+
* This may differ from the height of the image that will be returned by the
|
466
|
+
* decompressor if we request DCT scaling.
|
416
467
|
*/
|
417
468
|
|
418
|
-
static VALUE
|
469
|
+
static VALUE image_height(VALUE self)
|
419
470
|
{
|
420
471
|
struct jpeg_decompress_struct * dinfo;
|
421
472
|
Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
|
422
473
|
return INT2FIX(dinfo->image_height);
|
423
474
|
}
|
424
475
|
|
476
|
+
/*
|
477
|
+
* call-seq:
|
478
|
+
* reader.output_width -> number
|
479
|
+
*
|
480
|
+
* The width of the of the image that will be output by the decompressor.
|
481
|
+
*/
|
482
|
+
|
483
|
+
static VALUE output_width(VALUE self)
|
484
|
+
{
|
485
|
+
struct jpeg_decompress_struct * dinfo;
|
486
|
+
Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
|
487
|
+
return INT2FIX(dinfo->output_width);
|
488
|
+
}
|
489
|
+
|
490
|
+
/*
|
491
|
+
* call-seq:
|
492
|
+
* reader.image_height -> number
|
493
|
+
*
|
494
|
+
* The height of the image that will be output by the decompressor.
|
495
|
+
*/
|
496
|
+
|
497
|
+
static VALUE output_height(VALUE self)
|
498
|
+
{
|
499
|
+
struct jpeg_decompress_struct * dinfo;
|
500
|
+
Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
|
501
|
+
return INT2FIX(dinfo->output_height);
|
502
|
+
}
|
503
|
+
|
425
504
|
/*
|
426
505
|
* call-seq:
|
427
506
|
* reader.markers -> hash
|
@@ -710,7 +789,12 @@ static VALUE each2(struct write_jpeg_args *args)
|
|
710
789
|
if (!NIL_P(quality)) {
|
711
790
|
jpeg_set_quality(cinfo, FIX2INT(quality), FALSE);
|
712
791
|
}
|
792
|
+
}
|
713
793
|
|
794
|
+
jpeg_start_compress(cinfo, TRUE);
|
795
|
+
jpeg_start_decompress(dinfo);
|
796
|
+
|
797
|
+
if (!NIL_P(args->opts)) {
|
714
798
|
markers = rb_hash_aref(args->opts, sym_markers);
|
715
799
|
if (!NIL_P(markers)) {
|
716
800
|
Check_Type(markers, T_HASH);
|
@@ -718,9 +802,6 @@ static VALUE each2(struct write_jpeg_args *args)
|
|
718
802
|
}
|
719
803
|
}
|
720
804
|
|
721
|
-
jpeg_start_compress(cinfo, TRUE);
|
722
|
-
jpeg_start_decompress(dinfo);
|
723
|
-
|
724
805
|
for(i=0; i<scaley; i++) {
|
725
806
|
while ((yinbuf = yscaler_next(ys))) {
|
726
807
|
jpeg_read_scanlines(dinfo, (JSAMPARRAY)&inwidthbuf, 1);
|
@@ -816,12 +897,16 @@ void Init_jpeg()
|
|
816
897
|
rb_define_alloc_func(cJPEGReader, allocate);
|
817
898
|
rb_define_method(cJPEGReader, "initialize", initialize, -1);
|
818
899
|
rb_define_method(cJPEGReader, "markers", markers, 0);
|
819
|
-
rb_define_method(cJPEGReader, "
|
900
|
+
rb_define_method(cJPEGReader, "jpeg_color_space", jpeg_color_space, 0);
|
820
901
|
rb_define_method(cJPEGReader, "out_color_space", out_color_space, 0);
|
821
|
-
rb_define_method(cJPEGReader, "
|
822
|
-
rb_define_method(cJPEGReader, "
|
823
|
-
rb_define_method(cJPEGReader, "
|
824
|
-
rb_define_method(cJPEGReader, "
|
902
|
+
rb_define_method(cJPEGReader, "out_color_space=", set_out_color_space, 1);
|
903
|
+
rb_define_method(cJPEGReader, "num_components", num_components, 0);
|
904
|
+
rb_define_method(cJPEGReader, "output_components", output_components, 0);
|
905
|
+
rb_define_method(cJPEGReader, "out_color_components", out_color_components, 0);
|
906
|
+
rb_define_method(cJPEGReader, "image_width", image_width, 0);
|
907
|
+
rb_define_method(cJPEGReader, "image_height", image_height, 0);
|
908
|
+
rb_define_method(cJPEGReader, "output_width", output_width, 0);
|
909
|
+
rb_define_method(cJPEGReader, "output_height", output_height, 0);
|
825
910
|
rb_define_method(cJPEGReader, "each", each, -1);
|
826
911
|
rb_define_method(cJPEGReader, "scale_num", scale_num, 0);
|
827
912
|
rb_define_method(cJPEGReader, "scale_num=", set_scale_num, 1);
|
@@ -837,6 +922,7 @@ void Init_jpeg()
|
|
837
922
|
id_YCbCr = rb_intern("YCbCr");
|
838
923
|
id_CMYK = rb_intern("CMYK");
|
839
924
|
id_YCCK = rb_intern("YCCK");
|
925
|
+
id_RGBX = rb_intern("RGBX");
|
840
926
|
id_UNKNOWN = rb_intern("UNKNOWN");
|
841
927
|
id_APP0 = rb_intern("APP0");
|
842
928
|
id_APP1 = rb_intern("APP1");
|
data/ext/oil/png.c
CHANGED
@@ -54,6 +54,7 @@ static void write_data_fn(png_structp png_ptr, png_bytep data, png_size_t length
|
|
54
54
|
static void deallocate(struct readerdata *reader)
|
55
55
|
{
|
56
56
|
png_destroy_read_struct(&reader->png, &reader->info, NULL);
|
57
|
+
free(reader);
|
57
58
|
}
|
58
59
|
|
59
60
|
static void mark(struct readerdata *reader)
|
@@ -63,13 +64,19 @@ static void mark(struct readerdata *reader)
|
|
63
64
|
}
|
64
65
|
}
|
65
66
|
|
67
|
+
static void allocate2(struct readerdata *reader)
|
68
|
+
{
|
69
|
+
reader->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)error, (png_error_ptr)warning);
|
70
|
+
reader->info = png_create_info_struct(reader->png);
|
71
|
+
}
|
72
|
+
|
66
73
|
static VALUE allocate(VALUE klass)
|
67
74
|
{
|
68
75
|
struct readerdata *reader;
|
69
76
|
VALUE self;
|
70
77
|
|
71
78
|
self = Data_Make_Struct(klass, struct readerdata, mark, deallocate, reader);
|
72
|
-
reader
|
79
|
+
allocate2(reader);
|
73
80
|
return self;
|
74
81
|
}
|
75
82
|
|
@@ -88,16 +95,23 @@ static VALUE initialize(VALUE self, VALUE io)
|
|
88
95
|
|
89
96
|
Data_Get_Struct(self, struct readerdata, reader);
|
90
97
|
|
91
|
-
if (reader->
|
98
|
+
if (reader->info) {
|
92
99
|
png_destroy_read_struct(&reader->png, &reader->info, NULL);
|
93
|
-
reader
|
100
|
+
allocate2(reader);
|
94
101
|
reader->locked = 0;
|
95
102
|
}
|
96
103
|
|
97
104
|
reader->source_io = io;
|
98
|
-
reader->info = png_create_info_struct(reader->png);
|
99
105
|
png_set_read_fn(reader->png, (void*)io, read_data);
|
100
106
|
png_read_info(reader->png, reader->info);
|
107
|
+
|
108
|
+
png_set_packing(reader->png);
|
109
|
+
png_set_strip_16(reader->png);
|
110
|
+
png_set_expand(reader->png);
|
111
|
+
png_read_update_info(reader->png, reader->info);
|
112
|
+
|
113
|
+
reader->scale_width = png_get_image_width(reader->png, reader->info);
|
114
|
+
reader->scale_height = png_get_image_height(reader->png, reader->info);
|
101
115
|
return self;
|
102
116
|
}
|
103
117
|
|
@@ -193,54 +207,75 @@ static VALUE set_scale_height(VALUE self, VALUE scale_height)
|
|
193
207
|
return scale_height;
|
194
208
|
}
|
195
209
|
|
196
|
-
struct
|
197
|
-
VALUE opts;
|
210
|
+
struct each_args {
|
198
211
|
struct readerdata *reader;
|
212
|
+
png_structp wpng;
|
213
|
+
png_infop winfo;
|
199
214
|
unsigned char *inwidthbuf;
|
200
215
|
unsigned char *outwidthbuf;
|
201
|
-
|
202
|
-
|
203
|
-
png_infop info;
|
216
|
+
unsigned char **scanlines;
|
217
|
+
struct yscaler ys;
|
204
218
|
};
|
205
219
|
|
206
|
-
static VALUE
|
220
|
+
static VALUE each_interlace(struct each_args *args)
|
221
|
+
{
|
222
|
+
struct readerdata *reader;
|
223
|
+
unsigned char *inwidthbuf, *outwidthbuf;
|
224
|
+
uint32_t i, width, height, scalex, scaley;
|
225
|
+
int cmp;
|
226
|
+
|
227
|
+
reader = args->reader;
|
228
|
+
inwidthbuf = args->inwidthbuf;
|
229
|
+
outwidthbuf = args->outwidthbuf;
|
230
|
+
scalex = reader->scale_width;
|
231
|
+
scaley = reader->scale_height;
|
232
|
+
cmp = png_get_channels(reader->png, reader->info);
|
233
|
+
width = png_get_image_width(reader->png, reader->info);
|
234
|
+
height = png_get_image_height(reader->png, reader->info);
|
235
|
+
|
236
|
+
png_write_info(args->wpng, args->winfo);
|
237
|
+
png_read_image(args->reader->png, (png_bytepp)args->scanlines);
|
238
|
+
|
239
|
+
for (i=0; i<scaley; i++) {
|
240
|
+
yscaler_prealloc_scale(height, scaley,
|
241
|
+
(uint8_t **)args->scanlines, (uint8_t *)inwidthbuf,
|
242
|
+
i, width, cmp, 0);
|
243
|
+
xscale(inwidthbuf, width, outwidthbuf, scalex, cmp, 0);
|
244
|
+
png_write_row(args->wpng, outwidthbuf);
|
245
|
+
}
|
246
|
+
png_write_end(args->wpng, args->winfo);
|
247
|
+
return Qnil;
|
248
|
+
}
|
249
|
+
|
250
|
+
static VALUE each_interlace_none(struct each_args *args)
|
207
251
|
{
|
208
|
-
png_structp png;
|
209
|
-
png_infop info;
|
210
|
-
png_byte ctype;
|
211
252
|
struct readerdata *reader;
|
212
253
|
unsigned char *inwidthbuf, *outwidthbuf, *yinbuf;
|
213
254
|
struct yscaler *ys;
|
214
|
-
uint32_t i, scalex, scaley;
|
255
|
+
uint32_t i, width, scalex, scaley;
|
215
256
|
int cmp;
|
216
257
|
|
217
258
|
reader = args->reader;
|
218
|
-
png = args->png;
|
219
|
-
info = args->info;
|
220
259
|
inwidthbuf = args->inwidthbuf;
|
221
260
|
outwidthbuf = args->outwidthbuf;
|
222
|
-
ys = args->ys;
|
223
|
-
scalex =
|
224
|
-
scaley =
|
225
|
-
|
261
|
+
ys = &args->ys;
|
262
|
+
scalex = reader->scale_width;
|
263
|
+
scaley = reader->scale_height;
|
226
264
|
cmp = png_get_channels(reader->png, reader->info);
|
227
|
-
|
228
|
-
ctype = png_get_color_type(reader->png, reader->info);
|
265
|
+
width = png_get_image_width(reader->png, reader->info);
|
229
266
|
|
230
|
-
|
231
|
-
png_write_info(png, info);
|
267
|
+
png_write_info(args->wpng, args->winfo);
|
232
268
|
|
233
269
|
for(i=0; i<scaley; i++) {
|
234
270
|
while ((yinbuf = yscaler_next(ys))) {
|
235
271
|
png_read_row(reader->png, inwidthbuf, NULL);
|
236
|
-
xscale(inwidthbuf,
|
272
|
+
xscale(inwidthbuf, width, yinbuf, scalex, cmp, 0);
|
237
273
|
}
|
238
274
|
yscaler_scale(ys, outwidthbuf, scalex, cmp, 0);
|
239
|
-
png_write_row(
|
275
|
+
png_write_row(args->wpng, outwidthbuf);
|
240
276
|
}
|
241
277
|
|
242
|
-
png_write_end(
|
243
|
-
|
278
|
+
png_write_end(args->wpng, args->winfo);
|
244
279
|
return Qnil;
|
245
280
|
}
|
246
281
|
|
@@ -261,13 +296,15 @@ static VALUE each2(struct write_png_args *args)
|
|
261
296
|
static VALUE each(int argc, VALUE *argv, VALUE self)
|
262
297
|
{
|
263
298
|
struct readerdata *reader;
|
264
|
-
|
265
|
-
|
266
|
-
unsigned char *inwidthbuf, *outwidthbuf;
|
267
|
-
struct yscaler ys;
|
299
|
+
png_infop winfo;
|
300
|
+
png_structp wpng;
|
268
301
|
VALUE opts;
|
269
|
-
|
270
|
-
|
302
|
+
int cmp, state;
|
303
|
+
struct each_args args;
|
304
|
+
uint32_t i, height;
|
305
|
+
png_byte ctype;
|
306
|
+
unsigned char **scanlines;
|
307
|
+
size_t row_bytes;
|
271
308
|
|
272
309
|
rb_scan_args(argc, argv, "01", &opts);
|
273
310
|
|
@@ -276,41 +313,50 @@ static VALUE each(int argc, VALUE *argv, VALUE self)
|
|
276
313
|
raise_if_locked(reader);
|
277
314
|
reader->locked = 1;
|
278
315
|
|
279
|
-
|
280
|
-
png_set_strip_16(reader->png);
|
281
|
-
png_set_expand(reader->png);
|
282
|
-
png_read_update_info(reader->png, reader->info);
|
283
|
-
|
284
|
-
if (!reader->scale_width) {
|
285
|
-
reader->scale_width = png_get_image_width(reader->png, reader->info);
|
286
|
-
}
|
287
|
-
if (!reader->scale_height) {
|
288
|
-
reader->scale_height = png_get_image_height(reader->png, reader->info);
|
289
|
-
}
|
290
|
-
|
291
|
-
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
|
316
|
+
wpng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
|
292
317
|
(png_error_ptr)error, (png_error_ptr)warning);
|
293
|
-
|
318
|
+
winfo = png_create_info_struct(wpng);
|
319
|
+
png_set_write_fn(wpng, 0, write_data_fn, flush_data_fn);
|
294
320
|
|
295
|
-
inwidthbuf = malloc(png_get_rowbytes(reader->png, reader->info));
|
296
321
|
cmp = png_get_channels(reader->png, reader->info);
|
297
|
-
|
298
|
-
|
299
|
-
|
322
|
+
ctype = png_get_color_type(reader->png, reader->info);
|
323
|
+
|
324
|
+
png_set_IHDR(wpng, winfo, reader->scale_width, reader->scale_height, 8,
|
325
|
+
ctype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
326
|
+
PNG_FILTER_TYPE_DEFAULT);
|
327
|
+
|
328
|
+
height = png_get_image_height(reader->png, reader->info);
|
329
|
+
row_bytes = png_get_rowbytes(reader->png, reader->info);
|
300
330
|
|
301
331
|
args.reader = reader;
|
302
|
-
args.
|
303
|
-
args.
|
304
|
-
args.
|
305
|
-
args.
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
332
|
+
args.wpng = wpng;
|
333
|
+
args.winfo = winfo;
|
334
|
+
args.inwidthbuf = malloc(row_bytes);
|
335
|
+
args.outwidthbuf = malloc(reader->scale_width * cmp);
|
336
|
+
|
337
|
+
if (png_get_interlace_type(reader->png, reader->info) == PNG_INTERLACE_NONE) {
|
338
|
+
yscaler_init(&args.ys, height, reader->scale_height,
|
339
|
+
reader->scale_width * cmp);
|
340
|
+
rb_protect((VALUE(*)(VALUE))each_interlace_none, (VALUE)&args, &state);
|
341
|
+
yscaler_free(&args.ys);
|
342
|
+
} else {
|
343
|
+
scanlines = malloc(height * sizeof(unsigned char *));
|
344
|
+
for (i=0; i<height; i++) {
|
345
|
+
scanlines[i] = malloc(row_bytes);
|
346
|
+
}
|
347
|
+
|
348
|
+
args.scanlines = scanlines;
|
349
|
+
rb_protect((VALUE(*)(VALUE))each_interlace, (VALUE)&args, &state);
|
350
|
+
|
351
|
+
for (i=0; i<height; i++) {
|
352
|
+
free(scanlines[i]);
|
353
|
+
}
|
354
|
+
free(scanlines);
|
355
|
+
}
|
356
|
+
|
357
|
+
free(args.inwidthbuf);
|
358
|
+
free(args.outwidthbuf);
|
359
|
+
png_destroy_write_struct(&wpng, &winfo);
|
314
360
|
|
315
361
|
if (state) {
|
316
362
|
rb_jump_tag(state);
|
data/ext/oil/yscaler.c
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#include "yscaler.h"
|
2
|
+
#include "resample.h"
|
2
3
|
#include <stdlib.h>
|
3
4
|
#include <stdint.h>
|
4
5
|
|
@@ -136,3 +137,31 @@ void yscaler_scale(struct yscaler *ys, uint8_t *out, uint32_t width,
|
|
136
137
|
ys->out_pos++;
|
137
138
|
yscaler_map_pos(ys);
|
138
139
|
}
|
140
|
+
|
141
|
+
void yscaler_prealloc_scale(uint32_t in_height, uint32_t out_height,
|
142
|
+
uint8_t **in, uint8_t *out, uint32_t pos, uint32_t width, uint8_t cmp,
|
143
|
+
uint8_t opts)
|
144
|
+
{
|
145
|
+
uint32_t i, taps;
|
146
|
+
int32_t smp_i, strip_pos;
|
147
|
+
uint8_t **virt;
|
148
|
+
float ty;
|
149
|
+
|
150
|
+
taps = calc_taps(in_height, out_height);
|
151
|
+
virt = malloc(taps * sizeof(uint8_t *));
|
152
|
+
smp_i = split_map(in_height, out_height, pos, &ty);
|
153
|
+
strip_pos = smp_i + 1 - taps / 2;
|
154
|
+
|
155
|
+
for (i=0; i<taps; i++) {
|
156
|
+
if (strip_pos < 0) {
|
157
|
+
virt[i] = in[0];
|
158
|
+
} else if ((uint32_t)strip_pos > in_height - 1) {
|
159
|
+
virt[i] = in[in_height - 1];
|
160
|
+
} else {
|
161
|
+
virt[i] = in[strip_pos];
|
162
|
+
}
|
163
|
+
strip_pos++;
|
164
|
+
}
|
165
|
+
|
166
|
+
strip_scale((void **)virt, taps, width, (void *)out, ty, cmp, opts);
|
167
|
+
}
|
data/ext/oil/yscaler.h
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#ifndef YSCALER_H
|
2
2
|
#define YSCALER_H
|
3
3
|
|
4
|
-
#include "resample.h"
|
5
4
|
#include <stdint.h>
|
6
5
|
|
7
6
|
struct strip {
|
@@ -27,5 +26,8 @@ void yscaler_free(struct yscaler *ys);
|
|
27
26
|
unsigned char *yscaler_next(struct yscaler *ys);
|
28
27
|
void yscaler_scale(struct yscaler *ys, uint8_t *out, uint32_t width,
|
29
28
|
uint8_t cmp, uint8_t opts);
|
29
|
+
void yscaler_prealloc_scale(uint32_t in_height, uint32_t out_height,
|
30
|
+
uint8_t **in, uint8_t *out, uint32_t pos, uint32_t width, uint8_t cmp,
|
31
|
+
uint8_t opts);
|
30
32
|
|
31
33
|
#endif
|
data/lib/oil.rb
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
module Oil
|
2
|
-
VERSION = "0.1.
|
2
|
+
VERSION = "0.1.2"
|
3
|
+
|
4
|
+
def self.sniff_signature(io)
|
5
|
+
a = io.getc
|
6
|
+
b = io.getc
|
7
|
+
io.ungetc(b)
|
8
|
+
io.ungetc(a)
|
9
|
+
|
10
|
+
if (a == "\xFF".b && b == "\xD8".b)
|
11
|
+
return :JPEG
|
12
|
+
elsif (a == "\x89".b && b == "P".b)
|
13
|
+
return :PNG
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.new(io, box_width, box_height)
|
18
|
+
case sniff_signature(io)
|
19
|
+
when :JPEG
|
20
|
+
return new_jpeg_reader(io, box_width, box_height)
|
21
|
+
when :PNG
|
22
|
+
return new_png_reader(io, box_width, box_height)
|
23
|
+
else
|
24
|
+
raise "Unknown image file format."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
3
29
|
|
4
30
|
def self.fix_ratio(sw, sh, boxw, boxh)
|
5
31
|
x = boxw / sw.to_f
|
@@ -25,52 +51,52 @@ module Oil
|
|
25
51
|
return destw, desth
|
26
52
|
end
|
27
53
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
54
|
+
def self.new_jpeg_reader(io, box_width, box_height)
|
55
|
+
o = JPEGReader.new(io, [:COM, :APP1, :APP2])
|
56
|
+
|
57
|
+
# bump RGB images to RGBX
|
58
|
+
if (o.out_color_space == :RGB)
|
59
|
+
o.out_color_space = :RGBX
|
60
|
+
end
|
61
|
+
|
62
|
+
# JPEG Pre-scaling is equivalent to a box filter at an integer scale factor.
|
63
|
+
# We don't use this to scale down past 4x the target image size in order to
|
64
|
+
# get proper bicubic scaling in the final image.
|
65
|
+
inv_scale = o.image_width / box_width
|
33
66
|
inv_scale /= 4
|
34
67
|
|
35
68
|
if inv_scale >= 8
|
36
|
-
|
69
|
+
o.scale_denom = 8
|
37
70
|
elsif inv_scale >= 4
|
38
|
-
|
71
|
+
o.scale_denom = 4
|
39
72
|
elsif inv_scale >= 2
|
40
|
-
|
41
|
-
else
|
42
|
-
return 0
|
73
|
+
o.scale_denom = 2
|
43
74
|
end
|
44
|
-
end
|
45
75
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
io.ungetc(b)
|
50
|
-
io.ungetc(a)
|
76
|
+
destw, desth = self.fix_ratio(o.output_width, o.output_height, box_width, box_height)
|
77
|
+
o.scale_width = destw
|
78
|
+
o.scale_height = desth
|
51
79
|
|
52
|
-
|
53
|
-
|
54
|
-
if (o.color_space == :RGB)
|
55
|
-
o.out_color_space = :RGBX
|
56
|
-
end
|
57
|
-
elsif (a == "\x89".b && b == "P".b)
|
58
|
-
o = PNGReader.new(io)
|
59
|
-
else
|
60
|
-
raise "Unknown image file format."
|
61
|
-
end
|
80
|
+
return JPEGReaderWrapper.new(o, { markers: o.markers, quality: 95 })
|
81
|
+
end
|
62
82
|
|
83
|
+
def self.new_png_reader(io, box_width, box_height)
|
84
|
+
o = PNGReader.new(io)
|
63
85
|
destw, desth = self.fix_ratio(o.width, o.height, box_width, box_height)
|
64
|
-
pre = self.pre_scale(o.width, o.height, box_width, box_height)
|
65
|
-
|
66
86
|
o.scale_width = destw
|
67
87
|
o.scale_height = desth
|
88
|
+
return o
|
89
|
+
end
|
90
|
+
end
|
68
91
|
|
69
|
-
|
70
|
-
|
71
|
-
|
92
|
+
class JPEGReaderWrapper
|
93
|
+
def initialize(reader, opts)
|
94
|
+
@reader = reader
|
95
|
+
@opts = opts
|
96
|
+
end
|
72
97
|
|
73
|
-
|
98
|
+
def each(&block)
|
99
|
+
@reader.each(@opts, &block)
|
74
100
|
end
|
75
101
|
end
|
76
102
|
|
data/test/helper.rb
CHANGED
@@ -72,19 +72,3 @@ class NotStringIO < CustomIO
|
|
72
72
|
return 78887
|
73
73
|
end
|
74
74
|
end
|
75
|
-
|
76
|
-
def resize_string(str, width=nil, height=nil)
|
77
|
-
io = StringIO.new(str)
|
78
|
-
width ||= 100
|
79
|
-
height ||= 200
|
80
|
-
out = binary_stringio
|
81
|
-
o = Oil.new(io, width, height).each{ |d| out << d }
|
82
|
-
out.string
|
83
|
-
end
|
84
|
-
|
85
|
-
def binary_stringio
|
86
|
-
io = StringIO.new
|
87
|
-
io.set_encoding 'ASCII-8BIT' if RUBY_VERSION >= '1.9'
|
88
|
-
io
|
89
|
-
end
|
90
|
-
|
data/test/test_jpeg.rb
CHANGED
@@ -16,32 +16,46 @@ class TestJPEG < MiniTest::Test
|
|
16
16
|
\x01\x01\x00\x00\x3f\x00\xd2\xcf\x20\xff\xd9".b
|
17
17
|
|
18
18
|
BIG_JPEG = begin
|
19
|
-
|
19
|
+
s = ""
|
20
|
+
r = Oil::JPEGReader.new(StringIO.new(JPEG_DATA))
|
21
|
+
r.scale_width = 2000
|
22
|
+
r.scale_height = 2000
|
23
|
+
r.each{ |a| s << a }
|
24
|
+
s
|
20
25
|
end
|
21
26
|
|
22
27
|
def test_valid
|
23
28
|
o = Oil::JPEGReader.new(jpeg_io)
|
24
|
-
assert_equal 1, o.
|
25
|
-
assert_equal 1, o.
|
29
|
+
assert_equal 1, o.image_width
|
30
|
+
assert_equal 1, o.image_height
|
26
31
|
end
|
27
32
|
|
28
33
|
def test_missing_eof
|
29
34
|
io = StringIO.new(JPEG_DATA[0..-2])
|
30
35
|
o = Oil::JPEGReader.new(io)
|
31
|
-
assert_equal 1, o.
|
32
|
-
assert_equal 1, o.
|
36
|
+
assert_equal 1, o.image_width
|
37
|
+
assert_equal 1, o.image_height
|
33
38
|
end
|
34
39
|
|
35
40
|
def test_bogus_header_marker
|
36
41
|
str = JPEG_DATA.dup
|
37
42
|
str[3] = "\x10"
|
38
|
-
assert_raises(RuntimeError) {
|
43
|
+
assert_raises(RuntimeError) { drain_string(str) }
|
39
44
|
end
|
40
45
|
|
41
46
|
def test_bogus_body_marker
|
42
47
|
str = JPEG_DATA.dup
|
43
48
|
str[-22] = "\x10"
|
44
|
-
assert_raises(RuntimeError) {
|
49
|
+
assert_raises(RuntimeError) { drain_string(str) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_color_space
|
53
|
+
o = Oil::JPEGReader.new(jpeg_io)
|
54
|
+
assert_equal :GRAYSCALE, o.jpeg_color_space
|
55
|
+
assert_equal :GRAYSCALE, o.out_color_space
|
56
|
+
assert_equal 1, o.num_components
|
57
|
+
assert_equal 1, o.output_components
|
58
|
+
assert_equal 1, o.out_color_components
|
45
59
|
end
|
46
60
|
|
47
61
|
# Allocation tests
|
@@ -67,7 +81,10 @@ class TestJPEG < MiniTest::Test
|
|
67
81
|
end
|
68
82
|
|
69
83
|
def resize(io)
|
70
|
-
o = Oil.new(io
|
84
|
+
o = Oil::JPEGReader.new(io)
|
85
|
+
o.scale_width = 10
|
86
|
+
o.scale_height = 20
|
87
|
+
o.each{ |d| }
|
71
88
|
end
|
72
89
|
|
73
90
|
def test_io_too_much_data
|
@@ -112,18 +129,18 @@ class TestJPEG < MiniTest::Test
|
|
112
129
|
|
113
130
|
def test_raise_in_each
|
114
131
|
assert_raises(CustomError) do
|
115
|
-
Oil.new(jpeg_io
|
132
|
+
Oil::JPEGReader.new(jpeg_io).each{ raise CustomError }
|
116
133
|
end
|
117
134
|
end
|
118
135
|
|
119
136
|
def test_throw_in_each
|
120
137
|
catch(:foo) do
|
121
|
-
Oil.new(jpeg_io
|
138
|
+
Oil::JPEGReader.new(jpeg_io).each{ throw :foo }
|
122
139
|
end
|
123
140
|
end
|
124
141
|
|
125
142
|
def test_each_in_each
|
126
|
-
o = Oil.new(jpeg_io
|
143
|
+
o = Oil::JPEGReader.new(jpeg_io)
|
127
144
|
o.each do |d|
|
128
145
|
assert_raises(RuntimeError) do
|
129
146
|
o.each { |e| }
|
@@ -132,15 +149,78 @@ class TestJPEG < MiniTest::Test
|
|
132
149
|
end
|
133
150
|
|
134
151
|
def test_each_shrinks_buffer
|
135
|
-
|
136
|
-
io_out = binary_stringio
|
137
|
-
Oil.new(io, 200, 200).each{ |d| io_out << d; d.slice!(0, 4) }
|
152
|
+
Oil::JPEGReader.new(jpeg_io).each{ |d| d.slice!(0, 4) }
|
138
153
|
end
|
139
154
|
|
140
155
|
def test_each_enlarges_buffer
|
141
|
-
|
142
|
-
|
143
|
-
|
156
|
+
Oil::JPEGReader.new(jpeg_io).each{ |d| d << "foobar" }
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_marker_roundtrip
|
160
|
+
str = ""
|
161
|
+
opts = { markers: { COM: ["hello world", "foobar123"]}}
|
162
|
+
Oil::JPEGReader.new(jpeg_io).each(opts){ |s| str << s }
|
163
|
+
|
164
|
+
r = Oil::JPEGReader.new(StringIO.new(str), [:COM])
|
165
|
+
|
166
|
+
assert_equal(r.markers, opts[:markers])
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_marker_code_unrecognized
|
170
|
+
assert_raises(RuntimeError) do
|
171
|
+
Oil::JPEGReader.new(jpeg_io, [:FOOBAR])
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_marker_codes_not_array
|
176
|
+
assert_raises(TypeError) do
|
177
|
+
Oil::JPEGReader.new(jpeg_io, 1234)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_marker_code_not_symbol
|
182
|
+
assert_raises(TypeError) do
|
183
|
+
Oil::JPEGReader.new(jpeg_io, [1234])
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_marker_too_big
|
188
|
+
opts = { markers: { COM: ["hello world"*10000]}}
|
189
|
+
|
190
|
+
assert_raises(RuntimeError) do
|
191
|
+
Oil::JPEGReader.new(jpeg_io).each(opts){ |s| str << s }
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_markers_not_hash
|
196
|
+
opts = { markers: 1234 }
|
197
|
+
|
198
|
+
assert_raises(TypeError) do
|
199
|
+
Oil::JPEGReader.new(jpeg_io).each(opts){}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_marker_value_not_array
|
204
|
+
opts = { markers: { COM: 1234}}
|
205
|
+
|
206
|
+
assert_raises(TypeError) do
|
207
|
+
Oil::JPEGReader.new(jpeg_io).each(opts){}
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_marker_value_entry_not_string
|
212
|
+
opts = { markers: { COM: [1234]}}
|
213
|
+
|
214
|
+
assert_raises(TypeError) do
|
215
|
+
Oil::JPEGReader.new(jpeg_io).each(opts){}
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_quality_not_a_number
|
220
|
+
opts = { quality: "foobar" }
|
221
|
+
assert_raises(TypeError) do
|
222
|
+
Oil::JPEGReader.new(jpeg_io).each(opts){}
|
223
|
+
end
|
144
224
|
end
|
145
225
|
|
146
226
|
private
|
@@ -148,4 +228,8 @@ class TestJPEG < MiniTest::Test
|
|
148
228
|
def jpeg_io
|
149
229
|
StringIO.new(JPEG_DATA)
|
150
230
|
end
|
231
|
+
|
232
|
+
def drain_string(str)
|
233
|
+
Oil::JPEGReader.new(StringIO.new(str)).each{ |s| }
|
234
|
+
end
|
151
235
|
end
|
data/test/test_png.rb
CHANGED
@@ -13,11 +13,16 @@ class TestPNG < MiniTest::Test
|
|
13
13
|
\x57\xBF\xAB\xD4\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82".b
|
14
14
|
|
15
15
|
BIG_PNG = begin
|
16
|
-
|
16
|
+
s = ""
|
17
|
+
r = Oil::PNGReader.new(StringIO.new(PNG_DATA))
|
18
|
+
r.scale_width = 500
|
19
|
+
r.scale_height = 1000
|
20
|
+
r.each{ |a| s << a }
|
21
|
+
s
|
17
22
|
end
|
18
23
|
|
19
24
|
def test_valid
|
20
|
-
o = Oil.new(png_io
|
25
|
+
o = Oil::PNGReader.new(png_io)
|
21
26
|
assert_equal 1, o.width
|
22
27
|
assert_equal 1, o.height
|
23
28
|
end
|
@@ -25,20 +30,20 @@ class TestPNG < MiniTest::Test
|
|
25
30
|
def test_bogus_header_chunk
|
26
31
|
str = PNG_DATA.dup
|
27
32
|
str[15] = "\x10"
|
28
|
-
assert_raises(RuntimeError) {
|
33
|
+
assert_raises(RuntimeError) { drain_string(str) }
|
29
34
|
end
|
30
35
|
|
31
36
|
def test_bogus_body_chunk
|
32
37
|
str = PNG_DATA.dup
|
33
38
|
str[37] = "\x10"
|
34
|
-
assert_raises(RuntimeError) {
|
39
|
+
assert_raises(RuntimeError) { drain_string(str) }
|
35
40
|
end
|
36
41
|
|
37
42
|
def test_bogus_end_chunk
|
38
43
|
str = PNG_DATA.dup
|
39
44
|
str[-6] = "\x10"
|
40
45
|
io = StringIO.new(str)
|
41
|
-
o = Oil.new(png_io
|
46
|
+
o = Oil::PNGReader.new(png_io)
|
42
47
|
assert_equal 1, o.width
|
43
48
|
assert_equal 1, o.height
|
44
49
|
end
|
@@ -66,7 +71,7 @@ class TestPNG < MiniTest::Test
|
|
66
71
|
end
|
67
72
|
|
68
73
|
def resize(io)
|
69
|
-
Oil.new(io
|
74
|
+
Oil::PNGReader.new(io).each{ |d| }
|
70
75
|
end
|
71
76
|
|
72
77
|
def test_io_too_much_data
|
@@ -109,33 +114,29 @@ class TestPNG < MiniTest::Test
|
|
109
114
|
|
110
115
|
def test_raise_in_each
|
111
116
|
assert_raises(CustomError) do
|
112
|
-
Oil.new(png_io
|
117
|
+
Oil::PNGReader.new(png_io).each { raise CustomError }
|
113
118
|
end
|
114
119
|
end
|
115
120
|
|
116
121
|
def test_throw_in_each
|
117
122
|
catch(:foo) do
|
118
|
-
Oil.new(png_io
|
123
|
+
Oil::PNGReader.new(png_io).each { throw :foo }
|
119
124
|
end
|
120
125
|
end
|
121
126
|
|
122
127
|
def test_each_in_each
|
123
|
-
o = Oil.new(png_io
|
128
|
+
o = Oil::PNGReader.new(png_io)
|
124
129
|
o.each do |d|
|
125
130
|
assert_raises(RuntimeError){ o.each { |e| } }
|
126
131
|
end
|
127
132
|
end
|
128
133
|
|
129
134
|
def test_each_shrinks_buffer
|
130
|
-
|
131
|
-
io_out = binary_stringio
|
132
|
-
Oil.new(io, 200, 200).each { |d| io_out << d; d.slice!(0, 4) }
|
135
|
+
Oil::PNGReader.new(png_io).each { |d| d.slice!(0, 4) }
|
133
136
|
end
|
134
137
|
|
135
138
|
def test_each_enlarges_buffer
|
136
|
-
|
137
|
-
io_out = binary_stringio
|
138
|
-
Oil.new(io, 200, 200).each { |d| io_out << d; d << "foobar" }
|
139
|
+
Oil::PNGReader.new(png_io).each { |d| d << "foobar" }
|
139
140
|
end
|
140
141
|
|
141
142
|
private
|
@@ -143,4 +144,8 @@ class TestPNG < MiniTest::Test
|
|
143
144
|
def png_io
|
144
145
|
StringIO.new(PNG_DATA)
|
145
146
|
end
|
147
|
+
|
148
|
+
def drain_string(str)
|
149
|
+
Oil::PNGReader.new(StringIO.new(str)).each{|s|}
|
150
|
+
end
|
146
151
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Timothy Elliott
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Resize JPEG and PNG images, aiming for fast performance and low memory
|
14
14
|
use.
|
@@ -54,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
54
|
version: '0'
|
55
55
|
requirements: []
|
56
56
|
rubyforge_project:
|
57
|
-
rubygems_version: 2.4.
|
57
|
+
rubygems_version: 2.4.4
|
58
58
|
signing_key:
|
59
59
|
specification_version: 4
|
60
60
|
summary: Resize JPEG and PNG images.
|