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.
@@ -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;