webp-ffi 0.4.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +65 -0
- data/LICENSE.txt +1 -1
- data/README.md +137 -25
- data/ext/webp_ffi/Rakefile +2 -18
- data/ext/webp_ffi/build_config.rb +119 -0
- data/ext/webp_ffi/jpegdec.c +104 -10
- data/ext/webp_ffi/jpegdec.h +5 -2
- data/ext/webp_ffi/metadata.c +138 -0
- data/ext/webp_ffi/metadata.h +49 -0
- data/ext/webp_ffi/pngdec.c +197 -20
- data/ext/webp_ffi/pngdec.h +7 -2
- data/ext/webp_ffi/tiffdec.c +184 -20
- data/ext/webp_ffi/tiffdec.h +12 -4
- data/ext/webp_ffi/util.c +82 -35
- data/ext/webp_ffi/util.h +28 -3
- data/ext/webp_ffi/webp_ffi.c +484 -165
- data/ext/webp_ffi/webp_ffi.h +47 -5
- data/lib/webp/c.rb +41 -7
- data/lib/webp/error.rb +65 -15
- data/lib/webp/info.rb +13 -0
- data/lib/webp/options.rb +129 -22
- data/lib/webp/version.rb +1 -1
- data/lib/webp/webp.rb +150 -32
- data/lib/webp_ffi.rb +1 -1
- data/sig/webp.rbs +74 -0
- metadata +31 -48
- data/.github/workflows/build.yml +0 -45
- data/.gitignore +0 -23
- data/.tool-versions +0 -1
- data/Gemfile +0 -4
- data/Rakefile +0 -38
- data/lib/webp/libc.rb +0 -20
- data/spec/build.sh +0 -6
- data/spec/factories/1.png +0 -0
- data/spec/factories/1.webp +0 -0
- data/spec/factories/2.png +0 -0
- data/spec/factories/2.webp +0 -0
- data/spec/factories/3.jpg +0 -0
- data/spec/factories/3.webp +0 -0
- data/spec/factories/4.jpg +0 -0
- data/spec/factories/4.webp +0 -0
- data/spec/factories/5.tif +0 -0
- data/spec/factories/5.webp +0 -0
- data/spec/spec_helper.rb +0 -9
- data/spec/webp_ffi_spec.rb +0 -191
- data/webp-ffi.gemspec +0 -28
data/ext/webp_ffi/tiffdec.c
CHANGED
|
@@ -1,48 +1,212 @@
|
|
|
1
1
|
#include "./tiffdec.h"
|
|
2
|
+
#include "./util.h"
|
|
2
3
|
|
|
4
|
+
#include <stdarg.h>
|
|
5
|
+
#include <sys/types.h>
|
|
3
6
|
#include <tiffio.h>
|
|
7
|
+
#include <tiffvers.h>
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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);
|
|
8
169
|
uint32_t width, height;
|
|
9
170
|
uint32_t* raster;
|
|
171
|
+
int stride;
|
|
172
|
+
size_t raster_size;
|
|
10
173
|
int ok = 0;
|
|
11
|
-
int dircount = 1;
|
|
12
174
|
|
|
13
175
|
if (tif == NULL) {
|
|
14
|
-
//fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename);
|
|
15
176
|
return 0;
|
|
16
177
|
}
|
|
17
178
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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;
|
|
24
187
|
}
|
|
25
188
|
|
|
26
|
-
|
|
27
|
-
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
|
|
28
|
-
raster = (uint32_t*)_TIFFmalloc(width * height * sizeof(*raster));
|
|
189
|
+
raster = (uint32_t*)_TIFFmalloc(raster_size);
|
|
29
190
|
if (raster != NULL) {
|
|
30
191
|
if (TIFFReadRGBAImageOriented(tif, width, height, raster,
|
|
31
192
|
ORIENTATION_TOPLEFT, 1)) {
|
|
32
|
-
|
|
33
|
-
pic->
|
|
34
|
-
pic->height = height;
|
|
193
|
+
pic->width = (int)width;
|
|
194
|
+
pic->height = (int)height;
|
|
35
195
|
// TIFF data is ABGR
|
|
36
196
|
#ifdef __BIG_ENDIAN__
|
|
37
|
-
TIFFSwabArrayOfLong(raster,
|
|
197
|
+
TIFFSwabArrayOfLong(raster, raster_size / sizeof(*raster));
|
|
38
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
|
+
}
|
|
39
205
|
ok = keep_alpha
|
|
40
206
|
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
|
|
41
207
|
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
|
|
42
208
|
}
|
|
43
209
|
_TIFFfree(raster);
|
|
44
|
-
} else {
|
|
45
|
-
//fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
|
|
46
210
|
}
|
|
47
211
|
|
|
48
212
|
if (ok && keep_alpha == 2) {
|
data/ext/webp_ffi/tiffdec.h
CHANGED
|
@@ -3,21 +3,29 @@
|
|
|
3
3
|
|
|
4
4
|
#include "webp/encode.h"
|
|
5
5
|
#include "webp/decode.h"
|
|
6
|
+
#include "./metadata.h"
|
|
6
7
|
|
|
7
8
|
#ifdef __cplusplus
|
|
8
9
|
extern "C" {
|
|
9
10
|
#endif
|
|
10
11
|
|
|
11
|
-
// Reads a TIFF from '
|
|
12
|
+
// Reads a TIFF from 'in_file', returning the decoded output in 'pic'.
|
|
12
13
|
// If 'keep_alpha' is true and the TIFF has an alpha channel, the output is RGBA
|
|
13
|
-
// otherwise it will be RGB.
|
|
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.
|
|
14
17
|
// Returns true on success.
|
|
15
|
-
int UtilReadTIFF(
|
|
16
|
-
struct WebPPicture* const pic, int keep_alpha
|
|
18
|
+
int UtilReadTIFF(FILE* const in_file,
|
|
19
|
+
struct WebPPicture* const pic, int keep_alpha,
|
|
20
|
+
Metadata* const metadata);
|
|
17
21
|
|
|
18
22
|
int UtilWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer);
|
|
19
23
|
int UtilWriteBMP(FILE* fout, const WebPDecBuffer* const buffer);
|
|
20
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
|
+
|
|
21
29
|
#ifdef __cplusplus
|
|
22
30
|
} // extern "C"
|
|
23
31
|
#endif
|
data/ext/webp_ffi/util.c
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
#include <limits.h>
|
|
2
|
+
#include <sys/stat.h>
|
|
1
3
|
#include <stdio.h>
|
|
2
4
|
#include <stdlib.h>
|
|
3
5
|
#include <string.h>
|
|
@@ -14,6 +16,34 @@
|
|
|
14
16
|
extern "C" {
|
|
15
17
|
#endif
|
|
16
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
|
+
|
|
17
47
|
static int UtilReadYUV(FILE* in_file, WebPPicture* const pic) {
|
|
18
48
|
const int use_argb = pic->use_argb;
|
|
19
49
|
const int uv_width = (pic->width + 1) / 2;
|
|
@@ -54,7 +84,9 @@ static InputFileFormat GetImageType(FILE* in_file) {
|
|
|
54
84
|
return format;
|
|
55
85
|
}
|
|
56
86
|
|
|
57
|
-
|
|
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];
|
|
58
90
|
if (magic == 0x89504E47U) {
|
|
59
91
|
format = iPNG_;
|
|
60
92
|
} else if (magic >= 0xFFD8FF00U && magic <= 0xFFD8FFFFU) {
|
|
@@ -65,44 +97,53 @@ static InputFileFormat GetImageType(FILE* in_file) {
|
|
|
65
97
|
return format;
|
|
66
98
|
}
|
|
67
99
|
|
|
68
|
-
int
|
|
69
|
-
|
|
100
|
+
int UtilReadPictureFile(FILE* const in_file, WebPPicture* const pic,
|
|
101
|
+
int keep_alpha, Metadata* const metadata) {
|
|
70
102
|
int ok = 0;
|
|
71
|
-
FILE* in_file = fopen(filename, "rb");
|
|
72
|
-
if (in_file == NULL) {
|
|
73
|
-
//fprintf(stderr, "Error! Cannot open input file '%s'\n", filename);
|
|
74
|
-
return ok;
|
|
75
|
-
}
|
|
76
103
|
|
|
77
104
|
if (pic->width == 0 || pic->height == 0) {
|
|
78
|
-
// If no size specified, try to decode it as PNG/JPEG (as appropriate).
|
|
105
|
+
// If no size specified, try to decode it as PNG/JPEG/TIFF (as appropriate).
|
|
79
106
|
const InputFileFormat format = GetImageType(in_file);
|
|
80
107
|
if (format == iPNG_) {
|
|
81
|
-
ok = UtilReadPNG(in_file, pic, keep_alpha);
|
|
108
|
+
ok = UtilReadPNG(in_file, pic, keep_alpha, metadata);
|
|
82
109
|
} else if (format == iJPEG_) {
|
|
83
|
-
ok = UtilReadJPEG(in_file, pic);
|
|
110
|
+
ok = UtilReadJPEG(in_file, pic, metadata);
|
|
84
111
|
} else if (format == iTIFF_) {
|
|
85
|
-
ok = UtilReadTIFF(
|
|
112
|
+
ok = UtilReadTIFF(in_file, pic, keep_alpha, metadata);
|
|
86
113
|
}
|
|
87
114
|
} else {
|
|
88
115
|
// If image size is specified, infer it as YUV format.
|
|
89
116
|
ok = UtilReadYUV(in_file, pic);
|
|
90
117
|
}
|
|
91
|
-
|
|
92
|
-
fclose(in_file);
|
|
93
118
|
return ok;
|
|
94
119
|
}
|
|
95
120
|
|
|
121
|
+
int UtilFileExists(const char* const path) {
|
|
122
|
+
struct stat info;
|
|
123
|
+
return stat(path, &info) == 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
96
126
|
int UtilSaveOutput(const WebPDecBuffer* const buffer,
|
|
97
127
|
OutputFileFormat format, const char* const out_file) {
|
|
98
|
-
|
|
99
|
-
int
|
|
100
|
-
|
|
101
|
-
fout = fopen(out_file, "wb");
|
|
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");
|
|
102
132
|
if (!fout) {
|
|
103
|
-
fprintf(stderr, "Error opening output file %s\n", out_file);
|
|
104
133
|
return 0;
|
|
105
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;
|
|
106
147
|
|
|
107
148
|
if (format == oPNG) {
|
|
108
149
|
ok &= UtilWritePNG(fout, buffer);
|
|
@@ -114,14 +155,14 @@ int UtilSaveOutput(const WebPDecBuffer* const buffer,
|
|
|
114
155
|
ok &= UtilWriteBMP(fout, buffer);
|
|
115
156
|
} else if (format == oTIFF_) {
|
|
116
157
|
ok &= UtilWriteTIFF(fout, buffer);
|
|
117
|
-
} else if (format == oPGM
|
|
158
|
+
} else if (format == oPGM) {
|
|
118
159
|
ok &= UtilWritePGM(fout, buffer);
|
|
160
|
+
} else if (format == oYUV) {
|
|
161
|
+
ok &= UtilWriteYUV(fout, buffer);
|
|
119
162
|
} else if (format == ALPHA_PLANE_ONLY) {
|
|
120
163
|
ok &= UtilWriteAlphaPlane(fout, buffer);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (fout) {
|
|
124
|
-
fclose(fout);
|
|
164
|
+
} else {
|
|
165
|
+
ok = 0;
|
|
125
166
|
}
|
|
126
167
|
return ok;
|
|
127
168
|
}
|
|
@@ -133,7 +174,8 @@ int UtilReadFile(const char* const file_name,
|
|
|
133
174
|
const uint8_t** data, size_t* data_size) {
|
|
134
175
|
int ok;
|
|
135
176
|
void* file_data;
|
|
136
|
-
|
|
177
|
+
long file_size;
|
|
178
|
+
struct stat info;
|
|
137
179
|
FILE* in;
|
|
138
180
|
|
|
139
181
|
if (file_name == NULL || data == NULL || data_size == NULL) return 0;
|
|
@@ -142,25 +184,30 @@ int UtilReadFile(const char* const file_name,
|
|
|
142
184
|
|
|
143
185
|
in = fopen(file_name, "rb");
|
|
144
186
|
if (in == NULL) {
|
|
145
|
-
fprintf(stderr, "cannot open input file '%s'\n", file_name);
|
|
146
187
|
return 0;
|
|
147
188
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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);
|
|
154
203
|
fclose(in);
|
|
155
204
|
|
|
156
205
|
if (!ok) {
|
|
157
|
-
fprintf(stderr, "Could not read %zu bytes of data from file %s\n",
|
|
158
|
-
file_size, file_name);
|
|
159
206
|
free(file_data);
|
|
160
207
|
return 0;
|
|
161
208
|
}
|
|
162
209
|
*data = (uint8_t*)file_data;
|
|
163
|
-
*data_size = file_size;
|
|
210
|
+
*data_size = (size_t)file_size;
|
|
164
211
|
return 1;
|
|
165
212
|
}
|
|
166
213
|
|
data/ext/webp_ffi/util.h
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
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
|
+
|
|
1
8
|
#include "webp/decode.h"
|
|
2
9
|
#include "webp/encode.h"
|
|
10
|
+
#include "./metadata.h"
|
|
3
11
|
|
|
4
12
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
5
13
|
extern "C" {
|
|
@@ -23,16 +31,33 @@ typedef enum {
|
|
|
23
31
|
UNSUPPORTED
|
|
24
32
|
} InputFileFormat;
|
|
25
33
|
|
|
34
|
+
// Writes 'buffer' to 'out_file'. When writing fails, a file this call created
|
|
35
|
+
// is removed again. Returns 1 on success.
|
|
26
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);
|
|
27
40
|
// Allocates storage for entire file 'file_name' and returns contents and size
|
|
28
41
|
// in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
|
|
29
42
|
// be deleted using free().
|
|
30
43
|
int UtilReadFile(const char* const file_name,
|
|
31
44
|
const uint8_t** data, size_t* data_size);
|
|
32
45
|
|
|
33
|
-
|
|
34
|
-
|
|
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);
|
|
35
58
|
|
|
36
59
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
37
60
|
} // extern "C"
|
|
38
|
-
#endif
|
|
61
|
+
#endif
|
|
62
|
+
|
|
63
|
+
#endif /* _WEBP_FFI_UTIL_H_ */
|