webp-ffi 0.2.3 → 0.3.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 +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +20 -5
- data/CHANGELOG.md +17 -0
- data/README.md +50 -4
- data/Rakefile +3 -3
- data/ext/webp_ffi/Rakefile +6 -2
- 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/ext/webp_ffi/webp_ffi.c +9 -1
- data/ext/webp_ffi/webp_ffi.h +4 -3
- data/lib/webp/c.rb +1 -0
- data/lib/webp/options.rb +1 -1
- data/lib/webp/version.rb +1 -1
- data/spec/travis_build.sh +5 -7
- data/spec/webp_ffi_spec.rb +20 -8
- data/webp-ffi.gemspec +1 -1
- metadata +14 -9
@@ -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;
|