home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / libtiff / lbtif3_3.tar / tools / rgb2ycbcr.c < prev    next >
C/C++ Source or Header  |  1993-08-26  |  10KB  |  347 lines

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