New comit of SDL2
[supertux.git] / src / SDL2 / external / tiff-4.0.3 / tools / rgb2ycbcr.c
1 /* $Id: rgb2ycbcr.c,v 1.14 2011-05-31 17:03:16 bfriesen Exp $ */
2
3 /*
4  * Copyright (c) 1991-1997 Sam Leffler
5  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and 
8  * its documentation for any purpose is hereby granted without fee, provided
9  * that (i) the above copyright notices and this permission notice appear in
10  * all copies of the software and related documentation, and (ii) the names of
11  * Sam Leffler and Silicon Graphics may not be used in any advertising or
12  * publicity relating to the software without the specific, prior written
13  * permission of Sam Leffler and Silicon Graphics.
14  * 
15  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
16  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
17  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
18  * 
19  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
23  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
24  * OF THIS SOFTWARE.
25  */
26
27 #include "tif_config.h"
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36
37 #ifdef NEED_LIBPORT
38 # include "libport.h"
39 #endif
40
41 #include "tiffiop.h"
42 #include "tiffio.h"
43
44 #define streq(a,b)      (strcmp(a,b) == 0)
45 #define CopyField(tag, v) \
46     if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
47
48 #ifndef howmany
49 #define howmany(x, y)   (((x)+((y)-1))/(y))
50 #endif
51 #define roundup(x, y)   (howmany(x,y)*((uint32)(y)))
52
53 #define LumaRed         ycbcrCoeffs[0]
54 #define LumaGreen       ycbcrCoeffs[1]
55 #define LumaBlue        ycbcrCoeffs[2]
56
57 uint16  compression = COMPRESSION_PACKBITS;
58 uint32  rowsperstrip = (uint32) -1;
59
60 uint16  horizSubSampling = 2;           /* YCbCr horizontal subsampling */
61 uint16  vertSubSampling = 2;            /* YCbCr vertical subsampling */
62 float   ycbcrCoeffs[3] = { .299F, .587F, .114F };
63 /* default coding range is CCIR Rec 601-1 with no headroom/footroom */
64 float   refBlackWhite[6] = { 0.F, 255.F, 128.F, 255.F, 128.F, 255.F };
65
66 static  int tiffcvt(TIFF* in, TIFF* out);
67 static  void usage(int code);
68 static  void setupLumaTables(void);
69
70 int
71 main(int argc, char* argv[])
72 {
73         TIFF *in, *out;
74         int c;
75         extern int optind;
76         extern char *optarg;
77
78         while ((c = getopt(argc, argv, "c:h:r:v:z")) != -1)
79                 switch (c) {
80                 case 'c':
81                         if (streq(optarg, "none"))
82                             compression = COMPRESSION_NONE;
83                         else if (streq(optarg, "packbits"))
84                             compression = COMPRESSION_PACKBITS;
85                         else if (streq(optarg, "lzw"))
86                             compression = COMPRESSION_LZW;
87                         else if (streq(optarg, "jpeg"))
88                             compression = COMPRESSION_JPEG;
89                         else if (streq(optarg, "zip"))
90                             compression = COMPRESSION_ADOBE_DEFLATE;
91                         else
92                             usage(-1);
93                         break;
94                 case 'h':
95                         horizSubSampling = atoi(optarg);
96                         break;
97                 case 'v':
98                         vertSubSampling = atoi(optarg);
99                         break;
100                 case 'r':
101                         rowsperstrip = atoi(optarg);
102                         break;
103                 case 'z':       /* CCIR Rec 601-1 w/ headroom/footroom */
104                         refBlackWhite[0] = 16.;
105                         refBlackWhite[1] = 235.;
106                         refBlackWhite[2] = 128.;
107                         refBlackWhite[3] = 240.;
108                         refBlackWhite[4] = 128.;
109                         refBlackWhite[5] = 240.;
110                         break;
111                 case '?':
112                         usage(0);
113                         /*NOTREACHED*/
114                 }
115         if (argc - optind < 2)
116                 usage(-1);
117         out = TIFFOpen(argv[argc-1], "w");
118         if (out == NULL)
119                 return (-2);
120         setupLumaTables();
121         for (; optind < argc-1; optind++) {
122                 in = TIFFOpen(argv[optind], "r");
123                 if (in != NULL) {
124                         do {
125                                 if (!tiffcvt(in, out) ||
126                                     !TIFFWriteDirectory(out)) {
127                                         (void) TIFFClose(out);
128                                         return (1);
129                                 }
130                         } while (TIFFReadDirectory(in));
131                         (void) TIFFClose(in);
132                 }
133         }
134         (void) TIFFClose(out);
135         return (0);
136 }
137
138 float   *lumaRed;
139 float   *lumaGreen;
140 float   *lumaBlue;
141 float   D1, D2;
142 int     Yzero;
143
144 static float*
145 setupLuma(float c)
146 {
147         float *v = (float *)_TIFFmalloc(256 * sizeof (float));
148         int i;
149         for (i = 0; i < 256; i++)
150                 v[i] = c * i;
151         return (v);
152 }
153
154 static unsigned
155 V2Code(float f, float RB, float RW, int CR)
156 {
157         unsigned int c = (unsigned int)((((f)*(RW-RB)/CR)+RB)+.5);
158         return (c > 255 ? 255 : c);
159 }
160
161 static void
162 setupLumaTables(void)
163 {
164         lumaRed = setupLuma(LumaRed);
165         lumaGreen = setupLuma(LumaGreen);
166         lumaBlue = setupLuma(LumaBlue);
167         D1 = 1.F/(2.F - 2.F*LumaBlue);
168         D2 = 1.F/(2.F - 2.F*LumaRed);
169         Yzero = V2Code(0, refBlackWhite[0], refBlackWhite[1], 255);
170 }
171
172 static void
173 cvtClump(unsigned char* op, uint32* raster, uint32 ch, uint32 cw, uint32 w)
174 {
175         float Y, Cb = 0, Cr = 0;
176         uint32 j, k;
177         /*
178          * Convert ch-by-cw block of RGB
179          * to YCbCr and sample accordingly.
180          */
181         for (k = 0; k < ch; k++) {
182                 for (j = 0; j < cw; j++) {
183                         uint32 RGB = (raster - k*w)[j];
184                         Y = lumaRed[TIFFGetR(RGB)] +
185                             lumaGreen[TIFFGetG(RGB)] +
186                             lumaBlue[TIFFGetB(RGB)];
187                         /* accumulate chrominance */
188                         Cb += (TIFFGetB(RGB) - Y) * D1;
189                         Cr += (TIFFGetR(RGB) - Y) * D2;
190                         /* emit luminence */
191                         *op++ = V2Code(Y,
192                             refBlackWhite[0], refBlackWhite[1], 255);
193                 }
194                 for (; j < horizSubSampling; j++)
195                         *op++ = Yzero;
196         }
197         for (; k < vertSubSampling; k++) {
198                 for (j = 0; j < horizSubSampling; j++)
199                         *op++ = Yzero;
200         }
201         /* emit sampled chrominance values */
202         *op++ = V2Code(Cb / (ch*cw), refBlackWhite[2], refBlackWhite[3], 127);
203         *op++ = V2Code(Cr / (ch*cw), refBlackWhite[4], refBlackWhite[5], 127);
204 }
205 #undef LumaRed
206 #undef LumaGreen
207 #undef LumaBlue
208 #undef V2Code
209
210 /*
211  * Convert a strip of RGB data to YCbCr and
212  * sample to generate the output data.
213  */
214 static void
215 cvtStrip(unsigned char* op, uint32* raster, uint32 nrows, uint32 width)
216 {
217         uint32 x;
218         int clumpSize = vertSubSampling * horizSubSampling + 2;
219         uint32 *tp;
220
221         for (; nrows >= vertSubSampling; nrows -= vertSubSampling) {
222                 tp = raster;
223                 for (x = width; x >= horizSubSampling; x -= horizSubSampling) {
224                         cvtClump(op, tp,
225                             vertSubSampling, horizSubSampling, width);
226                         op += clumpSize;
227                         tp += horizSubSampling;
228                 }
229                 if (x > 0) {
230                         cvtClump(op, tp, vertSubSampling, x, width);
231                         op += clumpSize;
232                 }
233                 raster -= vertSubSampling*width;
234         }
235         if (nrows > 0) {
236                 tp = raster;
237                 for (x = width; x >= horizSubSampling; x -= horizSubSampling) {
238                         cvtClump(op, tp, nrows, horizSubSampling, width);
239                         op += clumpSize;
240                         tp += horizSubSampling;
241                 }
242                 if (x > 0)
243                         cvtClump(op, tp, nrows, x, width);
244         }
245 }
246
247 static int
248 cvtRaster(TIFF* tif, uint32* raster, uint32 width, uint32 height)
249 {
250         uint32 y;
251         tstrip_t strip = 0;
252         tsize_t cc, acc;
253         unsigned char* buf;
254         uint32 rwidth = roundup(width, horizSubSampling);
255         uint32 rheight = roundup(height, vertSubSampling);
256         uint32 nrows = (rowsperstrip > rheight ? rheight : rowsperstrip);
257         uint32 rnrows = roundup(nrows,vertSubSampling);
258
259         cc = rnrows*rwidth +
260             2*((rnrows*rwidth) / (horizSubSampling*vertSubSampling));
261         buf = (unsigned char*)_TIFFmalloc(cc);
262         // FIXME unchecked malloc
263         for (y = height; (int32) y > 0; y -= nrows) {
264                 uint32 nr = (y > nrows ? nrows : y);
265                 cvtStrip(buf, raster + (y-1)*width, nr, width);
266                 nr = roundup(nr, vertSubSampling);
267                 acc = nr*rwidth +
268                         2*((nr*rwidth)/(horizSubSampling*vertSubSampling));
269                 if (!TIFFWriteEncodedStrip(tif, strip++, buf, acc)) {
270                         _TIFFfree(buf);
271                         return (0);
272                 }
273         }
274         _TIFFfree(buf);
275         return (1);
276 }
277
278 static int
279 tiffcvt(TIFF* in, TIFF* out)
280 {
281         uint32 width, height;           /* image width & height */
282         uint32* raster;                 /* retrieve RGBA image */
283         uint16 shortv;
284         float floatv;
285         char *stringv;
286         uint32 longv;
287         int result;
288         size_t pixel_count;
289
290         TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
291         TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
292         pixel_count = width * height;
293
294         /* XXX: Check the integer overflow. */
295         if (!width || !height || pixel_count / width != height) {
296                 TIFFError(TIFFFileName(in),
297                           "Malformed input file; "
298                           "can't allocate buffer for raster of %lux%lu size",
299                           (unsigned long)width, (unsigned long)height);
300                 return 0;
301         }
302  
303         raster = (uint32*)_TIFFCheckMalloc(in, pixel_count, sizeof(uint32),
304                                            "raster buffer");
305         if (raster == 0) {
306                 TIFFError(TIFFFileName(in),
307                           "Failed to allocate buffer (%lu elements of %lu each)",
308                           (unsigned long)pixel_count,
309                           (unsigned long)sizeof(uint32));
310                 return (0);
311         }
312
313         if (!TIFFReadRGBAImage(in, width, height, raster, 0)) {
314                 _TIFFfree(raster);
315                 return (0);
316         }
317
318         CopyField(TIFFTAG_SUBFILETYPE, longv);
319         TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
320         TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
321         TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
322         TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
323         TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
324         if (compression == COMPRESSION_JPEG)
325                 TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW);
326         CopyField(TIFFTAG_FILLORDER, shortv);
327         TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
328         TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
329         CopyField(TIFFTAG_XRESOLUTION, floatv);
330         CopyField(TIFFTAG_YRESOLUTION, floatv);
331         CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
332         TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
333         { char buf[2048];
334           char *cp = strrchr(TIFFFileName(in), '/');
335           sprintf(buf, "YCbCr conversion of %s", cp ? cp+1 : TIFFFileName(in));
336           TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, buf);
337         }
338         TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFGetVersion());
339         CopyField(TIFFTAG_DOCUMENTNAME, stringv);
340
341         TIFFSetField(out, TIFFTAG_REFERENCEBLACKWHITE, refBlackWhite);
342         TIFFSetField(out, TIFFTAG_YCBCRSUBSAMPLING,
343             horizSubSampling, vertSubSampling);
344         TIFFSetField(out, TIFFTAG_YCBCRPOSITIONING, YCBCRPOSITION_CENTERED);
345         TIFFSetField(out, TIFFTAG_YCBCRCOEFFICIENTS, ycbcrCoeffs);
346         rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
347         TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
348
349         result = cvtRaster(out, raster, width, height);
350         _TIFFfree(raster);
351         return result;
352 }
353
354 char* stuff[] = {
355     "usage: rgb2ycbcr [-c comp] [-r rows] [-h N] [-v N] input... output\n",
356     "where comp is one of the following compression algorithms:\n",
357     " jpeg\t\tJPEG encoding\n",
358     " lzw\t\tLempel-Ziv & Welch encoding\n",
359     " zip\t\tdeflate encoding\n",
360     " packbits\tPackBits encoding (default)\n",
361     " none\t\tno compression\n",
362     "and the other options are:\n",
363     " -r\trows/strip\n",
364     " -h\thorizontal sampling factor (1,2,4)\n",
365     " -v\tvertical sampling factor (1,2,4)\n",
366     NULL
367 };
368
369 static void
370 usage(int code)
371 {
372         char buf[BUFSIZ];
373         int i;
374
375         setbuf(stderr, buf);
376        
377  fprintf(stderr, "%s\n\n", TIFFGetVersion());
378         for (i = 0; stuff[i] != NULL; i++)
379                 fprintf(stderr, "%s\n", stuff[i]);
380         exit(code);
381 }
382
383 /* vim: set ts=8 sts=8 sw=8 noet: */
384 /*
385  * Local Variables:
386  * mode: c
387  * c-basic-offset: 8
388  * fill-column: 78
389  * End:
390  */