oil 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e7ab475c778d9843d41134e7ad33cb989be6364e
4
- data.tar.gz: 91ac3a1eef0a7869e6282116b6de9fea04bb7b89
2
+ SHA256:
3
+ metadata.gz: 8667c59ce2f99a70651d4f217513aa0de0ee294b444bba1dcfa5e6123d841c18
4
+ data.tar.gz: b32ae44e0fc03708e7ea10a4f0e9b10378377fcc1ce78c6e74a15f56a543526c
5
5
  SHA512:
6
- metadata.gz: 619ef438853c052c54f9bc3063a2837d097fac003d3f251e24599532425986042b0c970eccce61ecb268ffb891d89f5efe2d0571d3009477b14f455a94daad08
7
- data.tar.gz: 933ed077f03c19a12d72bf8eed8eb79c0cbd0ff21905b9269fa17e49c9a859c0c606b1ee35a8f725ecd144cfddecac641857621bc7bbc05a62080d2f9310ea6c
6
+ metadata.gz: 33d09f09e4f4f897e98e50496415485d5ed5861b0ee260fd6eee7cb491c93d1844ec4567957d3dfeb4491be23f9fdd10e3ec9ba544e0d7b0c88d23d785146aca
7
+ data.tar.gz: ec308eb4710bc46faffbe24d802539d6fabf33d0a37e2edf2fd6c2706508fac486efb12e8bbc41960e7b4f018f1bda286054fc1526564210441875fcb83a1eaf
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014 Timothy Elliott
3
+ Copyright (c) 2018 Timothy Elliott
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -11,6 +11,9 @@ performance and low memory use.
11
11
 
12
12
  $ gem install oil
13
13
 
14
+ # when using homebrew w/ jpeg-turbo
15
+ $ gem install oil --with-ldflags=-L/usr/local/opt/jpeg-turbo/lib --with-cflags=-I/usr/local/opt/jpeg-turbo/include
16
+
14
17
  == SYNOPSIS:
15
18
 
16
19
  require 'oil'
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.3') do |s|
9
+ s = Gem::Specification.new('oil', '0.2.0') 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.'
@@ -19,8 +19,6 @@ s = Gem::Specification.new('oil', '0.1.3') do |s|
19
19
  lib/oil.rb
20
20
  ext/oil/resample.c
21
21
  ext/oil/resample.h
22
- ext/oil/yscaler.c
23
- ext/oil/yscaler.h
24
22
  ext/oil/jpeg.c
25
23
  ext/oil/png.c
26
24
  ext/oil/oil.c
@@ -1,6 +1,6 @@
1
1
  require 'mkmf'
2
2
 
3
- $CFLAGS += " -O3 -ffast-math -march=native"
3
+ $CFLAGS += " -O3 -march=native"
4
4
 
5
5
  unless have_header('jpeglib.h')
6
6
  abort "libjpeg headers were not found."
@@ -2,7 +2,6 @@
2
2
  #include <ruby/st.h>
3
3
  #include <jpeglib.h>
4
4
  #include "resample.h"
5
- #include "yscaler.h"
6
5
 
7
6
  #define READ_SIZE 1024
8
7
  #define WRITE_SIZE 1024
@@ -30,6 +29,10 @@ static ID j_color_space_to_id(J_COLOR_SPACE cs)
30
29
  return id_CMYK;
31
30
  case JCS_YCCK:
32
31
  return id_YCCK;
32
+ #ifdef JCS_EXTENSIONS
33
+ case JCS_EXT_RGBX:
34
+ return id_RGBX;
35
+ #endif
33
36
  default:
34
37
  return id_UNKNOWN;
35
38
  }
@@ -50,7 +53,11 @@ static J_COLOR_SPACE sym_to_j_color_space(VALUE sym)
50
53
  } else if (rb == id_YCCK) {
51
54
  return JCS_YCCK;
52
55
  } else if (rb == id_RGBX) {
56
+ #ifdef JCS_EXTENSIONS
53
57
  return JCS_EXT_RGBX;
58
+ #else
59
+ return JCS_RGB;
60
+ #endif
54
61
  }
