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

  1. /* $Header: /usr/people/sam/tiff/tools/RCS/pal2rgb.c,v 1.29 1996/01/10 19:35:29 sam Rel $ */
  2.  
  3. /*
  4.  * Copyright (c) 1988-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. #include <ctype.h>
  31.  
  32. #include "tiffio.h"
  33.  
  34. #define    streq(a,b)    (strcmp(a,b) == 0)
  35. #define    strneq(a,b,n)    (strncmp(a,b,n) == 0)
  36.  
  37. static    void usage(void);
  38. static    void cpTags(TIFF* in, TIFF* out);
  39.  
  40. static int
  41. checkcmap(int n, uint16* r, uint16* g, uint16* b)
  42. {
  43.     while (n-- > 0)
  44.         if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
  45.         return (16);
  46.     fprintf(stderr, "Warning, assuming 8-bit colormap.\n");
  47.     return (8);
  48. }
  49.  
  50. #define    CopyField(tag, v) \
  51.     if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
  52. #define    CopyField3(tag, v1, v2, v3) \
  53.     if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
  54.  
  55. static    uint16 compression = (uint16) -1;
  56. static    uint16 predictor = 0;
  57. static    int quality = 75;    /* JPEG quality */
  58. static    int jpegcolormode = JPEGCOLORMODE_RGB;
  59. static    int processCompressOptions(char*);
  60.  
  61. int
  62. main(int argc, char* argv[])
  63. {
  64.     uint16 bitspersample, shortv;
  65.     uint32 imagewidth, imagelength;
  66.     uint16 config = PLANARCONFIG_CONTIG;
  67.     uint32 rowsperstrip = (uint32) -1;
  68.     uint16 photometric = PHOTOMETRIC_RGB;
  69.     uint16 *rmap, *gmap, *bmap;
  70.     uint32 row;
  71.     int cmap = -1;
  72.     TIFF *in, *out;
  73.     int c;
  74.     extern int optind;
  75.     extern char* optarg;
  76.  
  77.     while ((c = getopt(argc, argv, "C:c:p:r:")) != -1)
  78.         switch (c) {
  79.         case 'C':        /* force colormap interpretation */
  80.             cmap = atoi(optarg);
  81.             break;
  82.         case 'c':        /* compression scheme */
  83.             if (!processCompressOptions(optarg))
  84.                 usage();
  85.             break;
  86.         case 'p':        /* planar configuration */
  87.             if (streq(optarg, "separate"))
  88.                 config = PLANARCONFIG_SEPARATE;
  89.             else if (streq(optarg, "contig"))
  90.                 config = PLANARCONFIG_CONTIG;
  91.             else
  92.                 usage();
  93.             break;
  94.         case 'r':        /* rows/strip */
  95.             rowsperstrip = atoi(optarg);
  96.             break;
  97.         case '?':
  98.             usage();
  99.             /*NOTREACHED*/
  100.         }
  101.     if (argc - optind != 2)
  102.         usage();
  103.     in = TIFFOpen(argv[optind], "r");
  104.     if (in == NULL)
  105.         return (-1);
  106.     if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &shortv) ||
  107.         shortv != PHOTOMETRIC_PALETTE) {
  108.         fprintf(stderr, "%s: Expecting a palette image.\n",
  109.             argv[optind]);
  110.         return (-1);
  111.     }
  112.     if (!TIFFGetField(in, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
  113.         fprintf(stderr,
  114.             "%s: No colormap (not a valid palette image).\n",
  115.             argv[optind]);
  116.         return (-1);
  117.     }
  118.     bitspersample = 0;
  119.     TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
  120.     if (bitspersample != 8) {
  121.         fprintf(stderr, "%s: Sorry, can only handle 8-bit images.\n",
  122.             argv[optind]);
  123.         return (-1);
  124.     }
  125.     out = TIFFOpen(argv[optind+1], "w");
  126.     if (out == NULL)
  127.         return (-2);
  128.     cpTags(in, out);
  129.     TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &imagewidth);
  130.     TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
  131.     if (compression != (uint16)-1)
  132.         TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
  133.     else
  134.         TIFFGetField(in, TIFFTAG_COMPRESSION, &compression);
  135.     switch (compression) {
  136.     case COMPRESSION_JPEG:
  137.         if (jpegcolormode == JPEGCOLORMODE_RGB)
  138.             photometric = PHOTOMETRIC_YCBCR;
  139.         else
  140.             photometric = PHOTOMETRIC_RGB;
  141.         TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
  142.         TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
  143.         break;
  144.     case COMPRESSION_LZW:
  145.     case COMPRESSION_DEFLATE:
  146.         if (predictor != 0)
  147.             TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
  148.         break;
  149.     }
  150.     TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
  151.     TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
  152.     TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
  153.     TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
  154.         rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip));
  155.     (void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);
  156.     if (cmap == -1)
  157.         cmap = checkcmap(1<<bitspersample, rmap, gmap, bmap);
  158.     if (cmap == 16) {
  159.         /*
  160.          * Convert 16-bit colormap to 8-bit.
  161.          */
  162.         int i;
  163.  
  164.         for (i = (1<<bitspersample)-1; i > 0; i--) {
  165. #define    CVT(x)        (((x) * 255) / ((1L<<16)-1))
  166.             rmap[i] = CVT(rmap[i]);
  167.             gmap[i] = CVT(gmap[i]);
  168.             bmap[i] = CVT(bmap[i]);
  169.         }
  170.     }
  171.     { unsigned char *ibuf, *obuf;
  172.       register unsigned char* pp;
  173.       register uint32 x;
  174.       ibuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(in));
  175.       obuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(out));
  176.       switch (config) {
  177.       case PLANARCONFIG_CONTIG:
  178.         for (row = 0; row < imagelength; row++) {
  179.             if (!TIFFReadScanline(in, ibuf, row, 0))
  180.                 goto done;
  181.             pp = obuf;
  182.             for (x = 0; x < imagewidth; x++) {
  183.                 *pp++ = rmap[ibuf[x]];
  184.                 *pp++ = gmap[ibuf[x]];
  185.                 *pp++ = bmap[ibuf[x]];
  186.             }
  187.             if (!TIFFWriteScanline(out, obuf, row, 0))
  188.                 goto done;
  189.         }
  190.         break;
  191.       case PLANARCONFIG_SEPARATE:
  192.         for (row = 0; row < imagelength; row++) {
  193.             if (!TIFFReadScanline(in, ibuf, row, 0))
  194.                 goto done;
  195.             for (pp = obuf, x = 0; x < imagewidth; x++)
  196.                 *pp++ = rmap[ibuf[x]];
  197.             if (!TIFFWriteScanline(out, obuf, row, 0))
  198.                 goto done;
  199.             for (pp = obuf, x = 0; x < imagewidth; x++)
  200.                 *pp++ = gmap[ibuf[x]];
  201.             if (!TIFFWriteScanline(out, obuf, row, 0))
  202.                 goto done;
  203.             for (pp = obuf, x = 0; x < imagewidth; x++)
  204.                 *pp++ = bmap[ibuf[x]];
  205.             if (!TIFFWriteScanline(out, obuf, row, 0))
  206.                 goto done;
  207.         }
  208.         break;
  209.       }
  210.       _TIFFfree(ibuf);
  211.       _TIFFfree(obuf);
  212.     }
  213. done:
  214.     (void) TIFFClose(in);
  215.     (void) TIFFClose(out);
  216.     return (0);
  217. }
  218.  
  219. static int
  220. processCompressOptions(char* opt)
  221. {
  222.     if (streq(opt, "none"))
  223.         compression = COMPRESSION_NONE;
  224.     else if (streq(opt, "packbits"))
  225.         compression = COMPRESSION_PACKBITS;
  226.     else if (strneq(opt, "jpeg", 4)) {
  227.         char* cp = strchr(opt, ':');
  228.         if (cp && isdigit(cp[1]))
  229.             quality = atoi(cp+1);
  230.         if (cp && strchr(cp, 'r'))
  231.             jpegcolormode = JPEGCOLORMODE_RAW;
  232.         compression = COMPRESSION_JPEG;
  233.     } else if (strneq(opt, "lzw", 3)) {
  234.         char* cp = strchr(opt, ':');
  235.         if (cp)
  236.             predictor = atoi(cp+1);
  237.         compression = COMPRESSION_LZW;
  238.     } else if (strneq(opt, "zip", 3)) {
  239.         char* cp = strchr(opt, ':');
  240.         if (cp)
  241.             predictor = atoi(cp+1);
  242.         compression = COMPRESSION_DEFLATE;
  243.     } else
  244.         return (0);
  245.     return (1);
  246. }
  247.  
  248. #define    CopyField1(tag, v) \
  249.     if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
  250. #define    CopyField2(tag, v1, v2) \
  251.     if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
  252. #define    CopyField3(tag, v1, v2, v3) \
  253.     if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
  254. #define    CopyField4(tag, v1, v2, v3, v4) \
  255.     if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
  256.  
  257. static void
  258. cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
  259. {
  260.     uint16 shortv, shortv2, *shortav;
  261.     float floatv, *floatav;
  262.     char *stringv;
  263.     uint32 longv;
  264.  
  265.     switch (type) {
  266.     case TIFF_SHORT:
  267.     if (count == 1) {
  268.         CopyField1(tag, shortv);
  269.     } else if (count == 2) {
  270.         CopyField2(tag, shortv, shortv2);
  271.     } else if (count == (uint16) -1) {
  272.         CopyField2(tag, shortv, shortav);
  273.     }
  274.     break;
  275.     case TIFF_LONG:
  276.     CopyField1(tag, longv);
  277.     break;
  278.     case TIFF_RATIONAL:
  279.     if (count == 1) {
  280.         CopyField1(tag, floatv);
  281.     } else if (count == (uint16) -1) {
  282.         CopyField1(tag, floatav);
  283.     }
  284.     break;
  285.     case TIFF_ASCII:
  286.     CopyField1(tag, stringv);
  287.     break;
  288.     }
  289. }
  290. #undef CopyField4
  291. #undef CopyField3
  292. #undef CopyField2
  293. #undef CopyField1
  294.  
  295. static struct cpTag {
  296.     uint16    tag;
  297.     uint16    count;
  298.     TIFFDataType type;
  299. } tags[] = {
  300.     { TIFFTAG_IMAGEWIDTH,        1, TIFF_LONG },
  301.     { TIFFTAG_IMAGELENGTH,        1, TIFF_LONG },
  302.     { TIFFTAG_BITSPERSAMPLE,        1, TIFF_SHORT },
  303.     { TIFFTAG_COMPRESSION,        1, TIFF_SHORT },
  304.     { TIFFTAG_FILLORDER,        1, TIFF_SHORT },
  305.     { TIFFTAG_ROWSPERSTRIP,        1, TIFF_LONG },
  306.     { TIFFTAG_GROUP3OPTIONS,        1, TIFF_LONG },
  307.     { TIFFTAG_SUBFILETYPE,        1, TIFF_LONG },
  308.     { TIFFTAG_THRESHHOLDING,        1, TIFF_SHORT },
  309.     { TIFFTAG_DOCUMENTNAME,        1, TIFF_ASCII },
  310.     { TIFFTAG_IMAGEDESCRIPTION,        1, TIFF_ASCII },
  311.     { TIFFTAG_MAKE,            1, TIFF_ASCII },
  312.     { TIFFTAG_MODEL,            1, TIFF_ASCII },
  313.     { TIFFTAG_ORIENTATION,        1, TIFF_SHORT },
  314.     { TIFFTAG_MINSAMPLEVALUE,        1, TIFF_SHORT },
  315.     { TIFFTAG_MAXSAMPLEVALUE,        1, TIFF_SHORT },
  316.     { TIFFTAG_XRESOLUTION,        1, TIFF_RATIONAL },
  317.     { TIFFTAG_YRESOLUTION,        1, TIFF_RATIONAL },
  318.     { TIFFTAG_PAGENAME,            1, TIFF_ASCII },
  319.     { TIFFTAG_XPOSITION,        1, TIFF_RATIONAL },
  320.     { TIFFTAG_YPOSITION,        1, TIFF_RATIONAL },
  321.     { TIFFTAG_GROUP4OPTIONS,        1, TIFF_LONG },
  322.     { TIFFTAG_RESOLUTIONUNIT,        1, TIFF_SHORT },
  323.     { TIFFTAG_PAGENUMBER,        2, TIFF_SHORT },
  324.     { TIFFTAG_SOFTWARE,            1, TIFF_ASCII },
  325.     { TIFFTAG_DATETIME,            1, TIFF_ASCII },
  326.     { TIFFTAG_ARTIST,            1, TIFF_ASCII },
  327.     { TIFFTAG_HOSTCOMPUTER,        1, TIFF_ASCII },
  328.     { TIFFTAG_WHITEPOINT,        1, TIFF_RATIONAL },
  329.     { TIFFTAG_PRIMARYCHROMATICITIES,    (uint16) -1,TIFF_RATIONAL },
  330.     { TIFFTAG_HALFTONEHINTS,        2, TIFF_SHORT },
  331.     { TIFFTAG_BADFAXLINES,        1, TIFF_LONG },
  332.     { TIFFTAG_CLEANFAXDATA,        1, TIFF_SHORT },
  333.     { TIFFTAG_CONSECUTIVEBADFAXLINES,    1, TIFF_LONG },
  334.     { TIFFTAG_INKSET,            1, TIFF_SHORT },
  335.     { TIFFTAG_INKNAMES,            1, TIFF_ASCII },
  336.     { TIFFTAG_DOTRANGE,            2, TIFF_SHORT },
  337.     { TIFFTAG_TARGETPRINTER,        1, TIFF_ASCII },
  338.     { TIFFTAG_SAMPLEFORMAT,        1, TIFF_SHORT },
  339.     { TIFFTAG_YCBCRCOEFFICIENTS,    (uint16) -1,TIFF_RATIONAL },
  340.     { TIFFTAG_YCBCRSUBSAMPLING,        2, TIFF_SHORT },
  341.     { TIFFTAG_YCBCRPOSITIONING,        1, TIFF_SHORT },
  342.     { TIFFTAG_REFERENCEBLACKWHITE,    (uint16) -1,TIFF_RATIONAL },
  343. };
  344. #define    NTAGS    (sizeof (tags) / sizeof (tags[0]))
  345.  
  346. static void
  347. cpTags(TIFF* in, TIFF* out)
  348. {
  349.     struct cpTag *p;
  350.     for (p = tags; p < &tags[NTAGS]; p++)
  351.     cpTag(in, out, p->tag, p->count, p->type);
  352. }
  353. #undef NTAGS
  354.  
  355. char* stuff[] = {
  356. "usage: pal2rgb [options] input.tif output.tif",
  357. "where options are:",
  358. " -p contig    pack samples contiguously (e.g. RGBRGB...)",
  359. " -p separate    store samples separately (e.g. RRR...GGG...BBB...)",
  360. " -r #        make each strip have no more than # rows",
  361. " -C 8        assume 8-bit colormap values (instead of 16-bit)",
  362. " -C 16        assume 16-bit colormap values",
  363. "",
  364. " -c lzw[:opts]    compress output with Lempel-Ziv & Welch encoding",
  365. " -c zip[:opts]    compress output with deflate encoding",
  366. " -c packbits    compress output with packbits encoding",
  367. " -c none    use no compression algorithm on output",
  368. "",
  369. "LZW and deflate options:",
  370. " #        set predictor value",
  371. "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
  372. NULL
  373. };
  374.  
  375. static void
  376. usage(void)
  377. {
  378.     char buf[BUFSIZ];
  379.     int i;
  380.  
  381.     setbuf(stderr, buf);
  382.     for (i = 0; stuff[i] != NULL; i++)
  383.         fprintf(stderr, "%s\n", stuff[i]);
  384.     exit(-1);
  385. }
  386.