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

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