55
62
  rb_raise(rb_eRuntimeError, "Color space not recognized.");
56
63
  }
@@ -103,37 +110,37 @@ static VALUE marker_code_to_sym(int marker_code)
103
110
  case JPEG_COM:
104
111
  return ID2SYM(id_COM);
105
112
  case JPEG_APP0:
106
- return ID2SYM(id_APP0);
113
+ return ID2SYM(id_APP0);
107
114
  case JPEG_APP0 + 1:
108
- return ID2SYM(id_APP1);
115
+ return ID2SYM(id_APP1);
109
116
  case JPEG_APP0 + 2:
110
- return ID2SYM(id_APP2);
117
+ return ID2SYM(id_APP2);
111
118
  case JPEG_APP0 + 3:
112
- return ID2SYM(id_APP3);
119
+ return ID2SYM(id_APP3);
113
120
  case JPEG_APP0 + 4:
114
- return ID2SYM(id_APP4);
121
+ return ID2SYM(id_APP4);
115
122
  case JPEG_APP0 + 5:
116
- return ID2SYM(id_APP5);
123
+ return ID2SYM(id_APP5);
117
124
  case JPEG_APP0 + 6:
118
- return ID2SYM(id_APP6);
125
+ return ID2SYM(id_APP6);
119
126
  case JPEG_APP0 + 7:
120
- return ID2SYM(id_APP7);
127
+ return ID2SYM(id_APP7);
121
128
  case JPEG_APP0 + 8:
122
- return ID2SYM(id_APP8);
129
+ return ID2SYM(id_APP8);
123
130
  case JPEG_APP0 + 9:
124
- return ID2SYM(id_APP9);
131
+ return ID2SYM(id_APP9);
125
132
  case JPEG_APP0 + 10:
126
- return ID2SYM(id_APP10);
133
+ return ID2SYM(id_APP10);
127
134
  case JPEG_APP0 + 11:
128
- return ID2SYM(id_APP11);
135
+ return ID2SYM(id_APP11);
129
136
  case JPEG_APP0 + 12:
130
- return ID2SYM(id_APP12);
137
+ return ID2SYM(id_APP12);
131
138
  case JPEG_APP0 + 13:
132
- return ID2SYM(id_APP13);
139
+ return ID2SYM(id_APP13);
133
140
  case JPEG_APP0 + 14:
134
- return ID2SYM(id_APP14);
141
+ return ID2SYM(id_APP14);
135
142
  case JPEG_APP0 + 15:
136
- return ID2SYM(id_APP15);
143
+ return ID2SYM(id_APP15);
137
144
  }
138
145
  rb_raise(rb_eRuntimeError, "Marker code not recognized.");
139
146
  }
@@ -274,7 +281,7 @@ static void raise_if_locked(struct readerdata *reader)
274
281
  *
275
282
  * io = File.open("image.jpg", "r")
276
283
  * reader = Oil::JPEGReader.new(io)
277
- *
284
+ *
278
285
  * io = File.open("image.jpg", "r")
279
286
  * reader = Oil::JPEGReader.new(io, [:APP1, :APP2])
280
287
  */
@@ -747,7 +754,8 @@ struct write_jpeg_args {
747
754
  struct writerdata *writer;
748
755
  unsigned char *inwidthbuf;
749
756
  unsigned char *outwidthbuf;
750
- struct yscaler *ys;
757
+ struct yscaler ys;
758
+ struct preprocess_xscaler xs;
751
759
  };
752
760
 
753
761
  static VALUE each2(struct write_jpeg_args *args)
@@ -755,24 +763,18 @@ static VALUE each2(struct write_jpeg_args *args)
755
763
  struct writerdata *writer;
