webp-ffi 0.1.1 → 0.1.2

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.
@@ -19,5 +19,4 @@ matrix:
19
19
  allow_failures:
20
20
  - rvm: ruby-head
21
21
  - rvm: jruby-head
22
- - rvm: jruby-19mode
23
- - rvm: rbx-19mode
22
+ - rvm: jruby-19mode
@@ -0,0 +1,12 @@
1
+ ## v0.1.2
2
+
3
+ * Added all possible encode options (also added this options in readme)
4
+ * Added error class for encode errors
5
+
6
+ ## v0.1.1
7
+
8
+ * Added encode options
9
+
10
+ ## v0.1.0
11
+
12
+ * First release
data/Gemfile CHANGED
@@ -1,6 +1,4 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in webp-ffi.gemspec
4
- gemspec
5
-
6
- gem 'ffi-compiler', github: 'ffi/ffi-compiler'
4
+ gemspec
data/README.md CHANGED
@@ -45,6 +45,8 @@ Or install it yourself as:
45
45
 
46
46
  ## Usage
47
47
 
48
+ ### Encode end Decoder versions
49
+
48
50
  Basic info about libwebp (encoder and decoder versions):
49
51
 
50
52
  $ irb
@@ -54,6 +56,8 @@ Basic info about libwebp (encoder and decoder versions):
54
56
  => "0.2.0"
55
57
  2.0.0p0 :003 > WebpFfi.encoder_version
56
58
  => "0.2.0"
59
+
60
+ ### WebP size (width and height)
57
61
 
58
62
  Get size (width and height) from webp image:
59
63
 
@@ -61,11 +65,7 @@ Get size (width and height) from webp image:
61
65
  WebpFfi.webp_size(File.open(filename, "rb").read)
62
66
  => [2000, 2353]
63
67
 
64
- Decode webp image to png:
65
-
66
- filename = File.expand_path(File.join(File.dirname(__FILE__), "spec/factories/4.webp"))
67
- out_filename = File.expand_path(File.join(File.dirname(__FILE__), "tmp/4.png"))
68
- WebpFfi.decode(filename, out_filename)
68
+ ### Encode png, jpg or tiff image to WebP image
69
69
 
70
70
  Encode png, jpg or tiff image to webp:
71
71
 
@@ -77,6 +77,39 @@ Encode png, jpg or tiff image to webp (with options):
77
77
 
78
78
  WebpFfi.encode(filename, out_filename, quality: 50, resize_w: 100, resize_h: 200)
79
79
  WebpFfi.encode(filename, out_filename, quality: 75, crop_x: 0, cropt_y: 0, crop_w: 100, crop_h: 100)
80
+
81
+ Possible encode options:
82
+
83
+ * **lossless** (int) - Lossless encoding (0=lossy(default), 1=lossless)
84
+ * **quality** (float) - between 0 (smallest file) and 100 (biggest)
85
+ * **method** (int) - quality/speed trade-off (0=fast, 6=slower-better)
86
+ * **target\_size** (int) - if non-zero, set the desired target size in bytes. Takes precedence over the 'compression' parameter
87
+ * **target\_PSNR** (float) - if non-zero, specifies the minimal distortion to try to achieve. Takes precedence over target\_size
88
+ * **segments** (int) - maximum number of segments to use, in [1..4]
89
+ * **sns_strength** (int) - Spatial Noise Shaping. 0=off, 100=maximum
90
+ * **filter\_strength** (int) - range: [0 = off .. 100 = strongest]
91
+ * **filter\_sharpness** (int) - range: [0 = off .. 7 = least sharp]
92
+ * **filter\_type** (int) - filtering type: 0 = simple, 1 = strong (only used if filter\_strength > 0 or autofilter > 0)
93
+ * **autofilter** (int) - Auto adjust filter's strength [0 = off, 1 = on]
94
+ * **alpha\_compression** (int) - Algorithm for encoding the alpha plane (0 = none, 1 = compressed with WebP lossless). Default is 1
95
+ * **alpha\_filtering** (int) - Predictive filtering method for alpha plane. 0: none, 1: fast, 2: best. Default if 1
96
+ * **alpha\_quality** (int) - Between 0 (smallest size) and 100 (lossless). Default is 100
97
+ * **pass** (int) - number of entropy-analysis passes (in [1..10])
98
+ * **show\_compressed** (int) - if true, export the compressed picture back. In-loop filtering is not applied
99
+ * **preprocessing** (int) - preprocessing filter (0=none, 1=segment-smooth)
100
+ * **partitions** (int) - log2(number of token partitions) in [0..3]. Default is set to 0 for easier progressive decoding
101
+ * **partition\_limit** (int) - quality degradation allowed to fit the 512k limit on prediction modes coding (0: no degradation, 100: maximum possible degradation)
102
+ * **width** (int), **height** (int) - Input size (width x height) for YUV
103
+ * **crop\_x** (int), **crop\_y** (int), **crop\_w** (int), **crop\_h** (int) - crop picture with the given rectangle
104
+ * **resize\_w** (int), **resize\_h** (int) - resize picture (after any cropping)
105
+
106
+ ### Decode WebP image to png image
107
+
108
+ Decode webp image to png:
109
+
110
+ filename = File.expand_path(File.join(File.dirname(__FILE__), "spec/factories/4.webp"))
111
+ out_filename = File.expand_path(File.join(File.dirname(__FILE__), "tmp/4.png"))
112
+ WebpFfi.decode(filename, out_filename)
80
113
 
