webp-ffi 1.0.0-x86_64-linux-gnu
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +135 -0
- data/LICENSE.txt +22 -0
- data/README.md +308 -0
- data/ext/webp_ffi/Rakefile +3 -0
- data/ext/webp_ffi/build_config.rb +119 -0
- data/ext/webp_ffi/jpegdec.c +174 -0
- data/ext/webp_ffi/jpegdec.h +20 -0
- data/ext/webp_ffi/metadata.c +138 -0
- data/ext/webp_ffi/metadata.h +49 -0
- data/ext/webp_ffi/pngdec.c +389 -0
- data/ext/webp_ffi/pngdec.h +29 -0
- data/ext/webp_ffi/tiffdec.c +361 -0
- data/ext/webp_ffi/tiffdec.h +31 -0
- data/ext/webp_ffi/util.c +216 -0
- data/ext/webp_ffi/util.h +63 -0
- data/ext/webp_ffi/webp_ffi.c +618 -0
- data/ext/webp_ffi/webp_ffi.h +110 -0
- data/ext/webp_ffi/x86_64-linux/libwebp_ffi.so +0 -0
- data/ext/webp_ffi/x86_64-linux/licenses/libjpeg-turbo-LICENSE.md +147 -0
- data/ext/webp_ffi/x86_64-linux/licenses/libjpeg-turbo-README.ijg +260 -0
- data/ext/webp_ffi/x86_64-linux/licenses/libpng-LICENSE +134 -0
- data/ext/webp_ffi/x86_64-linux/licenses/libtiff-LICENSE.md +49 -0
- data/ext/webp_ffi/x86_64-linux/licenses/libwebp-COPYING +30 -0
- data/ext/webp_ffi/x86_64-linux/licenses/libwebp-PATENTS +23 -0
- data/ext/webp_ffi/x86_64-linux/licenses/zlib-LICENSE +22 -0
- data/ext/webp_ffi/x86_64-linux/versions.txt +5 -0
- data/lib/webp/c.rb +101 -0
- data/lib/webp/error.rb +71 -0
- data/lib/webp/info.rb +13 -0
- data/lib/webp/options.rb +171 -0
- data/lib/webp/version.rb +3 -0
- data/lib/webp/webp.rb +179 -0
- data/lib/webp-ffi.rb +1 -0
- data/lib/webp_ffi.rb +16 -0
- data/sig/webp.rbs +74 -0
- metadata +145 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
#include "./pngdec.h"
|
|
2
|
+
#include "./util.h"
|
|
3
|
+
|
|
4
|
+
#include <assert.h>
|
|
5
|
+
#include <stdio.h>
|
|
6
|
+
#include <png.h>
|
|
7
|
+
#include <setjmp.h> // note: this must be included *after* png.h
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
|
|
11
|
+
static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
|
|
12
|
+
(void)dummy; // remove variable-unused warning
|
|
13
|
+
longjmp(png_jmpbuf(png), 1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// libpng prints warnings to stderr by default. A library should stay quiet.
|
|
17
|
+
static void PNGAPI warning_function(png_structp png, png_const_charp dummy) {
|
|
18
|
+
(void)png;
|
|
19
|
+
(void)dummy;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// The metadata code below is based on libwebp's imageio/pngdec.c.
|
|
23
|
+
|
|
24
|
+
// Converts pairs of hex digits, possibly split by newlines, to 'length' bytes.
|
|
25
|
+
// Returns NULL for other characters or when there are fewer bytes.
|
|
26
|
+
static uint8_t* HexStringToBytes(const char* hexstring, size_t length) {
|
|
27
|
+
const char* src = hexstring;
|
|
28
|
+
size_t actual_length = 0;
|
|
29
|
+
uint8_t* const raw_data = (uint8_t*)malloc(length > 0 ? length : 1);
|
|
30
|
+
uint8_t* dst;
|
|
31
|
+
|
|
32
|
+
if (raw_data == NULL) return NULL;
|
|
33
|
+
for (dst = raw_data; actual_length < length && *src != '\0'; ++src) {
|
|
34
|
+
char* end;
|
|
35
|
+
char value[3];
|
|
36
|
+
if (*src == '\n') continue;
|
|
37
|
+
value[0] = *src++;
|
|
38
|
+
value[1] = *src;
|
|
39
|
+
value[2] = '\0';
|
|
40
|
+
*dst++ = (uint8_t)strtol(value, &end, 16);
|
|
41
|
+
if (end != value + 2) break;
|
|
42
|
+
++actual_length;
|
|
43
|
+
}
|
|
44
|
+
if (actual_length != length) {
|
|
45
|
+
free(raw_data);
|
|
46
|
+
return NULL;
|
|
47
|
+
}
|
|
48
|
+
return raw_data;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ImageMagick and ExifTool store metadata in text chunks as "raw profiles":
|
|
52
|
+
// "\n<name>\n<length>\n<hex data>\n".
|
|
53
|
+
static int ProcessRawProfile(const char* profile, size_t profile_length,
|
|
54
|
+
MetadataPayload* const payload) {
|
|
55
|
+
const char* src = profile;
|
|
56
|
+
char* end;
|
|
57
|
+
long length;
|
|
58
|
+
|
|
59
|
+
if (profile == NULL || profile_length == 0 || *src != '\n') return 0;
|
|
60
|
+
++src;
|
|
61
|
+
while (*src != '\0' && *src++ != '\n') {} // skip the profile name
|
|
62
|
+
length = strtol(src, &end, 10);
|
|
63
|
+
if (*end != '\n') return 0;
|
|
64
|
+
++end;
|
|
65
|
+
// two hex digits per byte, so a longer length cannot be right
|
|
66
|
+
if (length < 0 || (size_t)length > profile_length / 2) return 0;
|
|
67
|
+
payload->bytes = HexStringToBytes(end, (size_t)length);
|
|
68
|
+
if (payload->bytes == NULL) return 0;
|
|
69
|
+
payload->size = (size_t)length;
|
|
70
|
+
return 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static int CopyText(const char* text, size_t length, MetadataPayload* const payload) {
|
|
74
|
+
return MetadataCopy(text, length, payload);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static const struct {
|
|
78
|
+
const char* key;
|
|
79
|
+
int (*process)(const char* text, size_t length, MetadataPayload* const payload);
|
|
80
|
+
int kind; // METADATA_* flag
|
|
81
|
+
} kPNGTextMetadata[] = {
|
|
82
|
+
// https://exiftool.org/TagNames/PNG.html#TextualData
|
|
83
|
+
{ "Raw profile type exif", ProcessRawProfile, METADATA_EXIF },
|
|
84
|
+
{ "Raw profile type xmp", ProcessRawProfile, METADATA_XMP },
|
|
85
|
+
// ExifTool puts EXIF data in an APP1 profile too; ImageMagick in "app1".
|
|
86
|
+
{ "Raw profile type APP1", ProcessRawProfile, METADATA_EXIF },
|
|
87
|
+
{ "Raw profile type app1", ProcessRawProfile, METADATA_EXIF },
|
|
88
|
+
// XMP Specification Part 3, Section 3 #PNG
|
|
89
|
+
{ "XML:com.adobe.xmp", CopyText, METADATA_XMP },
|
|
90
|
+
{ NULL, NULL, 0 }
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Looks for metadata before and after the image data, preferring what comes
|
|
94
|
+
// first. Like libwebp, an eXIf chunk wins over EXIF in text chunks.
|
|
95
|
+
static int ExtractMetadataFromPNG(png_structp png, png_infop info,
|
|
96
|
+
png_infop end_info, Metadata* const metadata) {
|
|
97
|
+
int p;
|
|
98
|
+
for (p = 0; p < 2; ++p) {
|
|
99
|
+
png_infop const head = (p == 0) ? info : end_info;
|
|
100
|
+
png_textp text = NULL;
|
|
101
|
+
const png_uint_32 count = png_get_text(png, head, &text, NULL);
|
|
102
|
+
png_uint_32 i;
|
|
103
|
+
|
|
104
|
+
#ifdef PNG_eXIf_SUPPORTED
|
|
105
|
+
{
|
|
106
|
+
png_bytep exif = NULL;
|
|
107
|
+
png_uint_32 length = 0;
|
|
108
|
+
if (png_get_eXIf_1(png, head, &length, &exif) == PNG_INFO_eXIf &&
|
|
109
|
+
!MetadataCopy(exif, length, &metadata->exif)) {
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
#endif
|
|
114
|
+
|
|
115
|
+
for (i = 0; i < count; ++i, ++text) {
|
|
116
|
+
int j;
|
|
117
|
+
for (j = 0; kPNGTextMetadata[j].key != NULL; ++j) {
|
|
118
|
+
if (text->key != NULL && !strcmp(text->key, kPNGTextMetadata[j].key)) {
|
|
119
|
+
MetadataPayload* const payload =
|
|
120
|
+
(kPNGTextMetadata[j].kind == METADATA_EXIF) ? &metadata->exif : &metadata->xmp;
|
|
121
|
+
// iTXt chunks keep their length in a separate field
|
|
122
|
+
const size_t length = (text->compression == PNG_ITXT_COMPRESSION_NONE ||
|
|
123
|
+
text->compression == PNG_ITXT_COMPRESSION_zTXt)
|
|
124
|
+
? text->itxt_length : text->text_length;
|
|
125
|
+
// the first one wins; like cwebp, a broken one fails the read
|
|
126
|
+
if (payload->bytes == NULL &&
|
|
127
|
+
!kPNGTextMetadata[j].process(text->text, length, payload)) {
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
{
|
|
136
|
+
png_charp name;
|
|
137
|
+
int compression_type;
|
|
138
|
+
png_bytep profile;
|
|
139
|
+
png_uint_32 length;
|
|
140
|
+
if (png_get_iCCP(png, head, &name, &compression_type, &profile, &length) == PNG_INFO_iCCP &&
|
|
141
|
+
!MetadataCopy(profile, length, &metadata->iccp)) {
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
int UtilReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha,
|
|
150
|
+
Metadata* const metadata) {
|
|
151
|
+
// Locals that change after setjmp() must be volatile, otherwise their values
|
|
152
|
+
// are undefined when libpng jumps back to the error handler.
|
|
153
|
+
volatile png_structp png = NULL;
|
|
154
|
+
volatile png_infop info = NULL;
|
|
155
|
+
volatile png_infop end_info = NULL;
|
|
156
|
+
int color_type, bit_depth, interlaced;
|
|
157
|
+
int has_alpha;
|
|
158
|
+
int num_passes;
|
|
159
|
+
int p;
|
|
160
|
+
int ok = 0;
|
|
161
|
+
png_uint_32 width, height, y;
|
|
162
|
+
int stride;
|
|
163
|
+
size_t rgb_size;
|
|
164
|
+
uint8_t* volatile rgb = NULL;
|
|
165
|
+
|
|
166
|
+
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
167
|
+
if (png == NULL) {
|
|
168
|
+
goto End;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
png_set_error_fn(png, NULL, error_function, warning_function);
|
|
172
|
+
if (setjmp(png_jmpbuf(png))) {
|
|
173
|
+
Error:
|
|
174
|
+
png_destroy_read_struct((png_structpp)&png, (png_infopp)&info,
|
|
175
|
+
(png_infopp)&end_info);
|
|
176
|
+
goto End;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
info = png_create_info_struct(png);
|
|
180
|
+
if (info == NULL) goto Error;
|
|
181
|
+
end_info = png_create_info_struct(png);
|
|
182
|
+
if (end_info == NULL) goto Error;
|
|
183
|
+
|
|
184
|
+
png_init_io(png, in_file);
|
|
185
|
+
png_read_info(png, info);
|
|
186
|
+
if (!png_get_IHDR(png, info,
|
|
187
|
+
&width, &height, &bit_depth, &color_type, &interlaced,
|
|
188
|
+
NULL, NULL)) goto Error;
|
|
189
|
+
|
|
190
|
+
png_set_strip_16(png);
|
|
191
|
+
png_set_packing(png);
|
|
192
|
+
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
|
|
193
|
+
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
|
194
|
+
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
|
195
|
+
if (bit_depth < 8) {
|
|
196
|
+
png_set_expand_gray_1_2_4_to_8(png);
|
|
197
|
+
}
|
|
198
|
+
png_set_gray_to_rgb(png);
|
|
199
|
+
}
|
|
200
|
+
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
|
|
201
|
+
png_set_tRNS_to_alpha(png);
|
|
202
|
+
has_alpha = 1;
|
|
203
|
+
} else {
|
|
204
|
+
has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!keep_alpha) {
|
|
208
|
+
png_set_strip_alpha(png);
|
|
209
|
+
has_alpha = 0;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
num_passes = png_set_interlace_handling(png);
|
|
213
|
+
png_read_update_info(png, info);
|
|
214
|
+
if (!UtilCheckImageSize(width, height, has_alpha ? 4 : 3,
|
|
215
|
+
&stride, &rgb_size)) {
|
|
216
|
+
goto Error;
|
|
217
|
+
}
|
|
218
|
+
rgb = (uint8_t*)malloc(rgb_size);
|
|
219
|
+
if (rgb == NULL) goto Error;
|
|
220
|
+
for (p = 0; p < num_passes; ++p) {
|
|
221
|
+
for (y = 0; y < height; ++y) {
|
|
222
|
+
png_bytep row = rgb + (size_t)y * stride;
|
|
223
|
+
png_read_rows(png, &row, NULL, 1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
png_read_end(png, end_info);
|
|
227
|
+
if (metadata != NULL && !ExtractMetadataFromPNG(png, info, end_info, metadata)) {
|
|
228
|
+
goto Error;
|
|
229
|
+
}
|
|
230
|
+
png_destroy_read_struct((png_structpp)&png, (png_infopp)&info,
|
|
231
|
+
(png_infopp)&end_info);
|
|
232
|
+
|
|
233
|
+
pic->width = (int)width;
|
|
234
|
+
pic->height = (int)height;
|
|
235
|
+
pic->use_argb = 1;
|
|
236
|
+
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
|
|
237
|
+
: WebPPictureImportRGB(pic, rgb, stride);
|
|
238
|
+
|
|
239
|
+
End:
|
|
240
|
+
free(rgb);
|
|
241
|
+
return ok;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
int UtilWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
|
|
249
|
+
const uint32_t width = buffer->width;
|
|
250
|
+
const uint32_t height = buffer->height;
|
|
251
|
+
unsigned char* const rgb = buffer->u.RGBA.rgba;
|
|
252
|
+
const int stride = buffer->u.RGBA.stride;
|
|
253
|
+
const int has_alpha = (buffer->colorspace == MODE_RGBA);
|
|
254
|
+
png_structp png;
|
|
255
|
+
png_infop info;
|
|
256
|
+
png_uint_32 y;
|
|
257
|
+
|
|
258
|
+
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
|
259
|
+
NULL, error_function, warning_function);
|
|
260
|
+
if (png == NULL) {
|
|
261
|
+
return 0;
|
|
262
|
+
}
|
|
263
|
+
info = png_create_info_struct(png);
|
|
264
|
+
if (info == NULL) {
|
|
265
|
+
png_destroy_write_struct(&png, NULL);
|
|
266
|
+
return 0;
|
|
267
|
+
}
|
|
268
|
+
if (setjmp(png_jmpbuf(png))) {
|
|
269
|
+
png_destroy_write_struct(&png, &info);
|
|
270
|
+
return 0;
|
|
271
|
+
}
|
|
272
|
+
png_init_io(png, out_file);
|
|
273
|
+
png_set_IHDR(png, info, width, height, 8,
|
|
274
|
+
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
|
|
275
|
+
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
|
276
|
+
PNG_FILTER_TYPE_DEFAULT);
|
|
277
|
+
png_write_info(png, info);
|
|
278
|
+
for (y = 0; y < height; ++y) {
|
|
279
|
+
png_bytep row = rgb + y * stride;
|
|
280
|
+
png_write_rows(png, &row, 1);
|
|
281
|
+
}
|
|
282
|
+
png_write_end(png, info);
|
|
283
|
+
png_destroy_write_struct(&png, &info);
|
|
284
|
+
return 1;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
int UtilWritePPM(FILE* fout, const WebPDecBuffer* const buffer, int alpha) {
|
|
289
|
+
const uint32_t width = buffer->width;
|
|
290
|
+
const uint32_t height = buffer->height;
|
|
291
|
+
const unsigned char* const rgb = buffer->u.RGBA.rgba;
|
|
292
|
+
const int stride = buffer->u.RGBA.stride;
|
|
293
|
+
const size_t bytes_per_px = alpha ? 4 : 3;
|
|
294
|
+
uint32_t y;
|
|
295
|
+
|
|
296
|
+
if (alpha) {
|
|
297
|
+
fprintf(fout, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\n"
|
|
298
|
+
"TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
|
|
299
|
+
} else {
|
|
300
|
+
fprintf(fout, "P6\n%d %d\n255\n", width, height);
|
|
301
|
+
}
|
|
302
|
+
for (y = 0; y < height; ++y) {
|
|
303
|
+
if (fwrite(rgb + y * stride, width, bytes_per_px, fout) != bytes_per_px) {
|
|
304
|
+
return 0;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return 1;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
int UtilWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
|
|
311
|
+
const uint32_t width = buffer->width;
|
|
312
|
+
const uint32_t height = buffer->height;
|
|
313
|
+
const unsigned char* const a = buffer->u.YUVA.a;
|
|
314
|
+
const int a_stride = buffer->u.YUVA.a_stride;
|
|
315
|
+
uint32_t y;
|
|
316
|
+
assert(a != NULL);
|
|
317
|
+
fprintf(fout, "P5\n%d %d\n255\n", width, height);
|
|
318
|
+
for (y = 0; y < height; ++y) {
|
|
319
|
+
if (fwrite(a + y * a_stride, width, 1, fout) != 1) {
|
|
320
|
+
return 0;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return 1;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
int UtilWritePGM(FILE* fout, const WebPDecBuffer* const buffer) {
|
|
327
|
+
const int width = buffer->width;
|
|
328
|
+
const int height = buffer->height;
|
|
329
|
+
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
|
|
330
|
+
// Save a grayscale PGM file using the IMC4 layout
|
|
331
|
+
// (http://www.fourcc.org/yuv.php#IMC4). This is a very
|
|
332
|
+
// convenient format for viewing the samples, esp. for
|
|
333
|
+
// odd dimensions.
|
|
334
|
+
int ok = 1;
|
|
335
|
+
int y;
|
|
336
|
+
const int uv_width = (width + 1) / 2;
|
|
337
|
+
const int uv_height = (height + 1) / 2;
|
|
338
|
+
const int out_stride = (width + 1) & ~1;
|
|
339
|
+
const int a_height = yuv->a ? height : 0;
|
|
340
|
+
fprintf(fout, "P5\n%d %d\n255\n", out_stride, height + uv_height + a_height);
|
|
341
|
+
for (y = 0; ok && y < height; ++y) {
|
|
342
|
+
ok &= (fwrite(yuv->y + y * yuv->y_stride, width, 1, fout) == 1);
|
|
343
|
+
if (width & 1) fputc(0, fout); // padding byte
|
|
344
|
+
}
|
|
345
|
+
for (y = 0; ok && y < uv_height; ++y) {
|
|
346
|
+
ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
|
|
347
|
+
ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
|
|
348
|
+
}
|
|
349
|
+
for (y = 0; ok && y < a_height; ++y) {
|
|
350
|
+
ok &= (fwrite(yuv->a + y * yuv->a_stride, width, 1, fout) == 1);
|
|
351
|
+
if (width & 1) fputc(0, fout); // padding byte
|
|
352
|
+
}
|
|
353
|
+
return ok;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Based on WebPWriteYUV in libwebp's imageio/image_enc.c.
|
|
357
|
+
int UtilWriteYUV(FILE* fout, const WebPDecBuffer* const buffer) {
|
|
358
|
+
const int width = buffer->width;
|
|
359
|
+
const int height = buffer->height;
|
|
360
|
+
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
|
|
361
|
+
const uint8_t* src_y = yuv->y;
|
|
362
|
+
const uint8_t* src_u = yuv->u;
|
|
363
|
+
const uint8_t* src_v = yuv->v;
|
|
364
|
+
const uint8_t* src_a = yuv->a;
|
|
365
|
+
const int uv_width = (width + 1) / 2;
|
|
366
|
+
const int uv_height = (height + 1) / 2;
|
|
367
|
+
const int a_height = (src_a != NULL) ? height : 0;
|
|
368
|
+
int ok = 1;
|
|
369
|
+
int y;
|
|
370
|
+
|
|
371
|
+
if (src_y == NULL || src_u == NULL || src_v == NULL) return 0;
|
|
372
|
+
for (y = 0; ok && y < height; ++y) {
|
|
373
|
+
ok &= (fwrite(src_y, width, 1, fout) == 1);
|
|
374
|
+
src_y += yuv->y_stride;
|
|
375
|
+
}
|
|
376
|
+
for (y = 0; ok && y < uv_height; ++y) {
|
|
377
|
+
ok &= (fwrite(src_u, uv_width, 1, fout) == 1);
|
|
378
|
+
src_u += yuv->u_stride;
|
|
379
|
+
}
|
|
380
|
+
for (y = 0; ok && y < uv_height; ++y) {
|
|
381
|
+
ok &= (fwrite(src_v, uv_width, 1, fout) == 1);
|
|
382
|
+
src_v += yuv->v_stride;
|
|
383
|
+
}
|
|
384
|
+
for (y = 0; ok && y < a_height; ++y) {
|
|
385
|
+
ok &= (fwrite(src_a, width, 1, fout) == 1);
|
|
386
|
+
src_a += yuv->a_stride;
|
|
387
|
+
}
|
|
388
|
+
return ok;
|
|
389
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#include <stdio.h>
|
|
2
|
+
#include <stdlib.h>
|
|
3
|
+
|
|
4
|
+
#include "webp/encode.h"
|
|
5
|
+
#include "webp/decode.h"
|
|
6
|
+
#include "./metadata.h"
|
|
7
|
+
|
|
8
|
+
#ifdef __cplusplus
|
|
9
|
+
extern "C" {
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
// Reads a PNG from 'in_file', returning the decoded output in 'pic'.
|
|
13
|
+
// If 'keep_alpha' is true and the PNG has an alpha channel, the output is RGBA
|
|
14
|
+
// otherwise it will be RGB. When 'metadata' is not NULL, the ICC profile, EXIF
|
|
15
|
+
// and XMP data are copied into it.
|
|
16
|
+
// Returns true on success.
|
|
17
|
+
int UtilReadPNG(FILE* in_file, struct WebPPicture* const pic, int keep_alpha,
|
|
18
|
+
Metadata* const metadata);
|
|
19
|
+
|
|
20
|
+
int UtilWritePNG(FILE* out_file, const WebPDecBuffer* const buffer);
|
|
21
|
+
int UtilWritePPM(FILE* fout, const WebPDecBuffer* const buffer, int alpha);
|
|
22
|
+
int UtilWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer);
|
|
23
|
+
int UtilWritePGM(FILE* fout, const WebPDecBuffer* const buffer);
|
|
24
|
+
// Raw planes: Y, then U and V (half size, rounded up), then alpha if any.
|
|
25
|
+
int UtilWriteYUV(FILE* fout, const WebPDecBuffer* const buffer);
|
|
26
|
+
|
|
27
|
+
#ifdef __cplusplus
|
|
28
|
+
} // extern "C"
|
|
29
|
+
#endif
|