webp-ffi 0.0.1 → 0.1.0

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