webp-ffi 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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