webp-ffi 0.0.1 → 0.1.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.
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ .DS_Store
6
7
  Gemfile.lock
7
8
  InstalledFiles
8
9
  _yardoc
data/.travis.yml CHANGED
@@ -18,4 +18,6 @@ branches:
18
18
  matrix:
19
19
  allow_failures:
20
20
  - rvm: ruby-head
21
- - rvm: jruby-head
21
+ - rvm: jruby-head
22
+ - rvm: jruby-19mode
23
+ - rvm: rbx-19mode
data/README.md CHANGED
@@ -7,6 +7,27 @@ Ruby wrapper for libwebp.
7
7
 
8
8
  ## Installation
9
9
 
10
+ ### Requirements
11
+
12
+ First of all you should have install libraries: libpng, libjpeg and libwebp (for libwebp need libpng and libjpeg).
13
+
14
+ For ubuntu, debian:
15
+
16
+ sudo apt-get install libjpeg62-dev
17
+ sudo apt-get install libpng12-dev
18
+
19
+ For Mac OS:
20
+
21
+ sudo port install jpeg libpng
22
+
23
+ or:
24
+
25
+ brew install libjpg libpng
26
+
27
+ Next, you should [install libwebp](https://developers.google.com/speed/webp/docs/compiling).
28
+
29
+ ### Final part
30
+
10
31
  Add this line to your application's Gemfile:
11
32
 
12
33
  gem 'webp-ffi'
@@ -21,7 +42,42 @@ Or install it yourself as:
21
42
 
22
43
  ## Usage
23
44
 
24
- TODO: Write usage instructions here
45
+ Basic info about libwebp (encoder and decoder versions):
46
+
47
+ $ irb
48
+ 2.0.0p0 :001 > require 'webp_ffi'
49
+ => true
50
+ 2.0.0p0 :002 > WebpFfi.decoder_version
51
+ => "0.2.0"
52
+ 2.0.0p0 :003 > WebpFfi.encoder_version
53
+ => "0.2.0"
54
+
55
+ Get size (width and height) from webp image:
56
+
57
+ 2.0.0p0 :001 > require 'webp_ffi'
58
+ => true
59
+ 2.0.0p0 :006 > filename = File.expand_path(File.join(File.dirname(__FILE__), "spec/factories/4.webp"))
60
+ 2.0.0p0 :007 > WebpFfi.webp_size(data = File.open(filename, "rb").read)
61
+ => [2000, 2353]
62
+
63
+ Decode webp image to png:
64
+
65
+ 2.0.0p0 :008 > filename = File.expand_path(File.join(File.dirname(__FILE__), "spec/factories/4.webp"))
66
+ => "/Users/leo/programs/projects/webp-ffi/spec/factories/4.webp"
67
+ 2.0.0p0 :009 > out_filename = File.expand_path(File.join(File.dirname(__FILE__), "tmp/4.png"))
68
+ => "/Users/leo/programs/projects/webp-ffi/tmp/4.png"
69
+ 2.0.0p0 :010 > WebpFfi.decode(filename, out_filename)
70
+ Saved file /Users/leo/programs/projects/webp-ffi/tmp/4.png
71
+ => 0
72
+
73
+ Encode png image to webp:
74
+
75
+ 2.0.0p0 :011 > filename = File.expand_path(File.join(File.dirname(__FILE__), "spec/factories/4.png"))
76
+ => "/Users/leo/programs/projects/webp-ffi/spec/factories/4.png"
77
+ 2.0.0p0 :012 > out_filename = File.expand_path(File.join(File.dirname(__FILE__), "tmp/4.webp"))
78
+ => "/Users/leo/programs/projects/webp-ffi/tmp/4.webp"
79
+ 2.0.0p0 :013 > WebpFfi.encode(filename, out_filename)
80
+ => 0
25
81
 
26
82
  ## Contributing
27
83
 
data/Rakefile CHANGED
@@ -16,6 +16,8 @@ namespace "ffi-compiler" do
16
16
  c.have_func?('WebPDecoderConfig')
17
17
  c.have_func?('WebPGetInfo')
18
18
  c.have_library?('webp')
19
+ c.have_library?('png')
20
+ c.have_library?('jpeg')
19
21
  c.cflags << "-arch x86_64" if c.platform.mac?
20
22
  c.ldflags << "-arch x86_64" if c.platform.mac?
21
23
  end
@@ -10,7 +10,10 @@ FFI::Compiler::CompileTask.new('webp_ffi') do |c|
10
10
  c.have_func?('WebPDecoderConfig')
11
11
  c.have_func?('WebPGetInfo')
12
12
  c.have_library?('webp')
13
+ # libs
14
+ c.have_library?('png')
15
+ c.have_library?('jpeg')
13
16
  # compiler flags
14
- c.cflags << "-arch x86_64 -arch i386" if c.platform.mac?
15
- c.ldflags << "-arch x86_64 -arch i386" if c.platform.mac?
17
+ c.cflags << "-arch x86_64" if c.platform.mac?
18
+ c.ldflags << "-arch x86_64" if c.platform.mac?
16
19
  end
data/ext/webp_ffi/util.c CHANGED
@@ -1,15 +1,273 @@
1
1
  #include "./util.h"
2
+ #include <assert.h>
2
3
  #include <stdio.h>
3
4
  #include <stdlib.h>
5
+ #include <string.h>
6
+
7
+ #include <png.h>
8
+
9
+ #include <setjmp.h> // note: this must be included *after* png.h
10
+ #include <jpeglib.h>
11
+
12
+ #include "webp/decode.h"
13
+ #include "webp/encode.h"
4
14
 
5
15
  #if defined(__cplusplus) || defined(c_plusplus)
6
16
  extern "C" {
7
17
  #endif
8
18
 
19
+ static int UtilReadYUV(FILE* in_file, WebPPicture* const pic) {
20
+ const int use_argb = pic->use_argb;
21
+ const int uv_width = (pic->width + 1) / 2;
22
+ const int uv_height = (pic->height + 1) / 2;
23
+ int y;
24
+ int ok = 0;
25
+
26
+ pic->use_argb = 0;
27
+ if (!WebPPictureAlloc(pic)) return ok;
28
+
29
+ for (y = 0; y < pic->height; ++y) {
30
+ if (fread(pic->y + y * pic->y_stride, pic->width, 1, in_file) != 1) {
31
+ goto End;
32
+ }
33
+ }
34
+ for (y = 0; y < uv_height; ++y) {
35
+ if (fread(pic->u + y * pic->uv_stride, uv_width, 1, in_file) != 1)
36
+ goto End;
37
+ }
38
+ for (y = 0; y < uv_height; ++y) {
39
+ if (fread(pic->v + y * pic->uv_stride, uv_width, 1, in_file) != 1)
40
+ goto End;
41
+ }
42
+ ok = 1;
43
+ if (use_argb) ok = WebPPictureYUVAToARGB(pic);
44
+
45
+ End:
46
+ return ok;
47
+ }
48
+
49
+ static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
50
+ (void)dummy; // remove variable-unused warning
51
+ longjmp(png_jmpbuf(png), 1);
52
+ }
53
+
54
+ static int UtilReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
55
+ png_structp png;
56
+ png_infop info;
57
+ int color_type, bit_depth, interlaced;
58
+ int has_alpha;
59
+ int num_passes;
60
+ int p;
61
+ int ok = 0;
62
+ png_uint_32 width, height, y;
63
+ int stride;
64
+ uint8_t* rgb = NULL;
65
+
66
+ png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
67
+ if (png == NULL) {
68
+ goto End;
69
+ }
70
+
71
+ png_set_error_fn(png, 0, error_function, NULL);
72
+ if (setjmp(png_jmpbuf(png))) {
73
+ Error:
74
+ png_destroy_read_struct(&png, NULL, NULL);
75
+ free(rgb);
76
+ goto End;
77
+ }
78
+
79
+ info = png_create_info_struct(png);
80
+ if (info == NULL) goto Error;
81
+
82
+ png_init_io(png, in_file);
83
+ png_read_info(png, info);
84
+ if (!png_get_IHDR(png, info,
85
+ &width, &height, &bit_depth, &color_type, &interlaced,
86
+ NULL, NULL)) goto Error;
87
+
88
+ png_set_strip_16(png);
89
+ png_set_packing(png);
90
+ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
91
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
92
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
93
+ if (bit_depth < 8) {
94
+ png_set_expand_gray_1_2_4_to_8(png);
95
+ }
96
+ png_set_gray_to_rgb(png);
97
+ }
98
+ if (png_get_valid(png, info, PNG_INFO_tRNS)) {
99
+ png_set_tRNS_to_alpha(png);
100
+ has_alpha = 1;
101
+ } else {
102
+ has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
103
+ }
104
+
105
+ if (!keep_alpha) {
106
+ png_set_strip_alpha(png);
107
+ has_alpha = 0;
108
+ }
109
+
110
+ num_passes = png_set_interlace_handling(png);
111
+ png_read_update_info(png, info);
112
+ stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
113
+ rgb = (uint8_t*)malloc(stride * height);
114
+ if (rgb == NULL) goto Error;
115
+ for (p = 0; p < num_passes; ++p) {
116
+ for (y = 0; y < height; ++y) {
117
+ png_bytep row = rgb + y * stride;
118
+ png_read_rows(png, &row, NULL, 1);
119
+ }
120
+ }
121
+ png_read_end(png, info);
122
+ png_destroy_read_struct(&png, &info, NULL);
123
+
124
+ pic->width = width;
125
+ pic->height = height;
126
+ ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
127
+ : WebPPictureImportRGB(pic, rgb, stride);
128
+ free(rgb);
129
+
130
+ if (ok && has_alpha && keep_alpha == 2) {
131
+ WebPCleanupTransparentArea(pic);
132
+ }
133
+
134
+ End:
135
+ return ok;
136
+ }
137
+
138
+ static int UtilWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
139
+ const uint32_t width = buffer->width;
140
+ const uint32_t height = buffer->height;
141
+ unsigned char* const rgb = buffer->u.RGBA.rgba;
142
+ const int stride = buffer->u.RGBA.stride;
143
+ const int has_alpha = (buffer->colorspace == MODE_RGBA);
144
+ png_structp png;
145
+ png_infop info;
146
+ png_uint_32 y;
147
+
148
+ png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
149
+ NULL, error_function, NULL);
150
+ if (png == NULL) {
151
+ return 0;
152
+ }
153
+ info = png_create_info_struct(png);
154
+ if (info == NULL) {
155
+ png_destroy_write_struct(&png, NULL);
156
+ return 0;
157
+ }
158
+ if (setjmp(png_jmpbuf(png))) {
159
+ png_destroy_write_struct(&png, &info);
160
+ return 0;
161
+ }
162
+ png_init_io(png, out_file);
163
+ png_set_IHDR(png, info, width, height, 8,
164
+ has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
165
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
166
+ PNG_FILTER_TYPE_DEFAULT);
167
+ png_write_info(png, info);
168
+ for (y = 0; y < height; ++y) {
169
+ png_bytep row = rgb + y * stride;
170
+ png_write_rows(png, &row, 1);
171
+ }
172
+ png_write_end(png, info);
173
+ png_destroy_write_struct(&png, &info);
174
+ return 1;
175
+ }
176
+
177
+ static InputFileFormat GetImageType(FILE* in_file) {
178
+ InputFileFormat format = UNSUPPORTED;
179
+ unsigned int magic;
180
+ unsigned char buf[4];
181
+
182
+ if ((fread(&buf[0], 4, 1, in_file) != 1) ||
183
+ (fseek(in_file, 0, SEEK_SET) != 0)) {
184
+ return format;
185
+ }
186
+
187
+ magic = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
188
+ if (magic == 0x89504E47U) {
189
+ format = PNG_;
190
+ } else if (magic >= 0xFFD8FF00U && magic <= 0xFFD8FFFFU) {
191
+ format = JPEG_;
192
+ } else if (magic == 0x49492A00 || magic == 0x4D4D002A) {
193
+ format = TIFF_;
194
+ }
195
+ return format;
196
+ }
197
+
198
+ int UtilReadPicture(const char* const filename, WebPPicture* const pic,
199
+ int keep_alpha) {
200
+ int ok = 0;
201
+ FILE* in_file = fopen(filename, "rb");
202
+ if (in_file == NULL) {
203
+ fprintf(stderr, "Error! Cannot open input file '%s'\n", filename);
204
+ return ok;
205
+ }
206
+
207
+ if (pic->width == 0 || pic->height == 0) {
208
+ // If no size specified, try to decode it as PNG/JPEG (as appropriate).
209
+ const InputFileFormat format = GetImageType(in_file);
210
+ if (format == PNG_) {
211
+ ok = UtilReadPNG(in_file, pic, keep_alpha);
212
+ }
213
+ /*
214
+ } else if (format == JPEG_) {
215
+ ok = ReadJPEG(in_file, pic);
216
+ } else if (format == TIFF_) {
217
+ ok = ReadTIFF(filename, pic, keep_alpha);
218
+ }
219
+ */
220
+ } else {
221
+ // If image size is specified, infer it as YUV format.
222
+ ok = UtilReadYUV(in_file, pic);
223
+ }
224
+ if (!ok) {
225
+ fprintf(stderr, "Error! Could not process file %s\n", filename);
226
+ }
227
+
228
+ fclose(in_file);
229
+ return ok;
230
+ }
231
+
232
+ void UtilSaveOutput(const WebPDecBuffer* const buffer,
233
+ OutputFileFormat format, const char* const out_file) {
234
+ FILE* fout = NULL;
235
+ int ok = 1;
236
+
237
+ fout = fopen(out_file, "wb");
238
+ if (!fout) {
239
+ fprintf(stderr, "Error opening output file %s\n", out_file);
240
+ return;
241
+ }
242
+
243
+ if (format == PNG) {
244
+ ok &= UtilWritePNG(fout, buffer);
245
+ }
246
+ /*
247
+ } else if (format == PAM) {
248
+ ok &= WritePPM(fout, buffer, 1);
249
+ } else if (format == PPM) {
250
+ ok &= WritePPM(fout, buffer, 0);
251
+ } else if (format == PGM) {
252
+ ok &= WritePGM(fout, buffer);
253
+ } else if (format == ALPHA_PLANE_ONLY) {
254
+ ok &= WriteAlphaPlane(fout, buffer);
255
+ }
256
+ */
257
+ if (fout) {
258
+ fclose(fout);
259
+ }
260
+ if (ok) {
261
+ printf("Saved file %s\n", out_file);
262
+ } else {
263
+ fprintf(stderr, "Error writing file %s !!\n", out_file);
264
+ }
265
+ }
266
+
9
267
  // -----------------------------------------------------------------------------
