webp-ffi 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +1 -1
- data/CHANGELOG.md +4 -0
- data/ext/webp_ffi/jpegdec.c +80 -0
- data/ext/webp_ffi/jpegdec.h +17 -0
- data/ext/webp_ffi/pngdec.c +212 -0
- data/ext/webp_ffi/pngdec.h +24 -0
- data/ext/webp_ffi/tiffdec.c +197 -0
- data/ext/webp_ffi/tiffdec.h +23 -0
- data/ext/webp_ffi/util.c +4 -470
- data/lib/webp/version.rb +1 -1
- data/spec/webp_ffi_spec.rb +7 -7
- data/webp-ffi.gemspec +1 -1
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34b1495b74a5385dd27950b6e4bc2f4e5391fa97
|
4
|
+
data.tar.gz: 90b299d673ff0c22afef51ffbb61d6fabd4733ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe4fd8a5a8b3fe9b741bc028c55f13272ff1e642961d88b9bc4bbcbf74b4554c0312617a0e13b3b106473846587d0d4cbee2a0ae0818347e0f471d91badee2f1
|
7
|
+
data.tar.gz: 7a7b54b518cee8bb959c6a074c4983991492ec1cce5192a8f915568d748f20ad7570581952dd5c1b09ce0e471d87104532ff42c6cb849413a05f6e6b0f89eba4
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.2
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
#include "./jpegdec.h"
|
2
|
+
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <jpeglib.h>
|
5
|
+
#include <setjmp.h>
|
6
|
+
#include <stdlib.h>
|
7
|
+
#include <string.h>
|
8
|
+
|
9
|
+
struct my_error_mgr {
|
10
|
+
struct jpeg_error_mgr pub;
|
11
|
+
jmp_buf setjmp_buffer;
|
12
|
+
};
|
13
|
+
|
14
|
+
static void my_error_exit(j_common_ptr dinfo) {
|
15
|
+
struct my_error_mgr* myerr = (struct my_error_mgr*) dinfo->err;
|
16
|
+
(*dinfo->err->output_message) (dinfo);
|
17
|
+
longjmp(myerr->setjmp_buffer, 1);
|
18
|
+
}
|
19
|
+
|
20
|
+
int UtilReadJPEG(FILE* in_file, WebPPicture* const pic) {
|
21
|
+
int ok = 0;
|
22
|
+
int stride, width, height;
|
23
|
+
uint8_t* rgb = NULL;
|
24
|
+
struct jpeg_decompress_struct dinfo;
|
25
|
+
struct my_error_mgr jerr;
|
26
|
+
JSAMPROW buffer[1];
|
27
|
+
|
28
|
+
dinfo.err = jpeg_std_error(&jerr.pub);
|
29
|
+
jerr.pub.error_exit = my_error_exit;
|
30
|
+
|
31
|
+
if (setjmp(jerr.setjmp_buffer)) {
|
32
|
+
Error:
|
33
|
+
jpeg_destroy_decompress(&dinfo);
|
34
|
+
goto End;
|
35
|
+
}
|
36
|
+
|
37
|
+
jpeg_create_decompress(&dinfo);
|
38
|
+
jpeg_stdio_src(&dinfo, in_file);
|
39
|
+
jpeg_read_header(&dinfo, TRUE);
|
40
|
+
|
41
|
+
dinfo.out_color_space = JCS_RGB;
|
42
|
+
dinfo.do_fancy_upsampling = TRUE;
|
43
|
+
|
44
|
+
jpeg_start_decompress(&dinfo);
|
45
|
+
|
46
|
+
if (dinfo.output_components != 3) {
|
47
|
+
goto Error;
|
48
|
+
}
|
49
|
+
|
50
|
+
width = dinfo.output_width;
|
51
|
+
height = dinfo.output_height;
|
52
|
+
stride = dinfo.output_width * dinfo.output_components * sizeof(*rgb);
|
53
|
+
|
54
|
+
rgb = (uint8_t*)malloc(stride * height);
|
55
|
+
if (rgb == NULL) {
|
56
|
+
goto End;
|
57
|
+
}
|
58
|
+
buffer[0] = (JSAMPLE*)rgb;
|
59
|
+
|
60
|
+
while (dinfo.output_scanline < dinfo.output_height) {
|
61
|
+
if (jpeg_read_scanlines(&dinfo, buffer, 1) != 1) {
|
62
|
+
goto End;
|
63
|
+
}
|
64
|
+
buffer[0] += stride;
|
65
|
+
}
|
66
|
+
|
67
|
+
jpeg_finish_decompress(&dinfo);
|
68
|
+
jpeg_destroy_decompress(&dinfo);
|
69
|
+
|
70
|
+
// WebP conversion.
|
71
|
+
pic->width = width;
|
72
|
+
pic->height = height;
|
73
|
+
ok = WebPPictureImportRGB(pic, rgb, stride);
|
74
|
+
if (!ok) goto Error;
|
75
|
+
|
76
|
+
End:
|
77
|
+
free(rgb);
|
78
|
+
return ok;
|
79
|
+
}
|
80
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
|
3
|
+
#include "webp/encode.h"
|
4
|
+
#include "webp/decode.h"
|
5
|
+
|
6
|
+
#ifdef __cplusplus
|
7
|
+
extern "C" {
|
8
|
+
#endif
|
9
|
+
|
10
|
+
// Reads a JPEG from 'in_file', returning the decoded output in 'pic'.
|
11
|
+
// The output is RGB.
|
12
|
+
// Returns true on success.
|
13
|
+
int UtilReadJPEG(FILE* in_file, struct WebPPicture* const pic);
|
14
|
+
|
15
|
+
#ifdef __cplusplus
|
16
|
+
} // extern "C"
|
17
|
+
#endif
|
@@ -0,0 +1,212 @@
|
|
1
|
+
#include "./pngdec.h"
|
2
|
+
|
3
|
+
#include <assert.h>
|
4
|
+
#include <stdio.h>
|
5
|
+
#include <png.h>
|
6
|
+
#include <setjmp.h> // note: this must be included *after* png.h
|
7
|
+
#include <stdlib.h>
|
8
|
+
#include <string.h>
|
9
|
+
|
10
|
+
static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
|
11
|
+
(void)dummy; // remove variable-unused warning
|
12
|
+
longjmp(png_jmpbuf(png), 1);
|
13
|
+
}
|
14
|
+
|
15
|
+
int UtilReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
|
16
|
+
png_structp png;
|
17
|
+
png_infop info = NULL;
|
18
|
+
png_infop end_info = NULL;
|
19
|
+
int color_type, bit_depth, interlaced;
|
20
|
+
int has_alpha;
|
21
|
+
int num_passes;
|
22
|
+
int p;
|
23
|
+
int ok = 0;
|
24
|
+
png_uint_32 width, height, y;
|
25
|
+
int stride;
|
26
|
+
uint8_t* rgb = NULL;
|
27
|
+
|
28
|
+
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
29
|
+
if (png == NULL) {
|
30
|
+
goto End;
|
31
|
+
}
|
32
|
+
|
33
|
+
png_set_error_fn(png, 0, error_function, NULL);
|
34
|
+
if (setjmp(png_jmpbuf(png))) {
|
35
|
+
Error:
|
36
|
+
png_destroy_read_struct(&png, &info, &end_info);
|
37
|
+
goto End;
|
38
|
+
}
|
39
|
+
|
40
|
+
info = png_create_info_struct(png);
|
41
|
+
if (info == NULL) goto Error;
|
42
|
+
end_info = png_create_info_struct(png);
|
43
|
+
if (end_info == NULL) goto Error;
|
44
|
+
|
45
|
+
png_init_io(png, in_file);
|
46
|
+
png_read_info(png, info);
|
47
|
+
if (!png_get_IHDR(png, info,
|
48
|
+
&width, &height, &bit_depth, &color_type, &interlaced,
|
49
|
+
NULL, NULL)) goto Error;
|
50
|
+
|
51
|
+
png_set_strip_16(png);
|
52
|
+
png_set_packing(png);
|
53
|
+
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
|
54
|
+
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
55
|
+
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
56
|
+
if (bit_depth < 8) {
|
57
|
+
png_set_expand_gray_1_2_4_to_8(png);
|
58
|
+
}
|
59
|
+
png_set_gray_to_rgb(png);
|
60
|
+
}
|
61
|
+
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
|
62
|
+
png_set_tRNS_to_alpha(png);
|
63
|
+
has_alpha = 1;
|
64
|
+
} else {
|
65
|
+
has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
|
66
|
+
}
|
67
|
+
|
68
|
+
if (!keep_alpha) {
|
69
|
+
png_set_strip_alpha(png);
|
70
|
+
has_alpha = 0;
|
71
|
+
}
|
72
|
+
|
73
|
+
num_passes = png_set_interlace_handling(png);
|
74
|
+
png_read_update_info(png, info);
|
75
|
+
stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
|
76
|
+
rgb = (uint8_t*)malloc(stride * height);
|
77
|
+
if (rgb == NULL) goto Error;
|
78
|
+
for (p = 0; p < num_passes; ++p) {
|
79
|
+
for (y = 0; y < height; ++y) {
|
80
|
+
png_bytep row = rgb + y * stride;
|
81
|
+
png_read_rows(png, &row, NULL, 1);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
png_read_end(png, end_info);
|
85
|
+
png_destroy_read_struct(&png, &info, &end_info);
|
86
|
+
|
87
|
+
pic->width = width;
|
88
|
+
pic->height = height;
|
89
|
+
pic->use_argb = 1;
|
90
|
+
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
|
91
|
+
: WebPPictureImportRGB(pic, rgb, stride);
|
92
|
+
|
93
|
+
if (!ok) {
|
94
|
+
goto Error;
|
95
|
+
}
|
96
|
+
|
97
|
+
End:
|
98
|
+
free(rgb);
|
99
|
+
return ok;
|
100
|
+
}
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
int UtilWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
|
107
|
+
const uint32_t width = buffer->width;
|
108
|
+
const uint32_t height = buffer->height;
|
109
|
+
unsigned char* const rgb = buffer->u.RGBA.rgba;
|
110
|
+
const int stride = buffer->u.RGBA.stride;
|
111
|
+
const int has_alpha = (buffer->colorspace == MODE_RGBA);
|
112
|
+
png_structp png;
|
113
|
+
png_infop info;
|
114
|
+
png_uint_32 y;
|
115
|
+
|
116
|
+
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
117
|
+
NULL, error_function, NULL);
|
118
|
+
if (png == NULL) {
|
119
|
+
return 0;
|
120
|
+
}
|
121
|
+
info = png_create_info_struct(png);
|
122
|
+
if (info == NULL) {
|
123
|
+
png_destroy_write_struct(&png, NULL);
|
124
|
+
return 0;
|
125
|
+
}
|
126
|
+
if (setjmp(png_jmpbuf(png))) {
|
127
|
+
png_destroy_write_struct(&png, &info);
|
128
|
+
return 0;
|
129
|
+
}
|
130
|
+
png_init_io(png, out_file);
|
131
|
+
png_set_IHDR(png, info, width, height, 8,
|
132
|
+
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
|
133
|
+
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
134
|
+
PNG_FILTER_TYPE_DEFAULT);
|
135
|
+
png_write_info(png, info);
|
136
|
+
for (y = 0; y < height; ++y) {
|
137
|
+
png_bytep row = rgb + y * stride;
|
138
|
+
png_write_rows(png, &row, 1);
|
139
|
+
}
|
140
|
+
png_write_end(png, info);
|
141
|
+
png_destroy_write_struct(&png, &info);
|
142
|
+
return 1;
|
143
|
+
}
|
144
|
+
|
145
|
+
|
146
|
+
int UtilWritePPM(FILE* fout, const WebPDecBuffer* const buffer, int alpha) {
|
147
|
+
const uint32_t width = buffer->width;
|
148
|
+
const uint32_t height = buffer->height;
|
149
|
+
const unsigned char* const rgb = buffer->u.RGBA.rgba;
|
150
|
+
const int stride = buffer->u.RGBA.stride;
|
151
|
+
const size_t bytes_per_px = alpha ? 4 : 3;
|
152
|
+
uint32_t y;
|
153
|
+
|
154
|
+
if (alpha) {
|
155
|
+
fprintf(fout, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\n"
|
156
|
+
"TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
|
157
|
+
} else {
|
158
|
+
fprintf(fout, "P6\n%d %d\n255\n", width, height);
|
159
|
+
}
|
160
|
+
for (y = 0; y < height; ++y) {
|
161
|
+
if (fwrite(rgb + y * stride, width, bytes_per_px, fout) != bytes_per_px) {
|
162
|
+
return 0;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
return 1;
|
166
|
+
}
|
167
|
+
|
168
|
+
int UtilWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
|
169
|
+
const uint32_t width = buffer->width;
|
170
|
+
const uint32_t height = buffer->height;
|
171
|
+
const unsigned char* const a = buffer->u.YUVA.a;
|
172
|
+
const int a_stride = buffer->u.YUVA.a_stride;
|
173
|
+
uint32_t y;
|
174
|
+
assert(a != NULL);
|
175
|
+
fprintf(fout, "P5\n%d %d\n255\n", width, height);
|
176
|
+
for (y = 0; y < height; ++y) {
|
177
|
+
if (fwrite(a + y * a_stride, width, 1, fout) != 1) {
|
178
|
+
return 0;
|
179
|
+
}
|
180
|
+
}
|
181
|
+
return 1;
|
182
|
+
}
|
183
|
+
|
184
|
+
int UtilWritePGM(FILE* fout, const WebPDecBuffer* const buffer) {
|
185
|
+
const int width = buffer->width;
|
186
|
+
const int height = buffer->height;
|
187
|
+
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
|
188
|
+
// Save a grayscale PGM file using the IMC4 layout
|
189
|
+
// (http://www.fourcc.org/yuv.php#IMC4). This is a very
|
190
|
+
// convenient format for viewing the samples, esp. for
|
191
|
+
// odd dimensions.
|
192
|
+
int ok = 1;
|
193
|
+
int y;
|
194
|
+
const int uv_width = (width + 1) / 2;
|
195
|
+
const int uv_height = (height + 1) / 2;
|
196
|
+
const int out_stride = (width + 1) & ~1;
|
197
|
+
const int a_height = yuv->a ? height : 0;
|
198
|
+
fprintf(fout, "P5\n%d %d\n255\n", out_stride, height + uv_height + a_height);
|
199
|
+
for (y = 0; ok && y < height; ++y) {
|
200
|
+
ok &= (fwrite(yuv->y + y * yuv->y_stride, width, 1, fout) == 1);
|
201
|
+
if (width & 1) fputc(0, fout); // padding byte
|
202
|
+
}
|
203
|
+
for (y = 0; ok && y < uv_height; ++y) {
|
204
|
+
ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
|
205
|
+
ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
|
206
|
+
}
|
207
|
+
for (y = 0; ok && y < a_height; ++y) {
|
208
|
+
ok &= (fwrite(yuv->a + y * yuv->a_stride, width, 1, fout) == 1);
|
209
|
+
if (width & 1) fputc(0, fout); // padding byte
|
210
|
+
}
|
211
|
+
return ok;
|
212
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
#include "webp/encode.h"
|
5
|
+
#include "webp/decode.h"
|
6
|
+
|
7
|
+
#ifdef __cplusplus
|
8
|
+
extern "C" {
|
9
|
+
#endif
|
10
|
+
|
11
|
+
// Reads a PNG from 'in_file', returning the decoded output in 'pic'.
|
12
|
+
// If 'keep_alpha' is true and the PNG has an alpha channel, the output is RGBA
|
13
|
+
// otherwise it will be RGB.
|
14
|
+
// Returns true on success.
|
15
|
+
int UtilReadPNG(FILE* in_file, struct WebPPicture* const pic, int keep_alpha);
|
16
|
+
|
17
|
+
int UtilWritePNG(FILE* out_file, const WebPDecBuffer* const buffer);
|
18
|
+
int UtilWritePPM(FILE* fout, const WebPDecBuffer* const buffer, int alpha);
|
19
|
+
int UtilWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer);
|
20
|
+
int UtilWritePGM(FILE* fout, const WebPDecBuffer* const buffer);
|
21
|
+
|
22
|
+
#ifdef __cplusplus
|
23
|
+
} // extern "C"
|
24
|
+
#endif
|
@@ -0,0 +1,197 @@
|
|
1
|
+
#include "./tiffdec.h"
|
2
|
+
|
3
|
+
#include <tiffio.h>
|
4
|
+
|
5
|
+
int UtilReadTIFF(const char* const filename,
|
6
|
+
WebPPicture* const pic, int keep_alpha) {
|
7
|
+
TIFF* const tif = TIFFOpen(filename, "r");
|
8
|
+
uint32 width, height;
|
9
|
+
uint32* raster;
|
10
|
+
int ok = 0;
|
11
|
+
int dircount = 1;
|
12
|
+
|
13
|
+
if (tif == NULL) {
|
14
|
+
//fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename);
|
15
|
+
return 0;
|
16
|
+
}
|
17
|
+
|
18
|
+
while (TIFFReadDirectory(tif)) ++dircount;
|
19
|
+
|
20
|
+
if (dircount > 1) {
|
21
|
+
fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n"
|
22
|
+
"Only the first will be used, %d will be ignored.\n",
|
23
|
+
dircount - 1);
|
24
|
+
}
|
25
|
+
|
26
|
+
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
|
27
|
+
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
|
28
|
+
raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster));
|
29
|
+
if (raster != NULL) {
|
30
|
+
if (TIFFReadRGBAImageOriented(tif, width, height, raster,
|
31
|
+
ORIENTATION_TOPLEFT, 1)) {
|
32
|
+
const int stride = width * sizeof(*raster);
|
33
|
+
pic->width = width;
|
34
|
+
pic->height = height;
|
35
|
+
// TIFF data is ABGR
|
36
|
+
#ifdef __BIG_ENDIAN__
|
37
|
+
TIFFSwabArrayOfLong(raster, width * height);
|
38
|
+
#endif
|
39
|
+
ok = keep_alpha
|
40
|
+
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
|
41
|
+
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
|
42
|
+
}
|
43
|
+
_TIFFfree(raster);
|
44
|
+
} else {
|
45
|
+
//fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
|
46
|
+
}
|
47
|
+
|
48
|
+
if (ok && keep_alpha == 2) {
|
49
|
+
WebPCleanupTransparentArea(pic);
|
50
|
+
}
|
51
|
+
|
52
|
+
TIFFClose(tif);
|
53
|
+
return ok;
|
54
|
+
}
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
static void PutLE16(uint8_t* const dst, uint32_t value) {
|
59
|
+
dst[0] = (value >> 0) & 0xff;
|
60
|
+
dst[1] = (value >> 8) & 0xff;
|
61
|
+
}
|
62
|
+
|
63
|
+
static void PutLE32(uint8_t* const dst, uint32_t value) {
|
64
|
+
PutLE16(dst + 0, (value >> 0) & 0xffff);
|
65
|
+
PutLE16(dst + 2, (value >> 16) & 0xffff);
|
66
|
+
}
|
67
|
+
|
68
|
+
|
69
|
+
#define NUM_IFD_ENTRIES 15
|
70
|
+
#define EXTRA_DATA_SIZE 16
|
71
|
+
// 10b for signature/header + n * 12b entries + 4b for IFD terminator:
|
72
|
+
#define EXTRA_DATA_OFFSET (10 + 12 * NUM_IFD_ENTRIES + 4)
|
73
|
+
#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
|
74
|
+
|
75
|
+
int UtilWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
|
76
|
+
const int has_alpha = (buffer->colorspace != MODE_RGB);
|
77
|
+
const uint32_t width = buffer->width;
|
78
|
+
const uint32_t height = buffer->height;
|
79
|
+
const uint8_t* const rgba = buffer->u.RGBA.rgba;
|
80
|
+
const int stride = buffer->u.RGBA.stride;
|
81
|
+
const uint8_t bytes_per_px = has_alpha ? 4 : 3;
|
82
|
+
// For non-alpha case, we omit tag 0x152 (ExtraSamples).
|
83
|
+
const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
|
84
|
+
: NUM_IFD_ENTRIES - 1;
|
85
|
+
uint8_t tiff_header[TIFF_HEADER_SIZE] = {
|
86
|
+
0x49, 0x49, 0x2a, 0x00, // little endian signature
|
87
|
+
8, 0, 0, 0, // offset to the unique IFD that follows
|
88
|
+
// IFD (offset = 8). Entries must be written in increasing tag order.
|
89
|
+
num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each).
|
90
|
+
0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD)
|
91
|
+
0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD)
|
92
|
+
0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888
|
93
|
+
EXTRA_DATA_OFFSET + 0, 0, 0, 0,
|
94
|
+
0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 46: Compression: none
|
95
|
+
0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB
|
96
|
+
0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset:
|
97
|
+
TIFF_HEADER_SIZE, 0, 0, 0, // data follows header
|
98
|
+
0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft
|
99
|
+
0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels
|
100
|
+
bytes_per_px, 0, 0, 0,
|
101
|
+
0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 106: Rows per strip (TBD)
|
102
|
+
0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD)
|
103
|
+
0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution
|
104
|
+
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
|
105
|
+
0x1b, 0x01, 5, 0, 1, 0, 0, 0, // 142: Y-resolution
|
106
|
+
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
|
107
|
+
0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
|
108
|
+
0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
|
109
|
+
0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 178: ExtraSamples: rgbA
|
110
|
+
0, 0, 0, 0, // 190: IFD terminator
|
111
|
+
// EXTRA_DATA_OFFSET:
|
112
|
+
8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
|
113
|
+
72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution
|
114
|
+
};
|
115
|
+
uint32_t y;
|
116
|
+
|
117
|
+
// Fill placeholders in IFD:
|
118
|
+
PutLE32(tiff_header + 10 + 8, width);
|
119
|
+
PutLE32(tiff_header + 22 + 8, height);
|
120
|
+
PutLE32(tiff_header + 106 + 8, height);
|
121
|
+
PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height);
|
122
|
+
if (!has_alpha) PutLE32(tiff_header + 178, 0); // IFD terminator
|
123
|
+
|
124
|
+
// write header
|
125
|
+
if (fwrite(tiff_header, sizeof(tiff_header), 1, fout) != 1) {
|
126
|
+
return 0;
|
127
|
+
}
|
128
|
+
// write pixel values
|
129
|
+
for (y = 0; y < height; ++y) {
|
130
|
+
if (fwrite(rgba + y * stride, bytes_per_px, width, fout) != width) {
|
131
|
+
return 0;
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
return 1;
|
136
|
+
}
|
137
|
+
|
138
|
+
#undef TIFF_HEADER_SIZE
|
139
|
+
#undef EXTRA_DATA_OFFSET
|
140
|
+
#undef EXTRA_DATA_SIZE
|
141
|
+
#undef NUM_IFD_ENTRIES
|
142
|
+
|
143
|
+
#define BMP_HEADER_SIZE 54
|
144
|
+
int UtilWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
145
|
+
const int has_alpha = (buffer->colorspace != MODE_BGR);
|
146
|
+
const uint32_t width = buffer->width;
|
147
|
+
const uint32_t height = buffer->height;
|
148
|
+
const uint8_t* const rgba = buffer->u.RGBA.rgba;
|
149
|
+
const int stride = buffer->u.RGBA.stride;
|
150
|
+
const uint32_t bytes_per_px = has_alpha ? 4 : 3;
|
151
|
+
uint32_t y;
|
152
|
+
const uint32_t line_size = bytes_per_px * width;
|
153
|
+
const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
|
154
|
+
const uint32_t total_size = bmp_stride * height + BMP_HEADER_SIZE;
|
155
|
+
uint8_t bmp_header[BMP_HEADER_SIZE] = { 0 };
|
156
|
+
|
157
|
+
// bitmap file header
|
158
|
+
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
|
159
|
+
PutLE32(bmp_header + 2, total_size); // size including header
|
160
|
+
PutLE32(bmp_header + 6, 0); // reserved
|
161
|
+
PutLE32(bmp_header + 10, BMP_HEADER_SIZE); // offset to pixel array
|
162
|
+
// bitmap info header
|
163
|
+
PutLE32(bmp_header + 14, 40); // DIB header size
|
164
|
+
PutLE32(bmp_header + 18, width); // dimensions
|
165
|
+
PutLE32(bmp_header + 22, -(int)height); // vertical flip!
|
166
|
+
PutLE16(bmp_header + 26, 1); // number of planes
|
167
|
+
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
|
168
|
+
PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
|
169
|
+
PutLE32(bmp_header + 34, 0); // image size (dummy)
|
170
|
+
PutLE32(bmp_header + 38, 2400); // x pixels/meter
|
171
|
+
PutLE32(bmp_header + 42, 2400); // y pixels/meter
|
172
|
+
PutLE32(bmp_header + 46, 0); // number of palette colors
|
173
|
+
PutLE32(bmp_header + 50, 0); // important color count
|
174
|
+
|
175
|
+
// TODO(skal): color profile
|
176
|
+
|
177
|
+
// write header
|
178
|
+
if (fwrite(bmp_header, sizeof(bmp_header), 1, fout) != 1) {
|
179
|
+
return 0;
|
180
|
+
}
|
181
|
+
|
182
|
+
// write pixel array
|
183
|
+
for (y = 0; y < height; ++y) {
|
184
|
+
if (fwrite(rgba + y * stride, line_size, 1, fout) != 1) {
|
185
|
+
return 0;
|
186
|
+
}
|
187
|
+
// write padding zeroes
|
188
|
+
if (bmp_stride != line_size) {
|
189
|
+
const uint8_t zeroes[3] = { 0 };
|
190
|
+
if (fwrite(zeroes, bmp_stride - line_size, 1, fout) != 1) {
|
191
|
+
return 0;
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
195
|
+
return 1;
|
196
|
+
}
|
197
|
+
#undef BMP_HEADER_SIZE
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
#include "webp/encode.h"
|
5
|
+
#include "webp/decode.h"
|
6
|
+
|
7
|
+
#ifdef __cplusplus
|
8
|
+
extern "C" {
|
9
|
+
#endif
|
10
|
+
|
11
|
+
// Reads a TIFF from 'filename', returning the decoded output in 'pic'.
|
12
|
+
// If 'keep_alpha' is true and the TIFF has an alpha channel, the output is RGBA
|
13
|
+
// otherwise it will be RGB.
|
14
|
+
// Returns true on success.
|
15
|
+
int UtilReadTIFF(const char* const filename,
|
16
|
+
struct WebPPicture* const pic, int keep_alpha);
|
17
|
+
|
18
|
+
int UtilWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer);
|
19
|
+
int UtilWriteBMP(FILE* fout, const WebPDecBuffer* const buffer);
|
20
|
+
|
21
|
+
#ifdef __cplusplus
|
22
|
+
} // extern "C"
|
23
|
+
#endif
|
data/ext/webp_ffi/util.c
CHANGED
@@ -1,15 +1,11 @@
|
|
1
|
-
#include "./util.h"
|
2
|
-
#include <assert.h>
|
3
1
|
#include <stdio.h>
|
4
2
|
#include <stdlib.h>
|
5
3
|
#include <string.h>
|
6
4
|
|
7
|
-
#include
|
8
|
-
|
9
|
-
#include
|
10
|
-
#include
|
11
|
-
|
12
|
-
#include <tiffio.h>
|
5
|
+
#include "./util.h"
|
6
|
+
#include "./jpegdec.h"
|
7
|
+
#include "./pngdec.h"
|
8
|
+
#include "./tiffdec.h"
|
13
9
|
|
14
10
|
#include "webp/decode.h"
|
15
11
|
#include "webp/encode.h"
|
@@ -48,468 +44,6 @@ static int UtilReadYUV(FILE* in_file, WebPPicture* const pic) {
|
|
48
44
|
return ok;
|
49
45
|
}
|
50
46
|
|
51
|
-
struct my_error_mgr {
|
52
|
-
struct jpeg_error_mgr pub;
|
53
|
-
jmp_buf setjmp_buffer;
|
54
|
-
};
|
55
|
-
|
56
|
-
static void my_error_exit(j_common_ptr dinfo) {
|
57
|
-
struct my_error_mgr* myerr = (struct my_error_mgr*) dinfo->err;
|
58
|
-
(*dinfo->err->output_message) (dinfo);
|
59
|
-
longjmp(myerr->setjmp_buffer, 1);
|
60
|
-
}
|
61
|
-
|
62
|
-
static int UtilReadJPEG(FILE* in_file, WebPPicture* const pic) {
|
63
|
-
int ok = 0;
|
64
|
-
int stride, width, height;
|
65
|
-
uint8_t* rgb = NULL;
|
66
|
-
struct jpeg_decompress_struct dinfo;
|
67
|
-
struct my_error_mgr jerr;
|
68
|
-
JSAMPROW buffer[1];
|
69
|
-
|
70
|
-
dinfo.err = jpeg_std_error(&jerr.pub);
|
71
|
-
jerr.pub.error_exit = my_error_exit;
|
72
|
-
|
73
|
-
if (setjmp(jerr.setjmp_buffer)) {
|
74
|
-
Error:
|
75
|
-
jpeg_destroy_decompress(&dinfo);
|
76
|
-
goto End;
|
77
|
-
}
|
78
|
-
|
79
|
-
jpeg_create_decompress(&dinfo);
|
80
|
-
jpeg_stdio_src(&dinfo, in_file);
|
81
|
-
jpeg_read_header(&dinfo, TRUE);
|
82
|
-
|
83
|
-
dinfo.out_color_space = JCS_RGB;
|
84
|
-
dinfo.do_fancy_upsampling = TRUE;
|
85
|
-
|
86
|
-
jpeg_start_decompress(&dinfo);
|
87
|
-
|
88
|
-
if (dinfo.output_components != 3) {
|
89
|
-
goto Error;
|
90
|
-
}
|
91
|
-
|
92
|
-
width = dinfo.output_width;
|
93
|
-
height = dinfo.output_height;
|
94
|
-
stride = dinfo.output_width * dinfo.output_components * sizeof(*rgb);
|
95
|
-
|
96
|
-
rgb = (uint8_t*)malloc(stride * height);
|
97
|
-
if (rgb == NULL) {
|
98
|
-
goto End;
|
99
|
-
}
|
100
|
-
buffer[0] = (JSAMPLE*)rgb;
|
101
|
-
|
102
|
-
while (dinfo.output_scanline < dinfo.output_height) {
|
103
|
-
if (jpeg_read_scanlines(&dinfo, buffer, 1) != 1) {
|
104
|
-
goto End;
|
105
|
-
}
|
106
|
-
buffer[0] += stride;
|
107
|
-
}
|
108
|
-
|
109
|
-
jpeg_finish_decompress(&dinfo);
|
110
|
-
jpeg_destroy_decompress(&dinfo);
|
111
|
-
|
112
|
-
// WebP conversion.
|
113
|
-
pic->width = width;
|
114
|
-
pic->height = height;
|
115
|
-
ok = WebPPictureImportRGB(pic, rgb, stride);
|
116
|
-
if (!ok) goto Error;
|
117
|
-
|
118
|
-
End:
|
119
|
-
free(rgb);
|
120
|
-
return ok;
|
121
|
-
}
|
122
|
-
|
123
|
-
static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
|
124
|
-
(void)dummy; // remove variable-unused warning
|
125
|
-
longjmp(png_jmpbuf(png), 1);
|
126
|
-
}
|
127
|
-
|
128
|
-
static int UtilReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
|
129
|
-
png_structp png;
|
130
|
-
png_infop info = NULL;
|
131
|
-
png_infop end_info = NULL;
|
132
|
-
int color_type, bit_depth, interlaced;
|
133
|
-
int has_alpha;
|
134
|
-
int num_passes;
|
135
|
-
int p;
|
136
|
-
int ok = 0;
|
137
|
-
png_uint_32 width, height, y;
|
138
|
-
int stride;
|
139
|
-
uint8_t* rgb = NULL;
|
140
|
-
|
141
|
-
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
142
|
-
if (png == NULL) {
|
143
|
-
goto End;
|
144
|
-
}
|
145
|
-
|
146
|
-
png_set_error_fn(png, 0, error_function, NULL);
|
147
|
-
if (setjmp(png_jmpbuf(png))) {
|
148
|
-
Error:
|
149
|
-
png_destroy_read_struct(&png, &info, &end_info);
|
150
|
-
goto End;
|
151
|
-
}
|
152
|
-
|
153
|
-
info = png_create_info_struct(png);
|
154
|
-
if (info == NULL) goto Error;
|
155
|
-
end_info = png_create_info_struct(png);
|
156
|
-
if (end_info == NULL) goto Error;
|
157
|
-
|
158
|
-
png_init_io(png, in_file);
|
159
|
-
png_read_info(png, info);
|
160
|
-
if (!png_get_IHDR(png, info,
|
161
|
-
&width, &height, &bit_depth, &color_type, &interlaced,
|
162
|
-
NULL, NULL)) goto Error;
|
163
|
-
|
164
|
-
png_set_strip_16(png);
|
165
|
-
png_set_packing(png);
|
166
|
-
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
|
167
|
-
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
168
|
-
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
169
|
-
if (bit_depth < 8) {
|
170
|
-
png_set_expand_gray_1_2_4_to_8(png);
|
171
|
-
}
|
172
|
-
png_set_gray_to_rgb(png);
|
173
|
-
}
|
174
|
-
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
|
175
|
-
png_set_tRNS_to_alpha(png);
|
176
|
-
has_alpha = 1;
|
177
|
-
} else {
|
178
|
-
has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
|
179
|
-
}
|
180
|
-
|
181
|
-
if (!keep_alpha) {
|
182
|
-
png_set_strip_alpha(png);
|
183
|
-
has_alpha = 0;
|
184
|
-
}
|
185
|
-
|
186
|
-
num_passes = png_set_interlace_handling(png);
|
187
|
-
png_read_update_info(png, info);
|
188
|
-
stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
|
189
|
-
rgb = (uint8_t*)malloc(stride * height);
|
190
|
-
if (rgb == NULL) goto Error;
|
191
|
-
for (p = 0; p < num_passes; ++p) {
|
192
|
-
for (y = 0; y < height; ++y) {
|
193
|
-
png_bytep row = rgb + y * stride;
|
194
|
-
png_read_rows(png, &row, NULL, 1);
|
195
|
-
}
|
196
|
-
}
|
197
|
-
png_read_end(png, end_info);
|
198
|
-
png_destroy_read_struct(&png, &info, &end_info);
|
199
|
-
|
200
|
-
pic->width = width;
|
201
|
-
pic->height = height;
|
202
|
-
pic->use_argb = 1;
|
203
|
-
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
|
204
|
-
: WebPPictureImportRGB(pic, rgb, stride);
|
205
|
-
|
206
|
-
if (!ok) {
|
207
|
-
goto Error;
|
208
|
-
}
|
209
|
-
|
210
|
-
End:
|
211
|
-
free(rgb);
|
212
|
-
return ok;
|
213
|
-
}
|
214
|
-
|
215
|
-
static int UtilWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
|
216
|
-
const uint32_t width = buffer->width;
|
217
|
-
const uint32_t height = buffer->height;
|
218
|
-
unsigned char* const rgb = buffer->u.RGBA.rgba;
|
219
|
-
const int stride = buffer->u.RGBA.stride;
|
220
|
-
const int has_alpha = (buffer->colorspace == MODE_RGBA);
|
221
|
-
png_structp png;
|
222
|
-
png_infop info;
|
223
|
-
png_uint_32 y;
|
224
|
-
|
225
|
-
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
226
|
-
NULL, error_function, NULL);
|
227
|
-
if (png == NULL) {
|
228
|
-
return 0;
|
229
|
-
}
|
230
|
-
info = png_create_info_struct(png);
|
231
|
-
if (info == NULL) {
|
232
|
-
png_destroy_write_struct(&png, NULL);
|
233
|
-
return 0;
|
234
|
-
}
|
235
|
-
if (setjmp(png_jmpbuf(png))) {
|
236
|
-
png_destroy_write_struct(&png, &info);
|
237
|
-
return 0;
|
238
|
-
}
|
239
|
-
png_init_io(png, out_file);
|
240
|
-
png_set_IHDR(png, info, width, height, 8,
|
241
|
-
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
|
242
|
-
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
243
|
-
PNG_FILTER_TYPE_DEFAULT);
|
244
|
-
png_write_info(png, info);
|
245
|
-
for (y = 0; y < height; ++y) {
|
246
|
-
png_bytep row = rgb + y * stride;
|
247
|
-
png_write_rows(png, &row, 1);
|
248
|
-
}
|
249
|
-
png_write_end(png, info);
|
250
|
-
png_destroy_write_struct(&png, &info);
|
251
|
-
return 1;
|
252
|
-
}
|
253
|
-
|
254
|
-
static int UtilWritePPM(FILE* fout, const WebPDecBuffer* const buffer, int alpha) {
|
255
|
-
const uint32_t width = buffer->width;
|
256
|
-
const uint32_t height = buffer->height;
|
257
|
-
const unsigned char* const rgb = buffer->u.RGBA.rgba;
|
258
|
-
const int stride = buffer->u.RGBA.stride;
|
259
|
-
const size_t bytes_per_px = alpha ? 4 : 3;
|
260
|
-
uint32_t y;
|
261
|
-
|
262
|
-
if (alpha) {
|
263
|
-
fprintf(fout, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\n"
|
264
|
-
"TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
|
265
|
-
} else {
|
266
|
-
fprintf(fout, "P6\n%d %d\n255\n", width, height);
|
267
|
-
}
|
268
|
-
for (y = 0; y < height; ++y) {
|
269
|
-
if (fwrite(rgb + y * stride, width, bytes_per_px, fout) != bytes_per_px) {
|
270
|
-
return 0;
|
271
|
-
}
|
272
|
-
}
|
273
|
-
return 1;
|
274
|
-
}
|
275
|
-
|
276
|
-
static void PutLE16(uint8_t* const dst, uint32_t value) {
|
277
|
-
dst[0] = (value >> 0) & 0xff;
|
278
|
-
dst[1] = (value >> 8) & 0xff;
|
279
|
-
}
|
280
|
-
|
281
|
-
static void PutLE32(uint8_t* const dst, uint32_t value) {
|
282
|
-
PutLE16(dst + 0, (value >> 0) & 0xffff);
|
283
|
-
PutLE16(dst + 2, (value >> 16) & 0xffff);
|
284
|
-
}
|
285
|
-
|
286
|
-
#define BMP_HEADER_SIZE 54
|
287
|
-
static int UtilWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
288
|
-
const int has_alpha = (buffer->colorspace != MODE_BGR);
|
289
|
-
const uint32_t width = buffer->width;
|
290
|
-
const uint32_t height = buffer->height;
|
291
|
-
const uint8_t* const rgba = buffer->u.RGBA.rgba;
|
292
|
-
const int stride = buffer->u.RGBA.stride;
|
293
|
-
const uint32_t bytes_per_px = has_alpha ? 4 : 3;
|
294
|
-
uint32_t y;
|
295
|
-
const uint32_t line_size = bytes_per_px * width;
|
296
|
-
const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
|
297
|
-
const uint32_t total_size = bmp_stride * height + BMP_HEADER_SIZE;
|
298
|
-
uint8_t bmp_header[BMP_HEADER_SIZE] = { 0 };
|
299
|
-
|
300
|
-
// bitmap file header
|
301
|
-
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
|
302
|
-
PutLE32(bmp_header + 2, total_size); // size including header
|
303
|
-
PutLE32(bmp_header + 6, 0); // reserved
|
304
|
-
PutLE32(bmp_header + 10, BMP_HEADER_SIZE); // offset to pixel array
|
305
|
-
// bitmap info header
|
306
|
-
PutLE32(bmp_header + 14, 40); // DIB header size
|
307
|
-
PutLE32(bmp_header + 18, width); // dimensions
|
308
|
-
PutLE32(bmp_header + 22, -(int)height); // vertical flip!
|
309
|
-
PutLE16(bmp_header + 26, 1); // number of planes
|
310
|
-
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
|
311
|
-
PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
|
312
|
-
PutLE32(bmp_header + 34, 0); // image size (dummy)
|
313
|
-
PutLE32(bmp_header + 38, 2400); // x pixels/meter
|
314
|
-
PutLE32(bmp_header + 42, 2400); // y pixels/meter
|
315
|
-
PutLE32(bmp_header + 46, 0); // number of palette colors
|
316
|
-
PutLE32(bmp_header + 50, 0); // important color count
|
317
|
-
|
318
|
-
// TODO(skal): color profile
|
319
|
-
|
320
|
-
// write header
|
321
|
-
if (fwrite(bmp_header, sizeof(bmp_header), 1, fout) != 1) {
|
322
|
-
return 0;
|
323
|
-
}
|
324
|
-
|
325
|
-
// write pixel array
|
326
|
-
for (y = 0; y < height; ++y) {
|
327
|
-
if (fwrite(rgba + y * stride, line_size, 1, fout) != 1) {
|
328
|
-
return 0;
|
329
|
-
}
|
330
|
-
// write padding zeroes
|
331
|
-
if (bmp_stride != line_size) {
|
332
|
-
const uint8_t zeroes[3] = { 0 };
|
333
|
-
if (fwrite(zeroes, bmp_stride - line_size, 1, fout) != 1) {
|
334
|
-
return 0;
|
335
|
-
}
|
336
|
-
}
|
337
|
-
}
|
338
|
-
return 1;
|
339
|
-
}
|
340
|
-
#undef BMP_HEADER_SIZE
|
341
|
-
|
342
|
-
#define NUM_IFD_ENTRIES 15
|
343
|
-
#define EXTRA_DATA_SIZE 16
|
344
|
-
// 10b for signature/header + n * 12b entries + 4b for IFD terminator:
|
345
|
-
#define EXTRA_DATA_OFFSET (10 + 12 * NUM_IFD_ENTRIES + 4)
|
346
|
-
#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
|
347
|
-
|
348
|
-
static int UtilWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
|
349
|
-
const int has_alpha = (buffer->colorspace != MODE_RGB);
|
350
|
-
const uint32_t width = buffer->width;
|
351
|
-
const uint32_t height = buffer->height;
|
352
|
-
const uint8_t* const rgba = buffer->u.RGBA.rgba;
|
353
|
-
const int stride = buffer->u.RGBA.stride;
|
354
|
-
const uint8_t bytes_per_px = has_alpha ? 4 : 3;
|
355
|
-
// For non-alpha case, we omit tag 0x152 (ExtraSamples).
|
356
|
-
const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
|
357
|
-
: NUM_IFD_ENTRIES - 1;
|
358
|
-
uint8_t tiff_header[TIFF_HEADER_SIZE] = {
|
359
|
-
0x49, 0x49, 0x2a, 0x00, // little endian signature
|
360
|
-
8, 0, 0, 0, // offset to the unique IFD that follows
|
361
|
-
// IFD (offset = 8). Entries must be written in increasing tag order.
|
362
|
-
num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each).
|
363
|
-
0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD)
|
364
|
-
0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD)
|
365
|
-
0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888
|
366
|
-
EXTRA_DATA_OFFSET + 0, 0, 0, 0,
|
367
|
-
0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 46: Compression: none
|
368
|
-
0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB
|
369
|
-
0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset:
|
370
|
-
TIFF_HEADER_SIZE, 0, 0, 0, // data follows header
|
371
|
-
0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft
|
372
|
-
0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels
|
373
|
-
bytes_per_px, 0, 0, 0,
|
374
|
-
0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 106: Rows per strip (TBD)
|
375
|
-
0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD)
|
376
|
-
0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution
|
377
|
-
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
|
378
|
-
0x1b, 0x01, 5, 0, 1, 0, 0, 0, // 142: Y-resolution
|
379
|
-
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
|
380
|
-
0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
|
381
|
-
0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
|
382
|
-
0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 178: ExtraSamples: rgbA
|
383
|
-
0, 0, 0, 0, // 190: IFD terminator
|
384
|
-
// EXTRA_DATA_OFFSET:
|
385
|
-
8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
|
386
|
-
72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution
|
387
|
-
};
|
388
|
-
uint32_t y;
|
389
|
-
|
390
|
-
// Fill placeholders in IFD:
|
391
|
-
PutLE32(tiff_header + 10 + 8, width);
|
392
|
-
PutLE32(tiff_header + 22 + 8, height);
|
393
|
-
PutLE32(tiff_header + 106 + 8, height);
|
394
|
-
PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height);
|
395
|
-
if (!has_alpha) PutLE32(tiff_header + 178, 0); // IFD terminator
|
396
|
-
|
397
|
-
// write header
|
398
|
-
if (fwrite(tiff_header, sizeof(tiff_header), 1, fout) != 1) {
|
399
|
-
return 0;
|
400
|
-
}
|
401
|
-
// write pixel values
|
402
|
-
for (y = 0; y < height; ++y) {
|
403
|
-
if (fwrite(rgba + y * stride, bytes_per_px, width, fout) != width) {
|
404
|
-
return 0;
|
405
|
-
}
|
406
|
-
}
|
407
|
-
|
408
|
-
return 1;
|
409
|
-
}
|
410
|
-
|
411
|
-
#undef TIFF_HEADER_SIZE
|
412
|
-
#undef EXTRA_DATA_OFFSET
|
413
|
-
#undef EXTRA_DATA_SIZE
|
414
|
-
#undef NUM_IFD_ENTRIES
|
415
|
-
|
416
|
-
static int UtilWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
|
417
|
-
const uint32_t width = buffer->width;
|
418
|
-
const uint32_t height = buffer->height;
|
419
|
-
const unsigned char* const a = buffer->u.YUVA.a;
|
420
|
-
const int a_stride = buffer->u.YUVA.a_stride;
|
421
|
-
uint32_t y;
|
422
|
-
assert(a != NULL);
|
423
|
-
fprintf(fout, "P5\n%d %d\n255\n", width, height);
|
424
|
-
for (y = 0; y < height; ++y) {
|
425
|
-
if (fwrite(a + y * a_stride, width, 1, fout) != 1) {
|
426
|
-
return 0;
|
427
|
-
}
|
428
|
-
}
|
429
|
-
return 1;
|
430
|
-
}
|
431
|
-
|
432
|
-
static int UtilWritePGM(FILE* fout, const WebPDecBuffer* const buffer) {
|
433
|
-
const int width = buffer->width;
|
434
|
-
const int height = buffer->height;
|
435
|
-
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
|
436
|
-
// Save a grayscale PGM file using the IMC4 layout
|
437
|
-
// (http://www.fourcc.org/yuv.php#IMC4). This is a very
|
438
|
-
// convenient format for viewing the samples, esp. for
|
439
|
-
// odd dimensions.
|
440
|
-
int ok = 1;
|
441
|
-
int y;
|
442
|
-
const int uv_width = (width + 1) / 2;
|
443
|
-
const int uv_height = (height + 1) / 2;
|
444
|
-
const int out_stride = (width + 1) & ~1;
|
445
|
-
const int a_height = yuv->a ? height : 0;
|
446
|
-
fprintf(fout, "P5\n%d %d\n255\n", out_stride, height + uv_height + a_height);
|
447
|
-
for (y = 0; ok && y < height; ++y) {
|
448
|
-
ok &= (fwrite(yuv->y + y * yuv->y_stride, width, 1, fout) == 1);
|
449
|
-
if (width & 1) fputc(0, fout); // padding byte
|
450
|
-
}
|
451
|
-
for (y = 0; ok && y < uv_height; ++y) {
|
452
|
-
ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
|
453
|
-
ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
|
454
|
-
}
|
455
|
-
for (y = 0; ok && y < a_height; ++y) {
|
456
|
-
ok &= (fwrite(yuv->a + y * yuv->a_stride, width, 1, fout) == 1);
|
457
|
-
if (width & 1) fputc(0, fout); // padding byte
|
458
|
-
}
|
459
|
-
return ok;
|
460
|
-
}
|
461
|
-
|
462
|
-
static int UtilReadTIFF(const char* const filename,
|
463
|
-
WebPPicture* const pic, int keep_alpha) {
|
464
|
-
TIFF* const tif = TIFFOpen(filename, "r");
|
465
|
-
uint32 width, height;
|
466
|
-
uint32* raster;
|
467
|
-
int ok = 0;
|
468
|
-
int dircount = 1;
|
469
|
-
|
470
|
-
if (tif == NULL) {
|
471
|
-
//fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename);
|
472
|
-
return 0;
|
473
|
-
}
|
474
|
-
|
475
|
-
while (TIFFReadDirectory(tif)) ++dircount;
|
476
|
-
|
477
|
-
if (dircount > 1) {
|
478
|
-
fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n"
|
479
|
-
"Only the first will be used, %d will be ignored.\n",
|
480
|
-
dircount - 1);
|
481
|
-
}
|
482
|
-
|
483
|
-
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
|
484
|
-
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
|
485
|
-
raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster));
|
486
|
-
if (raster != NULL) {
|
487
|
-
if (TIFFReadRGBAImageOriented(tif, width, height, raster,
|
488
|
-
ORIENTATION_TOPLEFT, 1)) {
|
489
|
-
const int stride = width * sizeof(*raster);
|
490
|
-
pic->width = width;
|
491
|
-
pic->height = height;
|
492
|
-
// TIFF data is ABGR
|
493
|
-
#ifdef __BIG_ENDIAN__
|
494
|
-
TIFFSwabArrayOfLong(raster, width * height);
|
495
|
-
#endif
|
496
|
-
ok = keep_alpha
|
497
|
-
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
|
498
|
-
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
|
499
|
-
}
|
500
|
-
_TIFFfree(raster);
|
501
|
-
} else {
|
502
|
-
//fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
|
503
|
-
}
|
504
|
-
|
505
|
-
if (ok && keep_alpha == 2) {
|
506
|
-
WebPCleanupTransparentArea(pic);
|
507
|
-
}
|
508
|
-
|
509
|
-
TIFFClose(tif);
|
510
|
-
return ok;
|
511
|
-
}
|
512
|
-
|
513
47
|
static InputFileFormat GetImageType(FILE* in_file) {
|
514
48
|
InputFileFormat format = UNSUPPORTED;
|
515
49
|
unsigned int magic;
|
data/lib/webp/version.rb
CHANGED
data/spec/webp_ffi_spec.rb
CHANGED
@@ -79,21 +79,21 @@ describe WebP do
|
|
79
79
|
it "#{image}.png image" do
|
80
80
|
in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.png"))
|
81
81
|
out_filename = File.expand_path(File.join(@out_dir, "#{image}.png.webp"))
|
82
|
-
expect(WebP.encode(in_filename, out_filename)).to
|
82
|
+
expect(WebP.encode(in_filename, out_filename)).to be_truthy
|
83
83
|
end
|
84
84
|
end
|
85
85
|
factories[:jpg].each do |image|
|
86
86
|
it "#{image}.jpg image" do
|
87
87
|
in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.jpg"))
|
88
88
|
out_filename = File.expand_path(File.join(@out_dir, "#{image}.jpg.webp"))
|
89
|
-
expect(WebP.encode(in_filename, out_filename)).to
|
89
|
+
expect(WebP.encode(in_filename, out_filename)).to be_truthy
|
90
90
|
end
|
91
91
|
end
|
92
92
|
factories[:tiff].each do |image|
|
93
93
|
it "#{image}.tif image" do
|
94
94
|
in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.tif"))
|
95
95
|
out_filename = File.expand_path(File.join(@out_dir, "#{image}.tif.webp"))
|
96
|
-
expect(WebP.encode(in_filename, out_filename)).to
|
96
|
+
expect(WebP.encode(in_filename, out_filename)).to be_truthy
|
97
97
|
end
|
98
98
|
end
|
99
99
|
factories[:webp].each do |image|
|
@@ -128,7 +128,7 @@ describe WebP do
|
|
128
128
|
it "#{image}.webp image" do
|
129
129
|
in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.webp"))
|
130
130
|
out_filename = File.expand_path(File.join(@out_dir, "#{image}.webp.png"))
|
131
|
-
expect(WebP.decode(in_filename, out_filename)).to
|
131
|
+
expect(WebP.decode(in_filename, out_filename)).to be_truthy
|
132
132
|
end
|
133
133
|
end
|
134
134
|
context "with output_format" do
|
@@ -137,7 +137,7 @@ describe WebP do
|
|
137
137
|
it "#{image}.webp image to #{output_format}" do
|
138
138
|
in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.webp"))
|
139
139
|
out_filename = File.expand_path(File.join(@out_dir, "#{image}.#{output_format}.png"))
|
140
|
-
expect(WebP.decode(in_filename, out_filename, output_format: output_format)).to
|
140
|
+
expect(WebP.decode(in_filename, out_filename, output_format: output_format)).to be_truthy
|
141
141
|
end
|
142
142
|
end
|
143
143
|
end
|
@@ -147,12 +147,12 @@ describe WebP do
|
|
147
147
|
it "#{image}.webp image to png and crop" do
|
148
148
|
in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.webp"))
|
149
149
|
out_filename = File.expand_path(File.join(@out_dir, "#{image}_crop.png"))
|
150
|
-
expect(WebP.decode(in_filename, out_filename, crop_w: 200, crop_h: 200)).to
|
150
|
+
expect(WebP.decode(in_filename, out_filename, crop_w: 200, crop_h: 200)).to be_truthy
|
151
151
|
end
|
152
152
|
it "#{image}.webp image to png and scale" do
|
153
153
|
in_filename = File.expand_path(File.join(File.dirname(__FILE__), "factories/#{image}.webp"))
|
154
154
|
out_filename = File.expand_path(File.join(@out_dir, "#{image}_resize.png"))
|
155
|
-
expect(WebP.decode(in_filename, out_filename, resize_w: 200, resize_h: 200)).to
|
155
|
+
expect(WebP.decode(in_filename, out_filename, resize_w: 200, resize_h: 200)).to be_truthy
|
156
156
|
end
|
157
157
|
end
|
158
158
|
end
|
data/webp-ffi.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webp-ffi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Vasyliev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: '3'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: '3'
|
83
83
|
description: Ruby wrapper for libwebp
|
84
84
|
email:
|
85
85
|
- leopard.not.a@gmail.com
|
@@ -97,6 +97,12 @@ files:
|
|
97
97
|
- README.md
|
98
98
|
- Rakefile
|
99
99
|
- ext/webp_ffi/Rakefile
|
100
|
+
- ext/webp_ffi/jpegdec.c
|
101
|
+
- ext/webp_ffi/jpegdec.h
|
102
|
+
- ext/webp_ffi/pngdec.c
|
103
|
+
- ext/webp_ffi/pngdec.h
|
104
|
+
- ext/webp_ffi/tiffdec.c
|
105
|
+
- ext/webp_ffi/tiffdec.h
|
100
106
|
- ext/webp_ffi/util.c
|
101
107
|
- ext/webp_ffi/util.h
|
102
108
|
- ext/webp_ffi/webp_ffi.c
|
@@ -143,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
149
|
version: '0'
|
144
150
|
requirements: []
|
145
151
|
rubyforge_project:
|
146
|
-
rubygems_version: 2.2.
|
152
|
+
rubygems_version: 2.2.2
|
147
153
|
signing_key:
|
148
154
|
specification_version: 4
|
149
155
|
summary: Ruby wrapper for libwebp
|