4 * Copyright (c) 1991-1997 Sam Leffler
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
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.
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.
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
27 #include "tif_config.h"
44 #define streq(a,b) (strcmp(a,b) == 0)
45 #define CopyField(tag, v) \
46 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
49 #define howmany(x, y) (((x)+((y)-1))/(y))
51 #define roundup(x, y) (howmany(x,y)*((uint32)(y)))
53 #define LumaRed ycbcrCoeffs[0]
54 #define LumaGreen ycbcrCoeffs[1]
55 #define LumaBlue ycbcrCoeffs[2]
57 uint16 compression
= COMPRESSION_PACKBITS
;
58 uint32 rowsperstrip
= (uint32
) -1;
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
};
66 static int tiffcvt(TIFF
* in
, TIFF
* out
);
67 static void usage(int code
);
68 static void setupLumaTables(void);
71 main(int argc
, char* argv
[])
78 while ((c
= getopt(argc
, argv
, "c:h:r:v:z")) != -1)
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
;
95 horizSubSampling
= atoi(optarg
);
98 vertSubSampling
= atoi(optarg
);
101 rowsperstrip
= atoi(optarg
);
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.;
115 if (argc
- optind
< 2)
117 out
= TIFFOpen(argv
[argc
-1], "w");
121 for (; optind
< argc
-1; optind
++) {
122 in
= TIFFOpen(argv
[optind
], "r");
125 if (!tiffcvt(in
, out
) ||
126 !TIFFWriteDirectory(out
)) {
127 (void) TIFFClose(out
);
130 } while (TIFFReadDirectory(in
));
131 (void) TIFFClose(in
);
134 (void) TIFFClose(out
);
147 float *v
= (float *)_TIFFmalloc(256 * sizeof (float));
149 for (i
= 0; i
< 256; i
++)
155 V2Code(float f
, float RB
, float RW
, int CR
)
157 unsigned int c
= (unsigned int)((((f
)*(RW
-RB
)/CR
)+RB
)+.5);
158 return (c
> 255 ? 255 : c
);
162 setupLumaTables(void)
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);
173 cvtClump(unsigned char* op
, uint32
* raster
, uint32 ch
, uint32 cw
, uint32 w
)
175 float Y
, Cb
= 0, Cr
= 0;
178 * Convert ch-by-cw block of RGB
179 * to YCbCr and sample accordingly.
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
;
192 refBlackWhite
[0], refBlackWhite
[1], 255);
194 for (; j
< horizSubSampling
; j
++)
197 for (; k
< vertSubSampling
; k
++) {
198 for (j
= 0; j
< horizSubSampling
; j
++)
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);
211 * Convert a strip of RGB data to YCbCr and
212 * sample to generate the output data.
215 cvtStrip(unsigned char* op
, uint32
* raster
, uint32 nrows
, uint32 width
)
218 int clumpSize
= vertSubSampling
* horizSubSampling
+ 2;
221 for (; nrows
>= vertSubSampling
; nrows
-= vertSubSampling
) {
223 for (x
= width
; x
>= horizSubSampling
; x
-= horizSubSampling
) {
225 vertSubSampling
, horizSubSampling
, width
);
227 tp
+= horizSubSampling
;
230 cvtClump(op
, tp
, vertSubSampling
, x
, width
);
233 raster
-= vertSubSampling
*width
;
237 for (x
= width
; x
>= horizSubSampling
; x
-= horizSubSampling
) {
238 cvtClump(op
, tp
, nrows
, horizSubSampling
, width
);
240 tp
+= horizSubSampling
;
243 cvtClump(op
, tp
, nrows
, x
, width
);
248 cvtRaster(TIFF
* tif
, uint32
* raster
, uint32 width
, uint32 height
)
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
);
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
);
268 2*((nr
*rwidth
)/(horizSubSampling
*vertSubSampling
));
269 if (!TIFFWriteEncodedStrip(tif
, strip
++, buf
, acc
)) {
279 tiffcvt(TIFF
* in
, TIFF
* out
)
281 uint32 width
, height
; /* image width & height */
282 uint32
* raster
; /* retrieve RGBA image */
290 TIFFGetField(in
, TIFFTAG_IMAGEWIDTH
, &width
);
291 TIFFGetField(in
, TIFFTAG_IMAGELENGTH
, &height
);
292 pixel_count
= width
* height
;
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
);
303 raster
= (uint32
*)_TIFFCheckMalloc(in
, pixel_count
, sizeof(uint32
),
306 TIFFError(TIFFFileName(in
),
307 "Failed to allocate buffer (%lu elements of %lu each)",
308 (unsigned long)pixel_count
,
309 (unsigned long)sizeof(uint32
));
313 if (!TIFFReadRGBAImage(in
, width
, height
, raster
, 0)) {
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
);
334 char *cp
= strrchr(TIFFFileName(in
), '/');
335 sprintf(buf
, "YCbCr conversion of %s", cp
? cp
+1 : TIFFFileName(in
));
336 TIFFSetField(out
, TIFFTAG_IMAGEDESCRIPTION
, buf
);
338 TIFFSetField(out
, TIFFTAG_SOFTWARE
, TIFFGetVersion());
339 CopyField(TIFFTAG_DOCUMENTNAME
, stringv
);
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
);
349 result
= cvtRaster(out
, raster
, width
, height
);
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",
364 " -h\thorizontal sampling factor (1,2,4)\n",
365 " -v\tvertical sampling factor (1,2,4)\n",
377 fprintf(stderr
, "%s\n\n", TIFFGetVersion());
378 for (i
= 0; stuff
[i
] != NULL
; i
++)
379 fprintf(stderr
, "%s\n", stuff
[i
]);
383 /* vim: set ts=8 sts=8 sw=8 noet: */