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: */