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"
39 #define streq(a,b) (strcmp(a,b) == 0)
40 #define CopyField(tag, v) \
41 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
44 #define howmany(x, y) (((x)+((y)-1))/(y))
46 #define roundup(x, y) (howmany(x,y)*((uint32)(y)))
48 #define LumaRed ycbcrCoeffs[0]
49 #define LumaGreen ycbcrCoeffs[1]
50 #define LumaBlue ycbcrCoeffs[2]
52 uint16 compression
= COMPRESSION_PACKBITS
;
53 uint32 rowsperstrip
= (uint32
) -1;
55 uint16 horizSubSampling
= 2; /* YCbCr horizontal subsampling */
56 uint16 vertSubSampling
= 2; /* YCbCr vertical subsampling */
57 float ycbcrCoeffs
[3] = { .299F
, .587F
, .114F
};
58 /* default coding range is CCIR Rec 601-1 with no headroom/footroom */
59 float refBlackWhite
[6] = { 0.F
, 255.F
, 128.F
, 255.F
, 128.F
, 255.F
};
61 static int tiffcvt(TIFF
* in
, TIFF
* out
);
62 static void usage(int code
);
63 static void setupLumaTables(void);
66 main(int argc
, char* argv
[])
73 while ((c
= getopt(argc
, argv
, "c:h:r:v:z")) != -1)
76 if (streq(optarg
, "none"))
77 compression
= COMPRESSION_NONE
;
78 else if (streq(optarg
, "packbits"))
79 compression
= COMPRESSION_PACKBITS
;
80 else if (streq(optarg
, "lzw"))
81 compression
= COMPRESSION_LZW
;
82 else if (streq(optarg
, "jpeg"))
83 compression
= COMPRESSION_JPEG
;
84 else if (streq(optarg
, "zip"))
85 compression
= COMPRESSION_ADOBE_DEFLATE
;
90 horizSubSampling
= atoi(optarg
);
93 vertSubSampling
= atoi(optarg
);
96 rowsperstrip
= atoi(optarg
);
98 case 'z': /* CCIR Rec 601-1 w/ headroom/footroom */
99 refBlackWhite
[0] = 16.;
100 refBlackWhite
[1] = 235.;
101 refBlackWhite
[2] = 128.;
102 refBlackWhite
[3] = 240.;
103 refBlackWhite
[4] = 128.;
104 refBlackWhite
[5] = 240.;
110 if (argc
- optind
< 2)
112 out
= TIFFOpen(argv
[argc
-1], "w");
116 for (; optind
< argc
-1; optind
++) {
117 in
= TIFFOpen(argv
[optind
], "r");
120 if (!tiffcvt(in
, out
) ||
121 !TIFFWriteDirectory(out
)) {
122 (void) TIFFClose(out
);
125 } while (TIFFReadDirectory(in
));
126 (void) TIFFClose(in
);
129 (void) TIFFClose(out
);
142 float *v
= (float *)_TIFFmalloc(256 * sizeof (float));
144 for (i
= 0; i
< 256; i
++)
150 V2Code(float f
, float RB
, float RW
, int CR
)
152 unsigned int c
= (unsigned int)((((f
)*(RW
-RB
)/CR
)+RB
)+.5);
153 return (c
> 255 ? 255 : c
);
157 setupLumaTables(void)
159 lumaRed
= setupLuma(LumaRed
);
160 lumaGreen
= setupLuma(LumaGreen
);
161 lumaBlue
= setupLuma(LumaBlue
);
162 D1
= 1.F
/(2.F
- 2.F
*LumaBlue
);
163 D2
= 1.F
/(2.F
- 2.F
*LumaRed
);
164 Yzero
= V2Code(0, refBlackWhite
[0], refBlackWhite
[1], 255);
168 cvtClump(unsigned char* op
, uint32
* raster
, uint32 ch
, uint32 cw
, uint32 w
)
170 float Y
, Cb
= 0, Cr
= 0;
173 * Convert ch-by-cw block of RGB
174 * to YCbCr and sample accordingly.
176 for (k
= 0; k
< ch
; k
++) {
177 for (j
= 0; j
< cw
; j
++) {
178 uint32 RGB
= (raster
- k
*w
)[j
];
179 Y
= lumaRed
[TIFFGetR(RGB
)] +
180 lumaGreen
[TIFFGetG(RGB
)] +
181 lumaBlue
[TIFFGetB(RGB
)];
182 /* accumulate chrominance */
183 Cb
+= (TIFFGetB(RGB
) - Y
) * D1
;
184 Cr
+= (TIFFGetR(RGB
) - Y
) * D2
;
187 refBlackWhite
[0], refBlackWhite
[1], 255);
189 for (; j
< horizSubSampling
; j
++)
192 for (; k
< vertSubSampling
; k
++) {
193 for (j
= 0; j
< horizSubSampling
; j
++)
196 /* emit sampled chrominance values */
197 *op
++ = V2Code(Cb
/ (ch
*cw
), refBlackWhite
[2], refBlackWhite
[3], 127);
198 *op
++ = V2Code(Cr
/ (ch
*cw
), refBlackWhite
[4], refBlackWhite
[5], 127);
206 * Convert a strip of RGB data to YCbCr and
207 * sample to generate the output data.
210 cvtStrip(unsigned char* op
, uint32
* raster
, uint32 nrows
, uint32 width
)
213 int clumpSize
= vertSubSampling
* horizSubSampling
+ 2;
216 for (; nrows
>= vertSubSampling
; nrows
-= vertSubSampling
) {
218 for (x
= width
; x
>= horizSubSampling
; x
-= horizSubSampling
) {
220 vertSubSampling
, horizSubSampling
, width
);
222 tp
+= horizSubSampling
;
225 cvtClump(op
, tp
, vertSubSampling
, x
, width
);
228 raster
-= vertSubSampling
*width
;
232 for (x
= width
; x
>= horizSubSampling
; x
-= horizSubSampling
) {
233 cvtClump(op
, tp
, nrows
, horizSubSampling
, width
);
235 tp
+= horizSubSampling
;
238 cvtClump(op
, tp
, nrows
, x
, width
);
243 cvtRaster(TIFF
* tif
, uint32
* raster
, uint32 width
, uint32 height
)
249 uint32 rwidth
= roundup(width
, horizSubSampling
);
250 uint32 rheight
= roundup(height
, vertSubSampling
);
251 uint32 nrows
= (rowsperstrip
> rheight
? rheight
: rowsperstrip
);
252 uint32 rnrows
= roundup(nrows
,vertSubSampling
);
255 2*((rnrows
*rwidth
) / (horizSubSampling
*vertSubSampling
));
256 buf
= (unsigned char*)_TIFFmalloc(cc
);
257 for (y
= height
; (int32
) y
> 0; y
-= nrows
) {
258 uint32 nr
= (y
> nrows
? nrows
: y
);
259 cvtStrip(buf
, raster
+ (y
-1)*width
, nr
, width
);
260 nr
= roundup(nr
, vertSubSampling
);
262 2*((nr
*rwidth
)/(horizSubSampling
*vertSubSampling
));
263 if (!TIFFWriteEncodedStrip(tif
, strip
++, buf
, acc
)) {
273 tiffcvt(TIFF
* in
, TIFF
* out
)
275 uint32 width
, height
; /* image width & height */
276 uint32
* raster
; /* retrieve RGBA image */
282 TIFFGetField(in
, TIFFTAG_IMAGEWIDTH
, &width
);
283 TIFFGetField(in
, TIFFTAG_IMAGELENGTH
, &height
);
284 raster
= (uint32
*)_TIFFmalloc(width
* height
* sizeof (uint32
));
286 TIFFError(TIFFFileName(in
), "No space for raster buffer");
289 if (!TIFFReadRGBAImage(in
, width
, height
, raster
, 0)) {
294 CopyField(TIFFTAG_SUBFILETYPE
, longv
);
295 TIFFSetField(out
, TIFFTAG_IMAGEWIDTH
, width
);
296 TIFFSetField(out
, TIFFTAG_IMAGELENGTH
, height
);
297 TIFFSetField(out
, TIFFTAG_BITSPERSAMPLE
, 8);
298 TIFFSetField(out
, TIFFTAG_COMPRESSION
, compression
);
299 TIFFSetField(out
, TIFFTAG_PHOTOMETRIC
, PHOTOMETRIC_YCBCR
);
300 if (compression
== COMPRESSION_JPEG
)
301 TIFFSetField(out
, TIFFTAG_JPEGCOLORMODE
, JPEGCOLORMODE_RAW
);
302 CopyField(TIFFTAG_FILLORDER
, shortv
);
303 TIFFSetField(out
, TIFFTAG_ORIENTATION
, ORIENTATION_TOPLEFT
);
304 TIFFSetField(out
, TIFFTAG_SAMPLESPERPIXEL
, 3);
305 CopyField(TIFFTAG_XRESOLUTION
, floatv
);
306 CopyField(TIFFTAG_YRESOLUTION
, floatv
);
307 CopyField(TIFFTAG_RESOLUTIONUNIT
, shortv
);
308 TIFFSetField(out
, TIFFTAG_PLANARCONFIG
, PLANARCONFIG_CONTIG
);
310 char *cp
= strrchr(TIFFFileName(in
), '/');
311 sprintf(buf
, "YCbCr conversion of %s", cp
? cp
+1 : TIFFFileName(in
));
312 TIFFSetField(out
, TIFFTAG_IMAGEDESCRIPTION
, buf
);
314 TIFFSetField(out
, TIFFTAG_SOFTWARE
, TIFFGetVersion());
315 CopyField(TIFFTAG_DOCUMENTNAME
, stringv
);
317 TIFFSetField(out
, TIFFTAG_REFERENCEBLACKWHITE
, refBlackWhite
);
318 TIFFSetField(out
, TIFFTAG_YCBCRSUBSAMPLING
,
319 horizSubSampling
, vertSubSampling
);
320 TIFFSetField(out
, TIFFTAG_YCBCRPOSITIONING
, YCBCRPOSITION_CENTERED
);
321 TIFFSetField(out
, TIFFTAG_YCBCRCOEFFICIENTS
, ycbcrCoeffs
);
322 rowsperstrip
= TIFFDefaultStripSize(out
, rowsperstrip
);
323 TIFFSetField(out
, TIFFTAG_ROWSPERSTRIP
, rowsperstrip
);
325 return (cvtRaster(out
, raster
, width
, height
));
329 "usage: rgb2ycbcr [-c comp] [-r rows] [-h N] [-v N] input... output\n",
330 "where comp is one of the following compression algorithms:\n",
331 " jpeg\t\tJPEG encoding\n",
332 " lzw\t\tLempel-Ziv & Welch encoding\n",
333 " zip\t\tdeflate encoding\n",
334 " packbits\tPackBits encoding (default)\n",
335 " none\t\tno compression\n",
336 "and the other options are:\n",
338 " -h\thorizontal sampling factor (1,2,4)\n",
339 " -v\tvertical sampling factor (1,2,4)\n",
351 fprintf(stderr
, "%s\n\n", TIFFGetVersion());
352 for (i
= 0; stuff
[i
] != NULL
; i
++)
353 fprintf(stderr
, "%s\n", stuff
[i
]);
357 /* vim: set ts=8 sts=8 sw=8 noet: */