home *** CD-ROM | disk | FTP | other *** search
/ Practical Algorithms for Image Analysis / Practical Algorithms for Image Analysis.iso / TARFILE.GZ / tarfile / libtiff / tools / rgb2ycbcr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-11  |  9.4 KB  |  339 lines

  1. /* $Header: /usr/people/sam/tiff/tools/RCS/rgb2ycbcr.c,v 1.27 1996/01/10 19:35:31 sam Rel $ */
  2.  
  3. /*
  4.  * Copyright (c) 1991-1996 Sam Leffler
  5.  * Copyright (c) 1991-1996 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 <stdio.h>
  28. #include <string.h>
  29. #include <stdlib.h>
  30.  
  31. #include "tiffio.h"
  32.  
  33. #define    streq(a,b)    (strcmp(a,b) == 0)
  34. #define    CopyField(tag, v) \
  35.     if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
  36.  
  37. #define    howmany(x, y)    (((x)+((y)-1))/(y))
  38. #define    roundup(x, y)    (howmany(x,y)*((uint32)(y)))
  39.  
  40. #define    LumaRed        ycbcrCoeffs[0]
  41. #define    LumaGreen    ycbcrCoeffs[1]
  42. #define    LumaBlue    ycbcrCoeffs[2]
  43.  
  44. uint16    compression = COMPRESSION_LZW;
  45. uint32    rowsperstrip = (uint32) -1;
  46.  
  47. uint16    horizSubSampling = 2;        /* YCbCr horizontal subsampling */
  48. uint16    vertSubSampling = 2;        /* YCbCr vertical subsampling */
  49. float    ycbcrCoeffs[3] = { .299, .587, .114 };
  50. /* default coding range is CCIR Rec 601-1 with no headroom/footroom */
  51. float    refBlackWhite[6] = { 0., 255., 128., 255., 128., 255. };
  52.  
  53. static    int tiffcvt(TIFF* in, TIFF* out);
  54. static    void usage(void);
  55. static    void setupLumaTables(void);
  56.  
  57. int
  58. main(int argc, char* argv[])
  59. {
  60.     TIFF *in, *out;
  61.     int c;
  62.     extern int optind;
  63.     extern char *optarg;
  64.  
  65.     while ((c = getopt(argc, argv, "c:h:r:v:z")) != -1)
  66.         switch (c) {
  67.         case 'c':
  68.             if (streq(optarg, "none"))
  69.                 compression = COMPRESSION_NONE;
  70.             else if (streq(optarg, "packbits"))
  71.                 compression = COMPRESSION_PACKBITS;
  72.             else if (streq(optarg, "lzw"))
  73.                 compression = COMPRESSION_LZW;
  74.             else if (streq(optarg, "jpeg"))
  75.                 compression = COMPRESSION_JPEG;
  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.         return (-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.                     return (1);
  114.                 }
  115.             } while (TIFFReadDirectory(in));
  116.             (void) TIFFClose(in);
  117.         }
  118.     }
  119.     (void) TIFFClose(out);
  120.     return (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 *)_TIFFmalloc(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, uint32* 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.             uint32 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, uint32* raster, uint32 nrows, uint32 width)
  201. {
  202.     uint32 x;
  203.     int clumpSize = vertSubSampling * horizSubSampling + 2;
  204.     uint32 *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, uint32* raster, uint32 width, uint32 height)
  234. {
  235.     uint32 y;
  236.     tstrip_t strip = 0;
  237.     tsize_t cc, acc;
  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*)_TIFFmalloc(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.         nr = roundup(nr, vertSubSampling);
  250.         acc = nr*rwidth +
  251.             2*((nr*rwidth)/(horizSubSampling*vertSubSampling));
  252.         if (!TIFFWriteEncodedStrip(tif, strip++, buf, acc)) {
  253.             _TIFFfree(buf);
  254.             return (0);
  255.         }
  256.     }
  257.     _TIFFfree(buf);
  258.     return (1);
  259. }
  260.  
  261. static int
  262. tiffcvt(TIFF* in, TIFF* out)
  263. {
  264.     uint32 width, height;        /* image width & height */
  265.     uint32* raster;            /* retrieve RGBA image */
  266.     uint16 shortv;
  267.     float floatv;
  268.     char *stringv;
  269.     uint32 longv;
  270.  
  271.     TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
  272.     TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
  273.     raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32));
  274.     if (raster == 0) {
  275.         TIFFError(TIFFFileName(in), "No space for raster buffer");
  276.         return (0);
  277.     }
  278.     if (!TIFFReadRGBAImage(in, width, height, raster, 0)) {
  279.         _TIFFfree(raster);
  280.         return (0);
  281.     }
  282.  
  283.     CopyField(TIFFTAG_SUBFILETYPE, longv);
  284.     TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
  285.     TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
  286.     TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
  287.     TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
  288.     TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
  289.     if (compression == COMPRESSION_JPEG)
  290.         TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW);
  291.     CopyField(TIFFTAG_FILLORDER, shortv);
  292.     TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
  293.     TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
  294.     CopyField(TIFFTAG_XRESOLUTION, floatv);
  295.     CopyField(TIFFTAG_YRESOLUTION, floatv);
  296.     CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
  297.     TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  298.     { char buf[2048];
  299.       char *cp = strrchr(TIFFFileName(in), '/');
  300.       sprintf(buf, "YCbCr conversion of %s", cp ? cp+1 : TIFFFileName(in));
  301.       TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, buf);
  302.     }
  303.     TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFGetVersion());
  304.     CopyField(TIFFTAG_DOCUMENTNAME, stringv);
  305.  
  306.     TIFFSetField(out, TIFFTAG_REFERENCEBLACKWHITE, refBlackWhite);
  307.     TIFFSetField(out, TIFFTAG_YCBCRSUBSAMPLING,
  308.         horizSubSampling, vertSubSampling);
  309.     TIFFSetField(out, TIFFTAG_YCBCRPOSITIONING, YCBCRPOSITION_CENTERED);
  310.     TIFFSetField(out, TIFFTAG_YCBCRCOEFFICIENTS, ycbcrCoeffs);
  311.     rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
  312.     TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
  313.  
  314.     return (cvtRaster(out, raster, width, height));
  315. }
  316.  
  317. static char* usageMsg[] = {
  318.     "usage: rgb2ycbcr [-c comp] [-r rows] [-h N] [-v N] input... output\n",
  319.     "where comp is one of the following compression algorithms:\n",
  320.     " jpeg\t\tJPEG encoding\n",
  321.     " lzw\t\tLempel-Ziv & Welch encoding\n",
  322.     " packbits\tPackBits encoding\n",
  323.     " none\t\tno compression\n",
  324.     "and the other options are:\n",
  325.     " -r\trows/strip\n",
  326.     " -h\thorizontal sampling factor (1,2,4)\n",
  327.     " -v\tvertical sampling factor (1,2,4)\n",
  328.     NULL
  329. };
  330.  
  331. static void
  332. usage(void)
  333. {
  334.     int i;
  335.     for (i = 0; usageMsg[i]; i++)
  336.         fprintf(stderr, "%s", usageMsg[i]);
  337.     exit(-1);
  338. }
  339.