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.
@@ -0,0 +1,361 @@
1
+ #include "./tiffdec.h"
2
+ #include "./util.h"
3
+
4
+ #include <stdarg.h>
5
+ #include <sys/types.h>
6
+ #include <tiffio.h>
7
+ #include <tiffvers.h>
8
+
9
+ // libtiff 4.5.0 added error and warning handlers per opened file.
10
+ #if defined(TIFFLIB_AT_LEAST)
11
+ #if TIFFLIB_AT_LEAST(4, 5, 0)
12
+ #define UTIL_TIFF_HAS_OPEN_OPTIONS
13
+ #endif
14
+ #endif
15
+
16
+ #ifdef UTIL_TIFF_HAS_OPEN_OPTIONS
17
+ // libtiff prints errors and warnings to stderr by default. A library should
18
+ // stay quiet. Returning 1 also stops libtiff from calling its global handlers.
19
+ static int SilentTIFFHandler(TIFF* tif, void* user_data, const char* module,
20
+ const char* fmt, va_list ap) {
21
+ (void)tif;
22
+ (void)user_data;
23
+ (void)module;
24
+ (void)fmt;
25
+ (void)ap;
26
+ return 1;
27
+ }
28
+ #endif
29
+
30
+ // libtiff reads through these callbacks, so the same code works for files and
31
+ // for in-memory data opened with fmemopen.
32
+ static tmsize_t UtilTIFFRead(thandle_t handle, void* buffer, tmsize_t size) {
33
+ if (size <= 0) return 0;
34
+ return (tmsize_t)fread(buffer, 1, (size_t)size, (FILE*)handle);
35
+ }
36
+
37
+ static tmsize_t UtilTIFFWrite(thandle_t handle, void* buffer, tmsize_t size) {
38
+ (void)handle;
39
+ (void)buffer;
40
+ (void)size;
41
+ return 0; // read only
42
+ }
43
+
44
+ static toff_t UtilTIFFSeek(thandle_t handle, toff_t offset, int whence) {
45
+ FILE* const file = (FILE*)handle;
46
+ if (fseeko(file, (off_t)offset, whence) != 0) return (toff_t)-1;
47
+ return (toff_t)ftello(file);
48
+ }
49
+
50
+ static int UtilTIFFClose(thandle_t handle) {
51
+ (void)handle;
52
+ return 0; // the caller closes the file
53
+ }
54
+
55
+ static toff_t UtilTIFFSize(thandle_t handle) {
56
+ FILE* const file = (FILE*)handle;
57
+ const off_t position = ftello(file);
58
+ off_t size;
59
+ if (position < 0 || fseeko(file, 0, SEEK_END) != 0) return 0;
60
+ size = ftello(file);
61
+ fseeko(file, position, SEEK_SET);
62
+ return size < 0 ? 0 : (toff_t)size;
63
+ }
64
+
65
+ static int UtilTIFFMap(thandle_t handle, void** base, toff_t* size) {
66
+ (void)handle;
67
+ (void)base;
68
+ (void)size;
69
+ return 0; // no memory mapping
70
+ }
71
+
72
+ static void UtilTIFFUnmap(thandle_t handle, void* base, toff_t size) {
73
+ (void)handle;
74
+ (void)base;
75
+ (void)size;
76
+ }
77
+
78
+ // "m" turns off memory mapping, which a FILE* can't provide
79
+ static TIFF* OpenTIFF(FILE* const file) {
80
+ #ifdef UTIL_TIFF_HAS_OPEN_OPTIONS
81
+ TIFF* tif;
82
+ TIFFOpenOptions* const opts = TIFFOpenOptionsAlloc();
83
+ if (opts == NULL) return NULL;
84
+ TIFFOpenOptionsSetErrorHandlerExtR(opts, SilentTIFFHandler, NULL);
85
+ TIFFOpenOptionsSetWarningHandlerExtR(opts, SilentTIFFHandler, NULL);
86
+ tif = TIFFClientOpenExt("webp-ffi", "rm", (thandle_t)file,
87
+ UtilTIFFRead, UtilTIFFWrite, UtilTIFFSeek, UtilTIFFClose,
88
+ UtilTIFFSize, UtilTIFFMap, UtilTIFFUnmap, opts);
89
+ TIFFOpenOptionsFree(opts);
90
+ return tif;
91
+ #else
92
+ // Older libtiff only has process-wide handlers. Changing those would affect
93
+ // other code in the same process, so its messages still reach stderr.
94
+ return TIFFClientOpen("webp-ffi", "rm", (thandle_t)file,
95
+ UtilTIFFRead, UtilTIFFWrite, UtilTIFFSeek, UtilTIFFClose,
96
+ UtilTIFFSize, UtilTIFFMap, UtilTIFFUnmap);
97
+ #endif
98
+ }
99
+
100
+ const char* UtilTIFFVersion(void) {
101
+ return TIFFGetVersion();
102
+ }
103
+
104
+ // libtiff's RGBA interface always returns premultiplied (associated) alpha,
105
+ // whatever kind of alpha the file stores, so undo the multiplication.
106
+ // Based on MultARGBRow in libwebp's imageio/tiffdec.c (taken from libwebp's
107
+ // dsp/alpha_processing).
108
+ #define MFIX 24 // 24bit fixed-point arithmetic
109
+ #define HALF ((1u << MFIX) >> 1)
110
+
111
+ static uint32_t Unmult(uint8_t x, uint32_t mult) {
112
+ const uint32_t v = (x * mult + HALF) >> MFIX;
113
+ return (v > 255u) ? 255u : v;
114
+ }
115
+
116
+ static uint32_t GetScale(uint32_t a) {
117
+ return (255u << MFIX) / a;
118
+ }
119
+
120
+ #undef MFIX
121
+ #undef HALF
122
+
123
+ static void UnmultiplyRow(uint8_t* ptr, uint32_t width) {
124
+ uint32_t x;
125
+ for (x = 0; x < width; ++x, ptr += 4) {
126
+ const uint32_t alpha = ptr[3];
127
+ if (alpha < 255) {
128
+ if (alpha == 0) {
129
+ ptr[0] = ptr[1] = ptr[2] = 0;
130
+ } else {
131
+ const uint32_t scale = GetScale(alpha);
132
+ ptr[0] = (uint8_t)Unmult(ptr[0], scale);
133
+ ptr[1] = (uint8_t)Unmult(ptr[1], scale);
134
+ ptr[2] = (uint8_t)Unmult(ptr[2], scale);
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ // True when the first extra sample is alpha, associated or not.
141
+ static int HasAlphaSample(TIFF* const tif) {
142
+ uint16_t count = 0;
143
+ uint16_t* samples = NULL;
144
+ return TIFFGetField(tif, TIFFTAG_EXTRASAMPLES, &count, &samples) && count > 0 &&
145
+ samples != NULL && (samples[0] == EXTRASAMPLE_ASSOCALPHA ||
146
+ samples[0] == EXTRASAMPLE_UNASSALPHA);
147
+ }
148
+
149
+ static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) {
150
+ uint32_t length = 0;
151
+ void* data = NULL;
152
+ if (TIFFGetField(tif, TIFFTAG_ICCPROFILE, &length, &data) &&
153
+ !MetadataCopy(data, length, &metadata->iccp)) {
154
+ return 0;
155
+ }
156
+ length = 0;
157
+ data = NULL;
158
+ if (TIFFGetField(tif, TIFFTAG_XMLPACKET, &length, &data) &&
159
+ !MetadataCopy(data, length, &metadata->xmp)) {
160
+ return 0;
161
+ }
162
+ return 1;
163
+ }
164
+
165
+ int UtilReadTIFF(FILE* const in_file,
166
+ WebPPicture* const pic, int keep_alpha,
167
+ Metadata* const metadata) {
168
+ TIFF* const tif = OpenTIFF(in_file);
169
+ uint32_t width, height;
170
+ uint32_t* raster;
171
+ int stride;
172
+ size_t raster_size;
173
+ int ok = 0;
174
+
175
+ if (tif == NULL) {
176
+ return 0;
177
+ }
178
+
179
+ // Multi-page TIFF files are not supported: only the first page is used.
180
+ if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) ||
181
+ !TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height) ||
182
+ !UtilCheckImageSize(width, height, sizeof(*raster),
183
+ &stride, &raster_size) ||
184
+ (metadata != NULL && !ExtractMetadataFromTIFF(tif, metadata))) {
185
+ TIFFClose(tif);
186
+ return 0;
187
+ }
188
+
189
+ raster = (uint32_t*)_TIFFmalloc(raster_size);
190
+ if (raster != NULL) {
191
+ if (TIFFReadRGBAImageOriented(tif, width, height, raster,
192
+ ORIENTATION_TOPLEFT, 1)) {
193
+ pic->width = (int)width;
194
+ pic->height = (int)height;
195
+ // TIFF data is ABGR
196
+ #ifdef __BIG_ENDIAN__
197
+ TIFFSwabArrayOfLong(raster, raster_size / sizeof(*raster));
198
+ #endif
199
+ if (keep_alpha && HasAlphaSample(tif)) {
200
+ uint32_t y;
201
+ for (y = 0; y < height; ++y) {
202
+ UnmultiplyRow((uint8_t*)raster + (size_t)y * stride, width);
203
+ }
204
+ }
205
+ ok = keep_alpha
206
+ ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
207
+ : WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
208
+ }
209
+ _TIFFfree(raster);
210
+ }
211
+
212
+ if (ok && keep_alpha == 2) {
213
+ WebPCleanupTransparentArea(pic);
214
+ }
215
+
216
+ TIFFClose(tif);
217
+ return ok;
218
+ }
219
+
220
+
221
+
222
+ static void PutLE16(uint8_t* const dst, uint32_t value) {
223
+ dst[0] = (value >> 0) & 0xff;
224
+ dst[1] = (value >> 8) & 0xff;
225
+ }
226
+
227
+ static void PutLE32(uint8_t* const dst, uint32_t value) {
228
+ PutLE16(dst + 0, (value >> 0) & 0xffff);
229
+ PutLE16(dst + 2, (value >> 16) & 0xffff);
230
+ }
231
+
232
+
233
+ #define NUM_IFD_ENTRIES 15
234
+ #define EXTRA_DATA_SIZE 16
235
+ // 10b for signature/header + n * 12b entries + 4b for IFD terminator:
236
+ #define EXTRA_DATA_OFFSET (10 + 12 * NUM_IFD_ENTRIES + 4)
237
+ #define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
238
+
239
+ int UtilWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
240
+ const int has_alpha = (buffer->colorspace != MODE_RGB);
241
+ const uint32_t width = buffer->width;
242
+ const uint32_t height = buffer->height;
243
+ const uint8_t* const rgba = buffer->u.RGBA.rgba;
244
+ const int stride = buffer->u.RGBA.stride;
245
+ const uint8_t bytes_per_px = has_alpha ? 4 : 3;
246
+ // For non-alpha case, we omit tag 0x152 (ExtraSamples).
247
+ const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
248
+ : NUM_IFD_ENTRIES - 1;
249
+ uint8_t tiff_header[TIFF_HEADER_SIZE] = {
250
+ 0x49, 0x49, 0x2a, 0x00, // little endian signature
251
+ 8, 0, 0, 0, // offset to the unique IFD that follows
252
+ // IFD (offset = 8). Entries must be written in increasing tag order.
253
+ num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each).
254
+ 0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD)
255
+ 0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD)
256
+ 0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888
257
+ EXTRA_DATA_OFFSET + 0, 0, 0, 0,
258
+ 0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 46: Compression: none
259
+ 0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB
260
+ 0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset:
261
+ TIFF_HEADER_SIZE, 0, 0, 0, // data follows header
262
+ 0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft
263
+ 0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels
264
+ bytes_per_px, 0, 0, 0,
265
+ 0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 106: Rows per strip (TBD)
266
+ 0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD)
267
+ 0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution
268
+ EXTRA_DATA_OFFSET + 8, 0, 0, 0,
269
+ 0x1b, 0x01, 5, 0, 1, 0, 0, 0, // 142: Y-resolution
270
+ EXTRA_DATA_OFFSET + 8, 0, 0, 0,
271
+ 0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
272
+ 0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
273
+ 0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 178: ExtraSamples: rgbA
274
+ 0, 0, 0, 0, // 190: IFD terminator
275
+ // EXTRA_DATA_OFFSET:
276
+ 8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
277
+ 72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution
278
+ };
279
+ uint32_t y;
280
+
281
+ // Fill placeholders in IFD:
282
+ PutLE32(tiff_header + 10 + 8, width);
283
+ PutLE32(tiff_header + 22 + 8, height);
284
+ PutLE32(tiff_header + 106 + 8, height);
285
+ PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height);
286
+ if (!has_alpha) PutLE32(tiff_header + 178, 0); // IFD terminator
287
+
288
+ // write header
289
+ if (fwrite(tiff_header, sizeof(tiff_header), 1, fout) != 1) {
290
+ return 0;
291
+ }
292
+ // write pixel values
293
+ for (y = 0; y < height; ++y) {
294
+ if (fwrite(rgba + y * stride, bytes_per_px, width, fout) != width) {
295
+ return 0;
296
+ }
297
+ }
298
+
299
+ return 1;
300
+ }
301
+
302
+ #undef TIFF_HEADER_SIZE
303
+ #undef EXTRA_DATA_OFFSET
304
+ #undef EXTRA_DATA_SIZE
305
+ #undef NUM_IFD_ENTRIES
306
+
307
+ #define BMP_HEADER_SIZE 54
308
+ int UtilWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
309
+ const int has_alpha = (buffer->colorspace != MODE_BGR);
310
+ const uint32_t width = buffer->width;
311
+ const uint32_t height = buffer->height;
312
+ const uint8_t* const rgba = buffer->u.RGBA.rgba;
313
+ const int stride = buffer->u.RGBA.stride;
314
+ const uint32_t bytes_per_px = has_alpha ? 4 : 3;
315
+ uint32_t y;
316
+ const uint32_t line_size = bytes_per_px * width;
317
+ const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
318
+ const uint32_t total_size = bmp_stride * height + BMP_HEADER_SIZE;
319
+ uint8_t bmp_header[BMP_HEADER_SIZE] = { 0 };
320
+
321
+ // bitmap file header
322
+ PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
323
+ PutLE32(bmp_header + 2, total_size); // size including header
324
+ PutLE32(bmp_header + 6, 0); // reserved
325
+ PutLE32(bmp_header + 10, BMP_HEADER_SIZE); // offset to pixel array
326
+ // bitmap info header
327
+ PutLE32(bmp_header + 14, 40); // DIB header size
328
+ PutLE32(bmp_header + 18, width); // dimensions
329
+ PutLE32(bmp_header + 22, -(int)height); // vertical flip!
330
+ PutLE16(bmp_header + 26, 1); // number of planes
331
+ PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
332
+ PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
333
+ PutLE32(bmp_header + 34, 0); // image size (dummy)
334
+ PutLE32(bmp_header + 38, 2400); // x pixels/meter
335
+ PutLE32(bmp_header + 42, 2400); // y pixels/meter
336
+ PutLE32(bmp_header + 46, 0); // number of palette colors
337
+ PutLE32(bmp_header + 50, 0); // important color count
338
+
339
+ // TODO(skal): color profile
340
+
341
+ // write header
342
+ if (fwrite(bmp_header, sizeof(bmp_header), 1, fout) != 1) {
343
+ return 0;
344
+ }
345
+
346
+ // write pixel array
347
+ for (y = 0; y < height; ++y) {
348
+ if (fwrite(rgba + y * stride, line_size, 1, fout) != 1) {
349
+ return 0;
350
+ }
351
+ // write padding zeroes
352
+ if (bmp_stride != line_size) {
353
+ const uint8_t zeroes[3] = { 0 };
354
+ if (fwrite(zeroes, bmp_stride - line_size, 1, fout) != 1) {
355
+ return 0;
356
+ }
357
+ }
358
+ }
359
+ return 1;
360
+ }
361
+ #undef BMP_HEADER_SIZE
@@ -0,0 +1,31 @@
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 TIFF from 'in_file', returning the decoded output in 'pic'.
13
+ // If 'keep_alpha' is true and the TIFF has an alpha channel, the output is RGBA
14
+ // otherwise it will be RGB. 'in_file' must be seekable and stays open.
15
+ // When 'metadata' is not NULL, the ICC profile and XMP data are copied into it.
16
+ // Like libwebp's own reader, EXIF is not read from TIFF files.
17
+ // Returns true on success.
18
+ int UtilReadTIFF(FILE* const in_file,
19
+ struct WebPPicture* const pic, int keep_alpha,
20
+ Metadata* const metadata);
21
+
22
+ int UtilWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer);
23
+ int UtilWriteBMP(FILE* fout, const WebPDecBuffer* const buffer);
24
+
25
+ // Version string of the libtiff in use. Prebuilt gems keep the bundled
26
+ // libtiff symbols private, so the specs ask through this function.
27
+ const char* UtilTIFFVersion(void);
28
+
29
+ #ifdef __cplusplus
30
+ } // extern "C"
31
+ #endif
@@ -0,0 +1,216 @@
1
+ #include <limits.h>
2
+ #include <sys/stat.h>
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <string.h>
6
+
7
+ #include "./util.h"
8
+ #include "./jpegdec.h"
9
+ #include "./pngdec.h"
10
+ #include "./tiffdec.h"
11
+
12
+ #include "webp/decode.h"
13
+ #include "webp/encode.h"
14
+
15
+ #if defined(__cplusplus) || defined(c_plusplus)
16
+ extern "C" {
17
+ #endif
18
+
19
+ // Same memory cap as the image readers in libwebp (imageio/imageio_util.c).
20
+ #if SIZE_MAX > (1ULL << 34)
21
+ #define UTIL_MAX_ALLOCABLE_MEMORY (1ULL << 34)
22
+ #else
23
+ #define UTIL_MAX_ALLOCABLE_MEMORY ((1ULL << 31) - (1 << 16))
24
+ #endif
25
+ #define UTIL_MAX_BYTES_PER_PIXEL 8
26
+
27
+ int UtilCheckImageSize(uint64_t width, uint64_t height, uint64_t bytes_per_px,
28
+ int* const stride, size_t* const size) {
29
+ uint64_t row_size, total_size;
30
+
31
+ if (width == 0 || height == 0) return 0;
32
+ if (bytes_per_px == 0 || bytes_per_px > UTIL_MAX_BYTES_PER_PIXEL) return 0;
33
+ // WebPPicture and the row strides passed to libwebp are plain ints.
34
+ if (width > INT_MAX || height > INT_MAX) return 0;
35
+
36
+ // Both products stay far below 2^64 because of the limits checked above.
37
+ row_size = width * bytes_per_px;
38
+ if (row_size > INT_MAX) return 0;
39
+ total_size = row_size * height;
40
+ if (total_size > UTIL_MAX_ALLOCABLE_MEMORY) return 0;
41
+
42
+ if (stride != NULL) *stride = (int)row_size;
43
+ if (size != NULL) *size = (size_t)total_size;
44
+ return 1;
45
+ }
46
+
47
+ static int UtilReadYUV(FILE* in_file, WebPPicture* const pic) {
48
+ const int use_argb = pic->use_argb;
49
+ const int uv_width = (pic->width + 1) / 2;
50
+ const int uv_height = (pic->height + 1) / 2;
51
+ int y;
52
+ int ok = 0;
53
+
54
+ pic->use_argb = 0;
55
+ if (!WebPPictureAlloc(pic)) return ok;
56
+
57
+ for (y = 0; y < pic->height; ++y) {
58
+ if (fread(pic->y + y * pic->y_stride, pic->width, 1, in_file) != 1) {
59
+ goto End;
60
+ }
61
+ }
62
+ for (y = 0; y < uv_height; ++y) {
63
+ if (fread(pic->u + y * pic->uv_stride, uv_width, 1, in_file) != 1)
64
+ goto End;
65
+ }
66
+ for (y = 0; y < uv_height; ++y) {
67
+ if (fread(pic->v + y * pic->uv_stride, uv_width, 1, in_file) != 1)
68
+ goto End;
69
+ }
70
+ ok = 1;
71
+ if (use_argb) ok = WebPPictureYUVAToARGB(pic);
72
+
73
+ End:
74
+ return ok;
75
+ }
76
+
77
+ static InputFileFormat GetImageType(FILE* in_file) {
78
+ InputFileFormat format = UNSUPPORTED;
79
+ unsigned int magic;
80
+ unsigned char buf[4];
81
+
82
+ if ((fread(&buf[0], 4, 1, in_file) != 1) ||
83
+ (fseek(in_file, 0, SEEK_SET) != 0)) {
84
+ return format;
85
+ }
86
+
87
+ // shift unsigned values: buf[0] << 24 as an int overflows for bytes >= 0x80
88
+ magic = ((unsigned int)buf[0] << 24) | ((unsigned int)buf[1] << 16) |
89
+ ((unsigned int)buf[2] << 8) | buf[3];
90
+ if (magic == 0x89504E47U) {
91
+ format = iPNG_;
92
+ } else if (magic >= 0xFFD8FF00U && magic <= 0xFFD8FFFFU) {
93
+ format = iJPEG_;
94
+ } else if (magic == 0x49492A00 || magic == 0x4D4D002A) {
95
+ format = iTIFF_;
96
+ }
97
+ return format;
98
+ }
99
+
100
+ int UtilReadPictureFile(FILE* const in_file, WebPPicture* const pic,
101
+ int keep_alpha, Metadata* const metadata) {
102
+ int ok = 0;
103
+
104
+ if (pic->width == 0 || pic->height == 0) {
105
+ // If no size specified, try to decode it as PNG/JPEG/TIFF (as appropriate).
106
+ const InputFileFormat format = GetImageType(in_file);
107
+ if (format == iPNG_) {
108
+ ok = UtilReadPNG(in_file, pic, keep_alpha, metadata);
109
+ } else if (format == iJPEG_) {
110
+ ok = UtilReadJPEG(in_file, pic, metadata);
111
+ } else if (format == iTIFF_) {
112
+ ok = UtilReadTIFF(in_file, pic, keep_alpha, metadata);
113
+ }
114
+ } else {
115
+ // If image size is specified, infer it as YUV format.
116
+ ok = UtilReadYUV(in_file, pic);
117
+ }
118
+ return ok;
119
+ }
120
+
121
+ int UtilFileExists(const char* const path) {
122
+ struct stat info;
123
+ return stat(path, &info) == 0;
124
+ }
125
+
126
+ int UtilSaveOutput(const WebPDecBuffer* const buffer,
127
+ OutputFileFormat format, const char* const out_file) {
128
+ // a failed write removes the file, but only when this call created it
129
+ const int existed = UtilFileExists(out_file);
130
+ int ok;
131
+ FILE* const fout = fopen(out_file, "wb");
132
+ if (!fout) {
133
+ return 0;
134
+ }
135
+ ok = UtilWriteOutput(buffer, format, fout);
136
+ // fclose flushes buffered data, so it can also fail (for example, disk full)
137
+ if (fclose(fout) != 0) {
138
+ ok = 0;
139
+ }
140
+ if (!ok && !existed) remove(out_file);
141
+ return ok;
142
+ }
143
+
144
+ int UtilWriteOutput(const WebPDecBuffer* const buffer,
145
+ OutputFileFormat format, FILE* const fout) {
146
+ int ok = 1;
147
+
148
+ if (format == oPNG) {
149
+ ok &= UtilWritePNG(fout, buffer);
150
+ } else if (format == oPAM) {
151
+ ok &= UtilWritePPM(fout, buffer, 1);
152
+ } else if (format == oPPM) {
153
+ ok &= UtilWritePPM(fout, buffer, 0);
154
+ } else if (format == oBMP) {
155
+ ok &= UtilWriteBMP(fout, buffer);
156
+ } else if (format == oTIFF_) {
157
+ ok &= UtilWriteTIFF(fout, buffer);
158
+ } else if (format == oPGM) {
159
+ ok &= UtilWritePGM(fout, buffer);
160
+ } else if (format == oYUV) {
161
+ ok &= UtilWriteYUV(fout, buffer);
162
+ } else if (format == ALPHA_PLANE_ONLY) {
163
+ ok &= UtilWriteAlphaPlane(fout, buffer);
164
+ } else {
165
+ ok = 0;
166
+ }
167
+ return ok;
168
+ }
169
+
170
+ // -----------------------------------------------------------------------------
171
+ // File I/O
172
+
173
+ int UtilReadFile(const char* const file_name,
174
+ const uint8_t** data, size_t* data_size) {
175
+ int ok;
176
+ void* file_data;
177
+ long file_size;
178
+ struct stat info;
179
+ FILE* in;
180
+
181
+ if (file_name == NULL || data == NULL || data_size == NULL) return 0;
182
+ *data = NULL;
183
+ *data_size = 0;
184
+
185
+ in = fopen(file_name, "rb");
186
+ if (in == NULL) {
187
+ return 0;
188
+ }
189
+ // only regular files: on Linux a folder opens and reports a huge size
190
+ if (fstat(fileno(in), &info) != 0 || !S_ISREG(info.st_mode) ||
191
+ fseek(in, 0, SEEK_END) != 0 ||
192
+ (file_size = ftell(in)) <= 0 ||
193
+ fseek(in, 0, SEEK_SET) != 0) {
194
+ fclose(in);
195
+ return 0;
196
+ }
197
+ file_data = malloc((size_t)file_size);
198
+ if (file_data == NULL) {
199
+ fclose(in);
200
+ return 0;
201
+ }
202
+ ok = (fread(file_data, (size_t)file_size, 1, in) == 1);
203
+ fclose(in);
204
+
205
+ if (!ok) {
206
+ free(file_data);
207
+ return 0;
208
+ }
209
+ *data = (uint8_t*)file_data;
210
+ *data_size = (size_t)file_size;
211
+ return 1;
212
+ }
213
+
214
+ #if defined(__cplusplus) || defined(c_plusplus)
215
+ } // extern "C"
216
+ #endif
@@ -0,0 +1,63 @@
1
+ #ifndef _WEBP_FFI_UTIL_H_
2
+ #define _WEBP_FFI_UTIL_H_
3
+
4
+ #include <stddef.h>
5
+ #include <stdint.h>
6
+ #include <stdio.h>
7
+
8
+ #include "webp/decode.h"
9
+ #include "webp/encode.h"
10
+ #include "./metadata.h"
11
+
12
+ #if defined(__cplusplus) || defined(c_plusplus)
13
+ extern "C" {
14
+ #endif
15
+
16
+ typedef enum {
17
+ oPNG = 0,
18
+ oPAM,
19
+ oPPM,
20
+ oPGM,
21
+ oBMP,
22
+ oTIFF_,
23
+ oYUV,
24
+ ALPHA_PLANE_ONLY // this is for experimenting only
25
+ } OutputFileFormat;
26
+
27
+ typedef enum {
28
+ iPNG_ = 0,
29
+ iJPEG_,
30
+ iTIFF_, // 'TIFF' clashes with libtiff
31
+ UNSUPPORTED
32
+ } InputFileFormat;
33
+
34
+ // Writes 'buffer' to 'out_file'. When writing fails, a file this call created
35
+ // is removed again. Returns 1 on success.
36
+ int UtilSaveOutput(const WebPDecBuffer* const buffer, OutputFileFormat format, const char* const out_file);
37
+ int UtilFileExists(const char* const path);
38
+ // Writes 'buffer' in 'format' to an open file. Returns 1 on success.
39
+ int UtilWriteOutput(const WebPDecBuffer* const buffer, OutputFileFormat format, FILE* const fout);
40
+ // Allocates storage for entire file 'file_name' and returns contents and size
41
+ // in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
42
+ // be deleted using free().
43
+ int UtilReadFile(const char* const file_name,
44
+ const uint8_t** data, size_t* data_size);
45
+
46
+ // Reads a PNG, JPEG or TIFF picture from an open file (or raw YUV when the
47
+ // picture already has a size). When 'metadata' is not NULL, the picture's
48
+ // metadata is copied into it. Returns 1 on success.
49
+ int UtilReadPictureFile(FILE* const in_file, WebPPicture* const pic,
50
+ int keep_alpha, Metadata* const metadata);
51
+
52
+ // Checks that a 'width' x 'height' image with 'bytes_per_px' bytes per pixel
53
+ // fits in memory, using 64-bit math so the size can't wrap around.
54
+ // Returns 1 on success and stores the row size in 'stride' and the buffer size
55
+ // in 'size' (either pointer may be NULL). Returns 0 for empty or oversized images.
56
+ int UtilCheckImageSize(uint64_t width, uint64_t height, uint64_t bytes_per_px,
57
+ int* const stride, size_t* const size);
58
+
59
+ #if defined(__cplusplus) || defined(c_plusplus)
60
+ } // extern "C"
61
+ #endif
62
+
63
+ #endif /* _WEBP_FFI_UTIL_H_ */