81
114
  ## Contributing
82
115
 
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ require 'rubygems'
1
2
  require 'bundler/setup'
2
3
  require 'rake'
3
4
  require 'rake/clean'
@@ -267,7 +267,7 @@ static int UtilReadTIFF(const char* const filename,
267
267
  int dircount = 1;
268
268
 
269
269
  if (tif == NULL) {
270
- fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename);
270
+ //fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename);
271
271
  return 0;
272
272
  }
273
273
 
@@ -298,7 +298,7 @@ static int UtilReadTIFF(const char* const filename,
298
298
  }
299
299
  _TIFFfree(raster);
300
300
  } else {
301
- fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
301
+ //fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
302
302
  }
303
303
 
304
304
  if (ok && keep_alpha == 2) {
@@ -335,7 +335,7 @@ int UtilReadPicture(const char* const filename, WebPPicture* const pic,
335
335
  int ok = 0;
336
336
  FILE* in_file = fopen(filename, "rb");
337
337
  if (in_file == NULL) {
338
- fprintf(stderr, "Error! Cannot open input file '%s'\n", filename);
338
+ //fprintf(stderr, "Error! Cannot open input file '%s'\n", filename);
339
339
  return ok;
340
340
  }
341
341
 
@@ -353,9 +353,6 @@ int UtilReadPicture(const char* const filename, WebPPicture* const pic,
353
353
  // If image size is specified, infer it as YUV format.
354
354
  ok = UtilReadYUV(in_file, pic);
355
355
  }
356
- if (!ok) {
357
- fprintf(stderr, "Error! Could not process file %s\n", filename);
358
- }
359
356
 
360
357
  fclose(in_file);
361
358
  return ok;
@@ -369,7 +366,7 @@ int UtilSaveOutput(const WebPDecBuffer* const buffer,
369
366
  fout = fopen(out_file, "wb");
370
367
  if (!fout) {
371
368
  fprintf(stderr, "Error opening output file %s\n", out_file);
372
- return;
369
+ return 0;
373
370
  }
374
371
 
375
372
  if (format == PNG) {
@@ -51,69 +51,6 @@ int webp_get_info(const uint8_t* data, size_t data_size, int* width, int* height
51
51
 
52
52
 
53
53
 
54
- int webp_decode(const char *in_file, const char *out_file) {
55
- int return_value = -1;
56
- WebPDecoderConfig config;
57
- WebPDecBuffer* const output_buffer = &config.output;
58
- WebPBitstreamFeatures* const bitstream = &config.input;
59
- OutputFileFormat format = PNG;
60
-
61
- if (!WebPInitDecoderConfig(&config)) {
62
- fprintf(stderr, "Library version mismatch!\n");
63
- return 1;
64
- }
65
-
66
- VP8StatusCode status = VP8_STATUS_OK;
67
- size_t data_size = 0;
68
- const uint8_t* data = NULL;
69
-
70
- if (!UtilReadFile(in_file, &data, &data_size)) return -1;
71
-
72
- status = WebPGetFeatures(data, data_size, bitstream);
73
- if (status != VP8_STATUS_OK) {
74
- fprintf(stderr, "This is invalid webp image!\n");
75
- return_value = 2;
76
- goto Error;
77
- }
78
-
79
- switch (format) {
80
- case PNG:
81
- output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB;
82
- break;
83
- case PAM:
84
- output_buffer->colorspace = MODE_RGBA;
85
- break;
86
- case PPM:
87
- output_buffer->colorspace = MODE_RGB; // drops alpha for PPM
88
- break;
89
- case PGM:
90
- output_buffer->colorspace = bitstream->has_alpha ? MODE_YUVA : MODE_YUV;
91
- break;
92
- case ALPHA_PLANE_ONLY:
93
- output_buffer->colorspace = MODE_YUVA;
94
- break;
95
- default:
96
- free((void*)data);
97
- return 3;
98
- }
99
- status = WebPDecode(data, data_size, &config);
100
-
101
- if (status != VP8_STATUS_OK) {
102
- fprintf(stderr, "Decoding of %s failed.\n", in_file);
103
- return_value = 4;
104
- goto Error;
105
- }
106
- UtilSaveOutput(output_buffer, format, out_file);
107
- return_value = 0;
108
-
109
- Error:
110
- free((void*)data);
111
- WebPFreeDecBuffer(output_buffer);
112
- return return_value;
113
- }
114
-
115
-
116
-
117
54
  int webp_encode(const char *in_file, const char *out_file, const FfiWebpEncodeConfig *encode_config) {
118
55
  int return_value = -1;
119
56
  FILE *out = NULL;
@@ -121,56 +58,90 @@ int webp_encode(const char *in_file, const char *out_file, const FfiWebpEncodeCo
121
58
  WebPPicture picture;
122
59
  WebPConfig config;
123
60
  // config
124
- if (encode_config->lossless && (encode_config->lossless == 0 || encode_config->lossless == 1)){
61
+ if (encode_config->lossless == 0 || encode_config->lossless == 1){
125
62
  config.lossless = encode_config->lossless;
126
63
  }
127
- if (encode_config->quality){
64
+ if (encode_config->quality >= 0 && encode_config->quality <= 100){
128
65
  config.quality = encode_config->quality;
129
66
  }
130
67
  if (encode_config->method >= 0 && encode_config->method <= 6){
131
68
  config.method = encode_config->method;
132
69
  }
133
- if (encode_config->segments){
70
+ if (encode_config->target_size > 0){
71
+ config.target_size = encode_config->target_size;
72
+ }
73
+ if (encode_config->target_PSNR > 0){
74
+ config.target_PSNR = encode_config->target_PSNR;
75
+ }
76
+ if (encode_config->segments >= 0 && encode_config->segments <= 4){
134
77
  config.segments = encode_config->segments;
135
78
  }
136
- if (encode_config->sns_strength){
79
+ if (encode_config->sns_strength >= 0 && encode_config->sns_strength <= 100){
137
80
  config.sns_strength = encode_config->sns_strength;
138
81
  }
139
- if (encode_config->alpha_quality){
140
- config.alpha_quality = encode_config->alpha_quality;
82
+ if (encode_config->filter_strength >= 0 && encode_config->filter_strength <= 100){
83
+ config.filter_strength = encode_config->filter_strength;
84
+ }
85
+ if (encode_config->filter_sharpness >= 0 && encode_config->filter_sharpness <= 7){
86
+ config.filter_sharpness = encode_config->filter_sharpness;
141
87
  }
142
- if (encode_config->alpha_compression){
88
+ if (encode_config->filter_type == 0 || encode_config->filter_type == 1){
89
+ config.filter_type = encode_config->filter_type;
90
+ }
91
+ if (encode_config->autofilter == 0 || encode_config->autofilter == 1){
92
+ config.autofilter = encode_config->autofilter;
93
+ }
94
+ if (encode_config->alpha_compression == 0 || encode_config->alpha_compression == 1){
143
95
  config.alpha_compression = encode_config->alpha_compression;
144
96
  }
145
- if (encode_config->alpha_filtering){
97
+ if (encode_config->alpha_filtering >= 0 && encode_config->alpha_filtering <= 2){
146
98
  config.alpha_filtering = encode_config->alpha_filtering;
147
99
  }
148
- if (encode_config->width && encode_config->height){
100
+ if (encode_config->alpha_quality >= 0 && encode_config->alpha_quality <= 100){
101
+ config.alpha_quality = encode_config->alpha_quality;
102
+ }
103
+ if (encode_config->pass >= 0 && encode_config->pass <= 10){
104
+ config.pass = encode_config->pass;
105
+ }
106
+ if (encode_config->show_compressed >= 0){
107
+ config.show_compressed = encode_config->show_compressed;
108
+ }
109
+ if (encode_config->preprocessing == 0 || encode_config->preprocessing == 1){
110
+ config.preprocessing = encode_config->preprocessing;
111
+ }
112
+ if (encode_config->partitions >= 0 && encode_config->partitions <= 3){
113
+ config.partitions = encode_config->partitions;
114
+ }
115
+ if (encode_config->partition_limit >= 0 && encode_config->partition_limit <= 100){
116
+ config.partition_limit = encode_config->partition_limit;
117
+ }
118
+
119
+ if ((encode_config->width | encode_config->height) > 0){
149
120
  picture.width = encode_config->width;
150
121
  picture.height = encode_config->height;
151
122
  }
152
123
 
153
124
  if (!WebPPictureInit(&picture) ||
154
125
  !WebPConfigInit(&config)) {
155
- fprintf(stderr, "Error! Version mismatch!\n");
126
+ //fprintf(stderr, "Error! Version mismatch!\n");
156
127
  return 1;
157
128
  }
158
129
 
159
130
  if (!WebPValidateConfig(&config)) {
160
- fprintf(stderr, "Error! Invalid configuration.\n");
131
+ //fprintf(stderr, "Error! Invalid configuration.\n");
161
132
  return_value = 2;
162
133
  goto Error;
163
134
  }
164
135
 
165
136
  if (!UtilReadPicture(in_file, &picture, keep_alpha)) {
166
- fprintf(stderr, "Error! Cannot read input picture file '%s'\n", in_file);
137
+ //fprintf(stderr, "Error! Cannot read input picture file '%s'\n", in_file);
167
138
  return_value = 3;
168
139
  goto Error;
169
140
  }
170
141
 
171
142
  out = fopen(out_file, "wb");
172
143
  if (out == NULL) {
173
- fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
144
+ //fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
174
145
  return_value = 4;
175
146
  goto Error;
176
147
  }
@@ -179,7 +150,7 @@ int webp_encode(const char *in_file, const char *out_file, const FfiWebpEncodeCo
179
150
 
180
151
  if ((encode_config->crop_w | encode_config->crop_h) > 0){
181
152
  if (!WebPPictureView(&picture, encode_config->crop_x, encode_config->crop_y, encode_config->crop_w, encode_config->crop_h, &picture)) {
182
- fprintf(stderr, "Error! Cannot crop picture\n");
153
+ //fprintf(stderr, "Error! Cannot crop picture\n");
183
154
  return_value = 5;
184
155
  goto Error;
185
156
  }
@@ -187,7 +158,7 @@ int webp_encode(const char *in_file, const char *out_file, const FfiWebpEncodeCo
187
158
 
188
159
  if ((encode_config->resize_w | encode_config->resize_h) > 0) {
189
160
  if (!WebPPictureRescale(&picture, encode_config->resize_w, encode_config->resize_h)) {
190
- fprintf(stderr, "Error! Cannot resize picture\n");
161
+ //fprintf(stderr, "Error! Cannot resize picture\n");
191
162
  return_value = 6;
192
163
  goto Error;
193
164
  }
@@ -198,8 +169,8 @@ int webp_encode(const char *in_file, const char *out_file, const FfiWebpEncodeCo
198
169
  }
199
170
 
200
171
  if (!WebPEncode(&config, &picture)) {
201
- fprintf(stderr, "Error! Cannot encode picture as WebP\n");
202
- return_value = 10;
172
+ //fprintf(stderr, "Error! Cannot encode picture as WebP\n");
173
+ return_value = 7;
203
174
  goto Error;
204
175
  }
205
176
  return_value = 0;
@@ -214,6 +185,70 @@ Error:
214
185
  return return_value;
215
186
  }
216
187
 
188
+
189
+
190
+ int webp_decode(const char *in_file, const char *out_file) {
191
+ int return_value = -1;
192
+ WebPDecoderConfig config;
193
+ WebPDecBuffer* const output_buffer = &config.output;
194
+ WebPBitstreamFeatures* const bitstream = &config.input;
195
+ OutputFileFormat format = PNG;
196
+
197
+ if (!WebPInitDecoderConfig(&config)) {
198
+ fprintf(stderr, "Library version mismatch!\n");
199
+ return 1;
200
+ }
201
+
202
+ VP8StatusCode status = VP8_STATUS_OK;
203
+ size_t data_size = 0;
204
+ const uint8_t* data = NULL;
205
+
206
+ if (!UtilReadFile(in_file, &data, &data_size)) return -1;
207
+
208
+ status = WebPGetFeatures(data, data_size, bitstream);
209
+ if (status != VP8_STATUS_OK) {
210
+ fprintf(stderr, "This is invalid webp image!\n");
211
+ return_value = 2;
212
+ goto Error;
213
+ }
214
+
215
+ switch (format) {
216
+ case PNG:
217
+ output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB;
218
+ break;
219
+ case PAM:
220
+ output_buffer->colorspace = MODE_RGBA;
221
+ break;
222
+ case PPM:
223
+ output_buffer->colorspace = MODE_RGB; // drops alpha for PPM
224
+ break;
225
+ case PGM:
226
+ output_buffer->colorspace = bitstream->has_alpha ? MODE_YUVA : MODE_YUV;
227
+ break;
228
+ case ALPHA_PLANE_ONLY:
229
+ output_buffer->colorspace = MODE_YUVA;
230
+ break;
231
+ default:
232
+ free((void*)data);
233
+ return 3;
234
+ }
235
+ status = WebPDecode(data, data_size, &config);
236
+
237
+ if (status != VP8_STATUS_OK) {
238
+ fprintf(stderr, "Decoding of %s failed.\n", in_file);
239
+ return_value = 4;
240
+ goto Error;
241
+ }
242
+ UtilSaveOutput(output_buffer, format, out_file);
243
+ return_value = 0;
244
+
245
+ Error:
246
+ free((void*)data);
247
+ WebPFreeDecBuffer(output_buffer);
248
+ return return_value;
249
+ }
250
+
251
+
217
252
  // test
218
253
  int test_c(int n) {
219
254
  return n + 100;
@@ -9,11 +9,35 @@ extern "C" {
9
9
  int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
10
10
  float quality; // between 0 (smallest file) and 100 (biggest)
11
11
  int method; // quality/speed trade-off (0=fast, 6=slower-better)
12
+
13
+ // Parameters related to lossy compression only:
14
+ int target_size; // if non-zero, set the desired target size in bytes.
15
+ // Takes precedence over the 'compression' parameter.
16
+ float target_PSNR; // if non-zero, specifies the minimal distortion to
17
+ // try to achieve. Takes precedence over target_size.
12
18
  int segments; // maximum number of segments to use, in [1..4]
13
19
  int sns_strength; // Spatial Noise Shaping. 0=off, 100=maximum.
14
- int alpha_quality; // Between 0 (smallest size) and 100 (lossless). Default is 100.
15
- int alpha_compression; // Algorithm for encoding the alpha plane
20
+ int filter_strength; // range: [0 = off .. 100 = strongest]
21
+ int filter_sharpness; // range: [0 = off .. 7 = least sharp]
22
+ int filter_type; // filtering type: 0 = simple, 1 = strong (only used
23
+ // if filter_strength > 0 or autofilter > 0)
24
+ int autofilter; // Auto adjust filter's strength [0 = off, 1 = on]
25
+ int alpha_compression; // Algorithm for encoding the alpha plane (0 = none,
26
+ // 1 = compressed with WebP lossless). Default is 1.
16
27
  int alpha_filtering; // Predictive filtering method for alpha plane.
28
+ // 0: none, 1: fast, 2: best. Default if 1.
29
+ int alpha_quality; // Between 0 (smallest size) and 100 (lossless).
30
+ // Default is 100.
31
+ int pass; // number of entropy-analysis passes (in [1..10]).
32
+
33
+ int show_compressed; // if true, export the compressed picture back.
34
+ // In-loop filtering is not applied.
35
+ int preprocessing; // preprocessing filter (0=none, 1=segment-smooth)
36
+ int partitions; // log2(number of token partitions) in [0..3]
37
+ // Default is set to 0 for easier progressive decoding.
38
+ int partition_limit; // quality degradation allowed to fit the 512k limit on
39
+ // prediction modes coding (0: no degradation,
40
+ // 100: maximum possible degradation).
17
41
  int width;
18
42
  int height;
19
43
  int crop_x;
@@ -23,12 +47,13 @@ extern "C" {
23
47
  int resize_w;
24
48
  int resize_h;
25
49
  } FfiWebpEncodeConfig;
50
+
26
51
 
27
52
  void decoder_version(char *version);
28
53
  void encoder_version(char *version);
29
54
  int webp_get_info(const uint8_t* data, size_t data_size, int* width, int* height);
30
- int webp_decode(const char *in_file, const char *out_file);
31
55
  int webp_encode(const char *in_file, const char *out_file, const FfiWebpEncodeConfig *encode_config);
56
+ int webp_decode(const char *in_file, const char *out_file);
32
57
  int test_c(int n);
33
58
 
34
59
  #if defined(__cplusplus) || defined(c_plusplus)
@@ -5,11 +5,23 @@ module WebpFfi
5
5
  layout :lossless, :int,
6
6
  :quality, :float,
7
7
  :method, :int,
8
+ :target_size, :int,
9
+ :target_PSNR, :float,
8
10
  :segments, :int,
9
11
  :sns_strength, :int,
10
- :alpha_quality, :int,
12
+ :filter_strength, :int,
13
+ :filter_sharpness, :int,
14
+ :filter_type, :int,
15
+ :autofilter, :int,
11
16
  :alpha_compression, :int,
12
17
  :alpha_filtering, :int,
18
+ :alpha_quality, :int,
19
+ :pass, :int,
20
+ :show_compressed, :int,
21
+ :preprocessing, :int,
22
+ :partitions, :int,
23
+ :partition_limit, :int,
24
+ # image
13
25
  :width, :int,
14
26
  :height, :int,
15
27
  :crop_x, :int,
@@ -24,8 +36,8 @@ module WebpFfi
24
36
  attach_function :decoder_version, [:pointer], :void
25
37
  attach_function :encoder_version, [:pointer], :void
26
38
  attach_function :webp_get_info, [:pointer, :size_t, :pointer, :pointer], :int
27
- attach_function :webp_decode, [:string, :string], :int
28
39
  attach_function :webp_encode, [:string, :string, :pointer], :int
40
+ attach_function :webp_decode, [:string, :string], :int
29
41
 
30
42
  attach_function :test_c, [:int], :int
31
43
  end
@@ -1,3 +1,15 @@
1
1
  module WebpFfi
2
+
3
+ ENCODER_ERRORS = [
4
+ "Version mismatch",
5
+ "Invalid configuration",
6
+ "Cannot read input picture file",
7
+ "Cannot open output file",
8
+ "Cannot crop picture",
9
+ "Cannot resize picture",
10
+ "Cannot encode picture as WebP"]
11
+
2
12
  class InvalidImageFormatError < StandardError; end
13
+ class EncoderError < StandardError; end
14
+ class DecoderError < StandardError; end
3
15
  end
@@ -14,10 +14,13 @@ module WebpFfi
14
14
  options_struct[:crop_w] = options_struct[:crop_h] = 0
15
15
  options_struct[:resize_w] = options_struct[:resize_h] = 0
16
16
  # users
17
- [:lossless, :quality, :method, :segments, :sns_strength,
18
- :alpha_quality, :alpha_compression, :alpha_filtering, :width, :height,
19
- :crop_x, :crop_y, :crop_w, :crop_h, :resize_w, :resize_h].each do |key|
20
- options_struct[key] = @user_options[key] if @user_options[key]
17
+ [:lossless, :quality, :method, :target_size, :target_PSNR,
18
+ :segments, :sns_strength, :filter_strength, :filter_sharpness,
19
+ :filter_type, :autofilter, :alpha_compression, :alpha_filtering,
20
+ :alpha_quality, :pass, :show_compressed, :preprocessing, :partitions,
21
+ :partition_limit, :width, :height, :crop_x, :crop_y, :crop_w,
22
+ :crop_h, :resize_w, :resize_h].each do |key|
23
+ options_struct[key] = @user_options[key] if @user_options[key]
21
24
  end
22
25
  options_pointer
23
26
  end
@@ -1,3 +1,3 @@
1
1
  module WebpFfi
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -19,28 +19,36 @@ module WebpFfi
19
19
  # get webp image size
20
20
  def webp_size(data)
21
21
  return nil if data.nil?
22
- size = data.respond_to?(:bytesize) ? data.bytesize : data.size
23
- width_ptr = FFI::MemoryPointer.new(:int, 2)
24
- height_ptr = FFI::MemoryPointer.new(:int, 2)
25
- memBuf = FFI::MemoryPointer.new(:char, size)
26
- memBuf.put_bytes(0, data)
27
- if C.webp_get_info(memBuf, size, width_ptr, height_ptr) == 0
28
- [width_ptr.null? ? nil : width_ptr.read_int, height_ptr.null? ? nil : height_ptr.read_int]
22
+ pointers = get_pointers_for_webp_size(data)
23
+ if 0 == C.webp_get_info(pointers[:data], pointers[:data_size], pointers[:width], pointers[:height])
24
+ [(pointers[:width].null? ? nil : pointers[:width].read_int), (pointers[:height].null? ? nil : pointers[:height].read_int)]
29
25
  else
30
- raise InvalidImageFormatError, "invalid webp image"
31
- return nil
26
+ raise InvalidImageFormatError, "invalid WebP image data"
32
27
  end
33
28
  end
34
29
 
30
+ # encode
31
+ def encode(input_file, output_file, options = {})
32
+ options_obj = Options.new options
33
+ res = C.webp_encode(input_file, output_file, options_obj.encode_pointer)
34
+ raise EncoderError, ENCODER_ERRORS[res - 1] unless 0 == res
35
+ return true
36
+ end
37
+
35
38
  # decode
36
39
  def decode(input_file, output_file, options = {})
37
- C.webp_decode(input_file, output_file)
40
+ res = C.webp_decode(input_file, output_file)
41
+ return true
38
42
  end
39
43
 
40
- # encode
41
- def encode(input_file, output_file, options = {})
42
- options_obj = Options.new options
43
- C.webp_encode(input_file, output_file, options_obj.encode_pointer)
44
+ private
45
+
46
+ def get_pointers_for_webp_size(data)
47
+ pointers = Hash.new
48
+ pointers[:data_size] = data.respond_to?(:bytesize) ? data.bytesize : data.size
49
+ pointers[:width], pointers[:height] = FFI::MemoryPointer.new(:int, 2), FFI::MemoryPointer.new(:int, 2)
50
+ pointers[:data] = FFI::MemoryPointer.new(:char, pointers[:data_size]).put_bytes(0, data)
51
+ pointers
44
52
  end
45
53
 
46
54
  end
@@ -37,8 +37,13 @@ describe WebpFfi do
37
37
  }
38
38
  }
39
39
  }
40
+
41
+ before :all do
42
+ @out_dir = File.expand_path(File.join(File.dirname(__FILE__), "../tmp/"))
43
+ Dir.mkdir(@out_dir) unless File.exists?(@out_dir)
44
+ end
40
45
 
41
- it "calculate plus 100 by test" do
46
+ it "calculate plus 100 by test_c (verify C)" do
42
47
  WebpFfi::C.test_c(100).should == 200
43
48
  WebpFfi::C.test_c(150).should == 250
44
49
  end
@@ -71,51 +76,38 @@ describe WebpFfi do
71
76
  end
72
77
  end
73
78
 
74
- context "decode" do
75
- factories[:webp].each do |image|
76
- it "#{image}.webp image" do
77
- out_dir = File.expand_path(File.join(File.dirname(__FILE__), "../tmp/"))
78
- Dir.mkdir(out_dir) unless File.exists?(out_dir)
79
- in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.webp"))
80
- out_filename = File.expand_path(File.join(out_dir, "#{image}.webp.png"))
81
- WebpFfi.decode(in_filename, out_filename)
82
- end
83
- end
84
- end
85
-
86
79
  context "encode" do
87
- before :all do
88
- @out_dir = File.expand_path(File.join(File.dirname(__FILE__), "../tmp/"))
89
- Dir.mkdir(@out_dir) unless File.exists?(@out_dir)
90
- end
91
80
  factories[:png].each do |image|
92
81
  it "#{image}.png image" do
93
82
  in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.png"))
94
83
  out_filename = File.expand_path(File.join(@out_dir, "#{image}.png.webp"))
95
- WebpFfi.encode(in_filename, out_filename)
84
+ WebpFfi.encode(in_filename, out_filename).should be_true
96
85
  end
97
86
  end
98
87
  factories[:jpg].each do |image|
99
88
  it "#{image}.jpg image" do
100
89
  in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.jpg"))
101
90
  out_filename = File.expand_path(File.join(@out_dir, "#{image}.jpg.webp"))
102
- WebpFfi.encode(in_filename, out_filename)
91
+ WebpFfi.encode(in_filename, out_filename).should be_true
103
92
  end
104
93
  end
105
94
  factories[:tiff].each do |image|
106
95
  it "#{image}.tif image" do
107
96
  in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.tif"))
108
97
  out_filename = File.expand_path(File.join(@out_dir, "#{image}.tif.webp"))
109
- WebpFfi.encode(in_filename, out_filename)
98
+ WebpFfi.encode(in_filename, out_filename).should be_true
99
+ end
100
+ end
101
+ factories[:webp].each do |image|
102
+ it "raise EncoderError on #{image}.webp image" do
103
+ in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.webp"))
104
+ out_filename = File.expand_path(File.join(@out_dir, "#{image}invalid.webp.png"))
105
+ expect { WebpFfi.encode(in_filename, out_filename) }.to raise_error WebpFfi::EncoderError
110
106
  end
111
107
  end
112
108
  end
113
109
 
114
110
  context "encode with options" do
115
- before :all do
116
- @out_dir = File.expand_path(File.join(File.dirname(__FILE__), "../tmp/"))
117
- Dir.mkdir(@out_dir) unless File.exists?(@out_dir)
118
- end
119
111
  factories[:png].each do |image|
120
112
  it "#{image}.png image" do
121
113
  in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.png"))
@@ -124,5 +116,25 @@ describe WebpFfi do
124
116
  end
125
117
  end
126
118
  end
119
+
120
+ context "raise EncoderError on invalid crop options" do
121
+ factories[:png].each do |image|
122
+ it "#{image}.png image" do
123
+ in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.png"))
124
+ out_filename = File.expand_path(File.join(@out_dir, "#{image}.50png.webp"))
125
+ expect { WebpFfi.encode(in_filename, out_filename, crop_w: 30000) }.to raise_error WebpFfi::EncoderError
126
+ end
127
+ end
128
+ end
129
+
130
+ context "decode" do
131
+ factories[:webp].each do |image|
132
+ it "#{image}.webp image" do
133
+ in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.webp"))
134
+ out_filename = File.expand_path(File.join(@out_dir, "#{image}.webp.png"))
135
+ WebpFfi.decode(in_filename, out_filename).should be_true
136
+ end
137
+ end
138
+ end
127
139
 
128
140
  end
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.extensions << 'ext/webp_ffi/Rakefile'
21
21
 
22
22
  spec.add_runtime_dependency "ffi", "~> 1.4.0"
23
- #spec.add_runtime_dependency "ffi-compiler", "~> 0.1.1"
23
+ spec.add_runtime_dependency "ffi-compiler", "~> 0.1.2"
24
24
 
25
25
  spec.add_development_dependency "bundler", ">= 1.2"
26
26
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webp-ffi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-10 00:00:00.000000000 Z
12
+ date: 2013-03-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: 1.4.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: ffi-compiler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.1.2
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.1.2
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: bundler
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +102,7 @@ files:
86
102
  - .gitignore
87
103
  - .rvmrc
88
104
  - .travis.yml
105
+ - CHANGELOG.md
89
106
  - Gemfile
90
107
  - LICENSE.txt
91
108
  - README.md
@@ -136,7 +153,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
153
  version: '0'
137
154
  segments:
138
155
  - 0
139
- hash: -4057552574747180548
156
+ hash: 2298624109850622941
140
157
  required_rubygems_version: !ruby/object:Gem::Requirement
141
158
  none: false
142
159
  requirements:
@@ -145,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
162
  version: '0'
146
163
  segments:
147
164
  - 0
148
- hash: -4057552574747180548
165
+ hash: 2298624109850622941
149
166
  requirements: []
150
167
  rubyforge_project:
151
168
  rubygems_version: 1.8.25