webp-ffi 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 <png.h>
8
-
9
- #include <setjmp.h> // note: this must be included *after* png.h
10
- #include <jpeglib.h>
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;