756
764
  struct jpeg_decompress_struct *dinfo;
757
765
  struct jpeg_compress_struct *cinfo;
758
- unsigned char *inwidthbuf, *outwidthbuf, *yinbuf;
759
- struct yscaler *ys;
766
+ unsigned char *outwidthbuf, *xinbuf;
767
+ uint16_t *yinbuf;
760
768
  uint32_t i, scalex, scaley;
761
769
  VALUE quality, markers;
762
- int cmp, opts;
763
770
 
764
771
  writer = args->writer;
765
- inwidthbuf = args->inwidthbuf;
766
772
  outwidthbuf = args->outwidthbuf;
767
- ys = args->ys;
768
773
  dinfo = &args->reader->dinfo;
769
774
  cinfo = &writer->cinfo;
770
775
  scalex = args->reader->scale_width;
771
776
  scaley = args->reader->scale_height;
772
777
 
773
- cmp = dinfo->output_components;
774
- opts = dinfo->out_color_space == JCS_EXT_RGBX ? OIL_FILLER : 0;
775
-
776
778
  writer->mgr.init_destination = init_destination;
777
779
  writer->mgr.empty_output_buffer = empty_output_buffer;
778
780
  writer->mgr.term_destination = term_destination;
@@ -780,7 +782,9 @@ static VALUE each2(struct write_jpeg_args *args)
780
782
  writer->cinfo.image_width = scalex;
781
783
  writer->cinfo.image_height = scaley;
782
784
  writer->cinfo.in_color_space = dinfo->out_color_space;
783
- writer->cinfo.input_components = cmp;
785
+ writer->cinfo.input_components = dinfo->output_components;
786
+
787
+ xinbuf = args->inwidthbuf;
784
788
 
785
789
  jpeg_set_defaults(cinfo);
786
790
 
@@ -803,11 +807,11 @@ static VALUE each2(struct write_jpeg_args *args)
803
807
  }
804
808
 
805
809
  for(i=0; i<scaley; i++) {
806
- while ((yinbuf = yscaler_next(ys))) {
807
- jpeg_read_scanlines(dinfo, (JSAMPARRAY)&inwidthbuf, 1);
808
- xscale(inwidthbuf, dinfo->output_width, yinbuf, scalex, cmp, opts);
810
+ while ((yinbuf = yscaler_next(&args->ys))) {
811
+ jpeg_read_scanlines(dinfo, (JSAMPARRAY)&xinbuf, 1);
812
+ preprocess_xscaler_scale(&args->xs, xinbuf, yinbuf);
809
813
  }
810
- yscaler_scale(ys, outwidthbuf, scalex, cmp, opts);
814
+ yscaler_scale(&args->ys, outwidthbuf, i);
811
815
  jpeg_write_scanlines(cinfo, (JSAMPARRAY)&outwidthbuf, 1);
812
816
  }
813
817
 
@@ -816,6 +820,24 @@ static VALUE each2(struct write_jpeg_args *args)
816
820
  return Qnil;
817
821
  }
818
822
 