10
268
  // File I/O
11
269
 
12
- int WebpFfiReadFile(const char* const file_name,
270
+ int UtilReadFile(const char* const file_name,
13
271
  const uint8_t** data, size_t* data_size) {
14
272
  int ok;
15
273
  void* file_data;
data/ext/webp_ffi/util.h CHANGED
@@ -1,13 +1,30 @@
1
- #include "webp/types.h"
1
+ #include "webp/decode.h"
2
+ #include "webp/encode.h"
2
3
 
3
4
  #if defined(__cplusplus) || defined(c_plusplus)
4
5
  extern "C" {
5
6
  #endif
6
7
 
8
+ typedef enum {
9
+ PNG = 0,
10
+ PAM,
11
+ PPM,
12
+ PGM,
13
+ ALPHA_PLANE_ONLY // this is for experimenting only
14
+ } OutputFileFormat;
15
+
16
+ typedef enum {
17
+ PNG_ = 0,
18
+ JPEG_,
19
+ TIFF_, // 'TIFF' clashes with libtiff
20
+ UNSUPPORTED
21
+ } InputFileFormat;
22
+
23
+ void UtilSaveOutput(const WebPDecBuffer* const buffer, OutputFileFormat format, const char* const out_file);
7
24
  // Allocates storage for entire file 'file_name' and returns contents and size
8
25
  // in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
9
26
  // be deleted using free().
10
- int WebpFfiReadFile(const char* const file_name,
27
+ int UtilReadFile(const char* const file_name,
11
28
  const uint8_t** data, size_t* data_size);
12
29
 
13
30
  #if defined(__cplusplus) || defined(c_plusplus)
@@ -10,23 +10,24 @@
10
10
  #include "./util.h"
11
11
  #include "./webp_ffi.h"
12
12
 
13
- #ifdef WEBP_HAVE_PNG
14
- #include <png.h>
15
- #endif
16
13
 
17
- #ifdef WEBP_HAVE_JPEG
18
- #include <setjmp.h> // note: this must be included *after* png.h
19
- #include <jpeglib.h>
14
+ #if defined(__cplusplus) || defined(c_plusplus)
15
+ extern "C" {
20
16
  #endif
21
17
 
22
- #ifdef WEBP_HAVE_TIFF
23
- #include <tiffio.h>
24
- #endif
18
+ static int EncodeWriter(const uint8_t* data, size_t data_size,
19
+ const WebPPicture* const pic) {
20
+ FILE* const out = (FILE*)pic->custom_ptr;
21
+ return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
22
+ }
25
23
 
24
+ static void AllocExtraInfo(WebPPicture* const pic) {
25
+ const int mb_w = (pic->width + 15) / 16;
26
+ const int mb_h = (pic->height + 15) / 16;
27
+ pic->extra_info = (uint8_t*)malloc(mb_w * mb_h * sizeof(*pic->extra_info));
28
+ }
26
29
 
27
- #if defined(__cplusplus) || defined(c_plusplus)
28
- extern "C" {
29
- #endif
30
+ // main functions
30
31
 
31
32
  void decoder_version(char *version) {
32
33
  int v = WebPGetDecoderVersion();
@@ -41,11 +42,132 @@ void encoder_version(char *version) {
41
42
  }
42
43
 
43
44
  int webp_get_info(const uint8_t* data, size_t data_size, int* width, int* height) {
44
- return WebPGetInfo(data, data_size, width, height);
45
+ if (WebPGetInfo(data, data_size, width, height) == 1) {
46
+ return 0;
47
+ } else {
48
+ return 1;
49
+ }
45
50
  }
46
51
 
47
- uint8_t* webp_decode_rgba(const uint8_t* data, size_t data_size, int* width, int* height) {
48
- return WebPDecodeRGBA(data, data_size, width, height);
52
+
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
+ int webp_encode(const char *in_file, const char *out_file) {
118
+ int return_value = -1;
119
+ FILE *out = NULL;
120
+ int keep_alpha = 1;
121
+ WebPPicture picture;
122
+ WebPConfig config;
123
+
124
+
125
+ if (!WebPPictureInit(&picture) ||
126
+ !WebPConfigInit(&config)) {
127
+ fprintf(stderr, "Error! Version mismatch!\n");
128
+ return 1;
129
+ }
130
+
131
+ if (!WebPValidateConfig(&config)) {
132
+ fprintf(stderr, "Error! Invalid configuration.\n");
133
+ return_value = 2;
134
+ goto Error;
135
+ }
136
+
137
+ if (!UtilReadPicture(in_file, &picture, keep_alpha)) {
138
+ fprintf(stderr, "Error! Cannot read input picture file '%s'\n", in_file);
139
+ return_value = 3;
140
+ goto Error;
141
+ }
142
+
143
+ out = fopen(out_file, "wb");
144
+ if (out == NULL) {
145
+ fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
146
+ return_value = 4;
147
+ goto Error;
148
+ }
149
+ picture.writer = EncodeWriter;
150
+ picture.custom_ptr = (void*)out;
151
+
152
+ if (picture.extra_info_type > 0) {
153
+ AllocExtraInfo(&picture);
154
+ }
155
+
156
+ if (!WebPEncode(&config, &picture)) {
157
+ fprintf(stderr, "Error! Cannot encode picture as WebP\n");
158
+ return_value = 5;
159
+ goto Error;
160
+ }
161
+ return_value = 0;
162
+
163
+ Error:
164
+ free(picture.extra_info);
165
+ WebPPictureFree(&picture);
166
+ if (out != NULL) {
167
+ fclose(out);
168
+ }
169
+
170
+ return return_value;
49
171
  }
50
172
 
51
173
  // test
@@ -5,10 +5,17 @@
5
5
  extern "C" {
6
6
  #endif
7
7
 
8
+ typedef struct {
9
+ int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
10
+ float quality; // between 0 (smallest file) and 100 (biggest)
11
+ int method; // quality/speed trade-off (0=fast, 6=slower-better)
12
+ } FfiWebpConfig;
13
+
8
14
  void decoder_version(char *version);
9
15
  void encoder_version(char *version);
10
16
  int webp_get_info(const uint8_t* data, size_t data_size, int* width, int* height);
11
- uint8_t* webp_decode_rgba(const uint8_t* data, size_t data_size, int* width, int* height);
17
+ int webp_decode(const char *in_file, const char *out_file);
18
+ int webp_encode(const char *in_file, const char *out_file);
12
19
  int test(int n);
13
20
 
14
21
  #if defined(__cplusplus) || defined(c_plusplus)
data/lib/webp_ffi.rb CHANGED
@@ -10,5 +10,6 @@ end
10
10
 
11
11
  require "webp_ffi/c"
12
12
  require "webp_ffi/error"
13
+ require "webp_ffi/libc"
13
14
  require "webp_ffi/webp_ffi"
14
15
  require "webp_ffi/version"
data/lib/webp_ffi/c.rb CHANGED
@@ -1,26 +1,24 @@
1
1
  module WebpFfi
2
2
  module C
3
3
  # enum
4
- vp8_status_code_enum = enum(:vp8_status_ok, 0,
5
- :vp8_status_out_of_memory,
6
- :vp8_status_invalid_params,
7
- :vp8_status_bitstream_error,
8
- :vp8_status_unsupported_feature,
9
- :vp8_status_suspended,
10
- :vp8_status_user_abort,
11
- :vp8_status_not_enought_data)
4
+ WebpImageHint = enum(:webp_hint_default, 0,
5
+ :webp_hint_picture,
6
+ :webp_hint_photo,
7
+ :webp_hint_graph,
8
+ :webp_hint_last)
12
9
  # struct
13
- class WebPBitstreamFeatures < FFI::Struct
14
- layout :width, :int,
15
- :height, :int,
16
- :has_alpha, :int
10
+ class FfiWebpConfig < FFI::Struct
11
+ layout :lossless, :int,
12
+ :quality, :float,
13
+ :method, :int
17
14
  end
18
-
15
+
19
16
  # webp lib functions
20
17
  attach_function :decoder_version, [:pointer], :void
21
18
  attach_function :encoder_version, [:pointer], :void
22
19
  attach_function :webp_get_info, [:pointer, :size_t, :pointer, :pointer], :int
23
- attach_function :webp_decode_rgba, [:pointer, :size_t, :pointer, :pointer], :pointer
20
+ attach_function :webp_decode, [:string, :string], :int
21
+ attach_function :webp_encode, [:string, :string], :int
24
22
 
25
23
  attach_function :test, [:int], :int
26
24
  end
@@ -0,0 +1,20 @@
1
+ module WebpFfi
2
+ module LibC
3
+ extend FFI::Library
4
+ # figures out the correct libc for each platform including Windows
5
+ library = ffi_lib(FFI::Library::LIBC).first
6
+
7
+ # Size_t not working properly on Windows
8
+ find_type(:size_t) rescue typedef(:ulong, :size_t)
9
+
10
+ # memory allocators
11
+ attach_function :malloc, [:size_t], :pointer
12
+ attach_function :free, [:pointer], :void
13
+
14
+ # get a pointer to the free function
15
+ Free = library.find_symbol('free')
16
+
17
+ # memory movers
18
+ attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
19
+ end # module LibC
20
+ end
@@ -1,3 +1,3 @@
1
1
  module WebpFfi
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -18,12 +18,12 @@ module WebpFfi
18
18
  # get webp image size
19
19
  def webp_size(data)
20
20
  return nil if data.nil?
21
+ size = data.respond_to?(:bytesize) ? data.bytesize : data.size
21
22
  width_ptr = FFI::MemoryPointer.new(:int, 2)
22
23
  height_ptr = FFI::MemoryPointer.new(:int, 2)
23
- size = data.respond_to?(:bytesize) ? data.bytesize : data.size
24
24
  memBuf = FFI::MemoryPointer.new(:char, size)
25
25
  memBuf.put_bytes(0, data)
26
- if C.webp_get_info(memBuf, size, width_ptr, height_ptr) == 1
26
+ if C.webp_get_info(memBuf, size, width_ptr, height_ptr) == 0
27
27
  [width_ptr.null? ? nil : width_ptr.read_int, height_ptr.null? ? nil : height_ptr.read_int]
28
28
  else
29
29
  raise InvalidImageFormatError, "invalid webp image"
@@ -31,15 +31,14 @@ module WebpFfi
31
31
  end
32
32
  end
33
33
 
34
- def webp_decode_rgba(data)
35
- return nil if data.nil?
36
- width_ptr = FFI::MemoryPointer.new(:int, 2)
37
- height_ptr = FFI::MemoryPointer.new(:int, 2)
38
- size = data.respond_to?(:bytesize) ? data.bytesize : data.size
39
- memBuf = FFI::MemoryPointer.new(:char, size)
40
- memBuf.put_bytes(0, data)
41
- pointer = C.webp_decode_rgba(memBuf, size, width_ptr, height_ptr)
42
- pointer.null? ? nil : pointer.read_string()
34
+ # decode
35
+ def decode(input_file, output_file, options = {})
36
+ C.webp_decode(input_file, output_file)
37
+ end
38
+
39
+ # encode
40
+ def encode(input_file, output_file, options = {})
41
+ C.webp_encode(input_file, output_file)
43
42
  end
44
43
 
45
44
  end
@@ -2,29 +2,31 @@ require 'spec_helper'
2
2
 
3
3
  describe WebpFfi do
4
4
  factories = {
5
- webp: ["1.webp", "2.webp", "3.webp", "4.webp", "5.webp", "6.webp"],
5
+ webp: ["1", "2", "3", "4", "5", "6"],
6
+ png: ["1", "2", "3", "4"],
7
+ jpg: ["5", "6"],
6
8
  info: {
7
- "1.webp" => {
9
+ "1" => {
8
10
  size: [400, 301],
9
11
  has_alpha: true
10
12
  },
11
- "2.webp" => {
13
+ "2" => {
12
14
  size: [386, 395],
13
15
  has_alpha: true
14
16
  },
15
- "3.webp" => {
17
+ "3" => {
16
18
  size: [300, 300],
17
19
  has_alpha: true
18
20
  },
19
- "4.webp" => {
21
+ "4" => {
20
22
  size: [2000, 2353],
21
23
  has_alpha: true
22
24
  },
23
- "5.webp" => {
25
+ "5" => {
24
26
  size: [550, 368],
25
27
  has_alpha: false
26
28
  },
27
- "6.webp" => {
29
+ "6" => {
28
30
  size: [1024, 772],
29
31
  has_alpha: false
30
32
  }
@@ -49,7 +51,7 @@ describe WebpFfi do
49
51
  context "webp_size" do
50
52
  factories[:webp].each do |image|
51
53
  it "#{image} image size == #{factories[:info][image][:size]}" do
52
- filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}"))
54
+ filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.webp"))
53
55
  data = File.open(filename, "rb").read
54
56
  info = WebpFfi.webp_size(data)
55
57
  info.class.should == Array
@@ -64,13 +66,26 @@ describe WebpFfi do
64
66
  end
65
67
  end
66
68
 
67
- context "webp_decode_rgba" do
69
+ context "decode" do
68
70
  factories[:webp].each do |image|
69
- it "#{image} webp_decode_rgba" do
70
- filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}"))
71
- data = File.open(filename, "rb").read
72
- output_data = WebpFfi.webp_decode_rgba(data)
73
- # TODO: finish
71
+ it "#{image}.webp image" do
72
+ out_dir = File.expand_path(File.join(File.dirname(__FILE__), "../tmp/"))
73
+ Dir.mkdir(out_dir) unless File.exists?(out_dir)
74
+ in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.webp"))
75
+ out_filename = File.expand_path(File.join(out_dir, "#{image}.webp.png"))
76
+ WebpFfi.decode(in_filename, out_filename)
77
+ end
78
+ end
79
+ end
80
+
81
+ context "encode" do
82
+ factories[:png].each do |image|
83
+ it "#{image}.png image" do
84
+ out_dir = File.expand_path(File.join(File.dirname(__FILE__), "../tmp/"))
85
+ Dir.mkdir(out_dir) unless File.exists?(out_dir)
86
+ in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.png"))
87
+ out_filename = File.expand_path(File.join(out_dir, "#{image}.png.webp"))
88
+ WebpFfi.encode(in_filename, out_filename)
74
89
  end
75
90
  end
76
91
  end
data/webp-ffi.gemspec CHANGED
@@ -25,5 +25,4 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "bundler", ">= 1.2"
26
26
  spec.add_development_dependency "rake"
27
27
  spec.add_development_dependency "rspec"
28
- spec.add_development_dependency "vagrant"
29
28
  end
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.0.1
4
+ version: 0.1.0
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-08 00:00:00.000000000 Z
12
+ date: 2013-03-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
@@ -75,22 +75,6 @@ dependencies:
75
75
  - - '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
- - !ruby/object:Gem::Dependency
79
- name: vagrant
80
- requirement: !ruby/object:Gem::Requirement
81
- none: false
82
- requirements:
83
- - - '>='
84
- - !ruby/object:Gem::Version
85
- version: '0'
86
- type: :development
87
- prerelease: false
88
- version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
- requirements:
91
- - - '>='
92
- - !ruby/object:Gem::Version
93
- version: '0'
94
78
  description: Ruby wrapper for libwebp
95
79
  email:
96
80
  - leopard.not.a@gmail.com
@@ -115,6 +99,7 @@ files:
115
99
  - lib/webp_ffi.rb
116
100
  - lib/webp_ffi/c.rb
117
101
  - lib/webp_ffi/error.rb
102
+ - lib/webp_ffi/libc.rb
118
103
  - lib/webp_ffi/version.rb
119
104
  - lib/webp_ffi/webp_ffi.rb
120
105
  - spec/bindings.md
@@ -149,7 +134,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
134
  version: '0'
150
135
  segments:
151
136
  - 0
152
- hash: 488812102417916187
137
+ hash: -112599722798268677
153
138
  required_rubygems_version: !ruby/object:Gem::Requirement
154
139
  none: false
155
140
  requirements:
@@ -158,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
143
  version: '0'
159
144
  segments:
160
145
  - 0
161
- hash: 488812102417916187
146
+ hash: -112599722798268677
162
147
  requirements: []
163
148
  rubyforge_project:
164
149
  rubygems_version: 1.8.25