823
+ static enum oil_colorspace jpeg_cs_to_oil(J_COLOR_SPACE cs)
824
+ {
825
+ switch(cs) {
826
+ case JCS_GRAYSCALE:
827
+ return OIL_CS_G;
828
+ case JCS_RGB:
829
+ return OIL_CS_RGB;
830
+ case JCS_CMYK:
831
+ return OIL_CS_CMYK;
832
+ #ifdef JCS_EXTENSIONS
833
+ case JCS_EXT_RGBX:
834
+ return OIL_CS_RGBX;
835
+ #endif
836
+ default:
837
+ rb_raise(rb_eRuntimeError, "Color space not recognized.");
838
+ }
839
+ }
840
+
819
841
  /*
820
842
  * call-seq:
821
843
  * reader.each(opts, &block) -> self
@@ -834,11 +856,12 @@ static VALUE each(int argc, VALUE *argv, VALUE self)
834
856
  {
835
857
  struct readerdata *reader;
836
858
  struct writerdata writer;
837
- int cmp, state;
859
+ int state;
838
860
  struct write_jpeg_args args;
839
861
  unsigned char *inwidthbuf, *outwidthbuf;
840
- struct yscaler ys;
862
+ uint32_t width_in, width_out;
841
863
  VALUE opts;
864
+ enum oil_colorspace cs;
842
865
 
843
866
  rb_scan_args(argc, argv, "01", &opts);
844
867
 
@@ -854,24 +877,27 @@ static VALUE each(int argc, VALUE *argv, VALUE self)
854
877
  writer.cinfo.err = &reader->jerr;
855
878
  jpeg_create_compress(&writer.cinfo);
856
879
 
857
- cmp = reader->dinfo.output_components;
858
- inwidthbuf = malloc(reader->dinfo.output_width * cmp);
859
- outwidthbuf = malloc(reader->scale_width * cmp);
860
- yscaler_init(&ys, reader->dinfo.output_height, reader->scale_height,
861
- reader->scale_width * cmp);
880
+ cs = jpeg_cs_to_oil(reader->dinfo.out_color_space);
881
+ width_in = reader->dinfo.output_width;
882
+ width_out = reader->scale_width;
883
+ inwidthbuf = malloc(width_in * CS_TO_CMP(cs));
884
+ outwidthbuf = malloc(width_out * CS_TO_CMP(cs));
885
+ preprocess_xscaler_init(&args.xs, width_in, width_out, cs);
886
+ yscaler_init(&args.ys, reader->dinfo.output_height, reader->scale_height,
887
+ width_out, cs);
862
888
 
863
889
  args.reader = reader;
864
890
  args.opts = opts;
865
891
  args.writer = &writer;
866
892
  args.inwidthbuf = inwidthbuf;
867
893
  args.outwidthbuf = outwidthbuf;
868
- args.ys = &ys;
869
894
  reader->locked = 1;
870
895
  rb_protect((VALUE(*)(VALUE))each2, (VALUE)&args, &state);
871
896
 
872
- yscaler_free(&ys);
873
- free(inwidthbuf);
897
+ yscaler_free(&args.ys);
898
+ preprocess_xscaler_free(&args.xs);
874
899
  free(outwidthbuf);
900
+ free(inwidthbuf);
875
901
  jpeg_destroy_compress(&writer.cinfo);
876
902
 
877
903
  if (state) {
@@ -1,10 +1,27 @@
1
1
  #include <ruby.h>
2
+ #include "resample.h"
3
+
4
+ static VALUE rb_fix_ratio(VALUE self, VALUE src_w, VALUE src_h, VALUE out_w, VALUE out_h)
5
+ {
6
+ uint32_t out_width, out_height;
7
+ VALUE ret;
8
+ out_width = NUM2INT(out_w);
9
+ out_height = NUM2INT(out_h);
10
+ fix_ratio(NUM2INT(src_w), NUM2INT(src_h), &out_width, &out_height);
11
+ ret = rb_ary_new2(2);
12
+ rb_ary_push(ret, INT2FIX(out_width));
13
+ rb_ary_push(ret, INT2FIX(out_height));
14
+ return ret;
15
+ }
2
16
 
3
17
  void Init_jpeg();
4
18
  void Init_png();
5
19
 
6
20
  void Init_oil()
7
21
  {
8
- Init_jpeg();
9
- Init_png();
22
+ VALUE mOil;
23
+ mOil = rb_const_get(rb_cObject, rb_intern("Oil"));
24
+ rb_define_singleton_method(mOil, "fix_ratio", rb_fix_ratio, 4);
25
+ Init_jpeg();
26
+ Init_png();
10
27
  }
@@ -1,7 +1,6 @@
1
1
  #include <ruby.h>
2
2
  #include <png.h>
3
3
  #include "resample.h"
4
- #include "yscaler.h"
5
4
 
6
5
  static ID id_read;
7
6
 
@@ -215,34 +214,37 @@ struct each_args {
215
214
  unsigned char *outwidthbuf;
216
215
  unsigned char **scanlines;
217
216
  struct yscaler ys;
217
+ struct preprocess_xscaler xs;
218
218
  };
219
219
 
220
220
  static VALUE each_interlace(struct each_args *args)
221
221
  {
222
222
  struct readerdata *reader;
223
- unsigned char *inwidthbuf, *outwidthbuf;
224
- uint32_t i, width, height, scalex, scaley;
225
- int cmp;
223
+ unsigned char **scanlines, *outwidthbuf;
224
+ uint32_t i, n, scaley;
225
+ uint16_t *yinbuf;
226
+ struct yscaler *ys;
227
+ struct preprocess_xscaler *xs;
226
228
 
227
229
  reader = args->reader;
228
- inwidthbuf = args->inwidthbuf;
230
+ xs = &args->xs;
231
+ ys = &args->ys;
232
+ scanlines = args->scanlines;
229
233
  outwidthbuf = args->outwidthbuf;
230
- scalex = reader->scale_width;
231
234
  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
235
 
236
236
  png_write_info(args->wpng, args->winfo);
237
237
  png_read_image(args->reader->png, (png_bytepp)args->scanlines);
238
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);
239
+ n = 0;
240
+ for(i=0; i<scaley; i++) {
241
+ while ((yinbuf = yscaler_next(ys))) {
242
+ preprocess_xscaler_scale(xs, scanlines[n++], yinbuf);
243
+ }
244
+ yscaler_scale(ys, outwidthbuf, i);
244
245
  png_write_row(args->wpng, outwidthbuf);
245
246
  }
247
+
246
248
  png_write_end(args->wpng, args->winfo);
247
249
  return Qnil;
248
250
  }
@@ -250,28 +252,27 @@ static VALUE each_interlace(struct each_args *args)
250
252
  static VALUE each_interlace_none(struct each_args *args)
251
253
  {
252
254
  struct readerdata *reader;
253
- unsigned char *inwidthbuf, *outwidthbuf, *yinbuf;
255
+ unsigned char *inwidthbuf, *outwidthbuf;
256
+ uint16_t *yinbuf;
257
+ struct preprocess_xscaler *xs;
254
258
  struct yscaler *ys;
255
- uint32_t i, width, scalex, scaley;
256
- int cmp;
259
+ uint32_t i, scaley;
257
260
 
258
261
  reader = args->reader;
262
+ xs = &args->xs;
259
263
  inwidthbuf = args->inwidthbuf;
260
264
  outwidthbuf = args->outwidthbuf;
261
265
  ys = &args->ys;
262
- scalex = reader->scale_width;
263
266
  scaley = reader->scale_height;
264
- cmp = png_get_channels(reader->png, reader->info);
265
- width = png_get_image_width(reader->png, reader->info);
266
267
 
267
268
  png_write_info(args->wpng, args->winfo);
268
269
 
269
270
  for(i=0; i<scaley; i++) {
270
271
  while ((yinbuf = yscaler_next(ys))) {
271
272
  png_read_row(reader->png, inwidthbuf, NULL);
272
- xscale(inwidthbuf, width, yinbuf, scalex, cmp, 0);
273
+ preprocess_xscaler_scale(xs, inwidthbuf, yinbuf);
273
274
  }
274
- yscaler_scale(ys, outwidthbuf, scalex, cmp, 0);
275
+ yscaler_scale(ys, outwidthbuf, i);
275
276
  png_write_row(args->wpng, outwidthbuf);
276
277
  }
277
278
 
@@ -279,6 +280,21 @@ static VALUE each_interlace_none(struct each_args *args)
279
280
  return Qnil;
280
281
  }
281
282
 
283
+ static enum oil_colorspace png_cs_to_oil(png_byte cs)
284
+ {
285
+ switch(cs) {
286
+ case PNG_COLOR_TYPE_GRAY:
287
+ return OIL_CS_G;
288
+ case PNG_COLOR_TYPE_GA:
289
+ return OIL_CS_GA;
290
+ case PNG_COLOR_TYPE_RGB:
291
+ return OIL_CS_RGB;
292
+ case PNG_COLOR_TYPE_RGBA:
293
+ return OIL_CS_RGBA;
294
+ }
295
+ rb_raise(rb_eRuntimeError, "Color space not recognized.");
296
+ }
297
+
282
298
  /*
283
299
  * call-seq:
284
300
  * reader.each(opts, &block) -> self
@@ -301,10 +317,11 @@ static VALUE each(int argc, VALUE *argv, VALUE self)
301
317
  VALUE opts;
302
318
  int cmp, state;
303
319
  struct each_args args;
304
- uint32_t i, height;
320
+ uint32_t i, height, width;
305
321
  png_byte ctype;
306
322
  unsigned char **scanlines;
307
323
  size_t row_bytes;
324
+ enum oil_colorspace cs;
308
325
 
309
326
  rb_scan_args(argc, argv, "01", &opts);
310
327
 
@@ -313,32 +330,35 @@ static VALUE each(int argc, VALUE *argv, VALUE self)
313
330
  raise_if_locked(reader);
314
331
  reader->locked = 1;
315
332
 
333
+ cmp = png_get_channels(reader->png, reader->info);
334
+ ctype = png_get_color_type(reader->png, reader->info);
335
+ cs = png_cs_to_oil(ctype);
336
+
316
337
  wpng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
317
338
  (png_error_ptr)error, (png_error_ptr)warning);
318
339
  winfo = png_create_info_struct(wpng);
319
340
  png_set_write_fn(wpng, 0, write_data_fn, flush_data_fn);
320
341
 
321
- cmp = png_get_channels(reader->png, reader->info);
322
- ctype = png_get_color_type(reader->png, reader->info);
323
-
324
342
  png_set_IHDR(wpng, winfo, reader->scale_width, reader->scale_height, 8,
325
343
  ctype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
326
344
  PNG_FILTER_TYPE_DEFAULT);
327
345
 
346
+ width = png_get_image_width(reader->png, reader->info);
328
347
  height = png_get_image_height(reader->png, reader->info);
329
348
  row_bytes = png_get_rowbytes(reader->png, reader->info);
330
349
 
331
350
  args.reader = reader;
332
351
  args.wpng = wpng;
333
352
  args.winfo = winfo;
334
- args.inwidthbuf = malloc(row_bytes);
335
353
  args.outwidthbuf = malloc(reader->scale_width * cmp);
336
354
 
355
+ preprocess_xscaler_init(&args.xs, width, reader->scale_width, cs);
356
+ yscaler_init(&args.ys, height, reader->scale_height, reader->scale_width, cs);
357
+
337
358
  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);
359
+ args.inwidthbuf = malloc(width * cmp);
340
360
  rb_protect((VALUE(*)(VALUE))each_interlace_none, (VALUE)&args, &state);
341
- yscaler_free(&args.ys);
361
+ free(args.inwidthbuf);
342
362
  } else {
343
363
  scanlines = malloc(height * sizeof(unsigned char *));
344
364
  for (i=0; i<height; i++) {
@@ -354,7 +374,8 @@ static VALUE each(int argc, VALUE *argv, VALUE self)
354
374
  free(scanlines);
355
375
  }
356
376
 
357
- free(args.inwidthbuf);
377
+ yscaler_free(&args.ys);
378
+ preprocess_xscaler_free(&args.xs);
358
379
  free(args.outwidthbuf);
359
380
  png_destroy_write_struct(&wpng, &winfo);
360
381