home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / MacPNG Library 1.02 / pngMacSrc 1.02 / png.1 / ptot / tiff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-11  |  17.8 KB  |  632 lines  |  [TEXT/CWIE]

  1. /*
  2.  * tiff.c
  3.  *
  4.  * TIFF writing routines for PNG-to-TIFF utility.
  5.  *
  6.  **********
  7.  *
  8.  * HISTORY
  9.  *
  10.  * 95-03-10 Created by Lee Daniel Crocker <lee@piclab.com>
  11.  *          <URL:http://www.piclab.com/piclab/index.html>
  12.  */
  13.  
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <math.h>
  18.  
  19. #include "ptot.h"
  20.  
  21. #define DEFINE_ENUMS
  22. #include "errors.h"
  23.  
  24. #define MAX_TAGS 40
  25.  
  26. U16 ASCII_tags[N_KEYWORDS] = {
  27.     TIFF_TAG_Artist, TIFF_TAG_Copyright, TIFF_TAG_Software,
  28.     TIFF_TAG_Model, TIFF_TAG_ImageDescription
  29. };
  30.  
  31. /*
  32.  * Local statics
  33.  */
  34.  
  35. static int write_tag(U16, int, U32, U8 *);
  36. static int get_tag_pos(U16);
  37. static int write_basic_tags(void);
  38. static int write_strips(void);
  39. static int write_extended_tags(void);
  40. static int write_png_data(void);
  41. static int write_ifd(void);
  42. static void align_file_offset(int);
  43.  
  44. static struct _tiff_state {
  45.     IMG_INFO *image;
  46.     FILE *outf;
  47.     int tag_count;
  48.     U16 byte_order;
  49.     U32 file_offset;
  50.     U8 ifd[12 * MAX_TAGS];
  51.     U8 *buf;
  52. } ts;
  53.  
  54. /*
  55.  * Determine what the local byte order is (this is the one we
  56.  * will use for the output TIFF), and verify that we have compiled
  57.  * the correct macros. We're a little more pedantic here than
  58.  * necessary, but if any of this is not exactly right, the whole
  59.  * thing falls apart quietly, so paranoia is justified.
  60.  */
  61.  
  62. int
  63. get_local_byte_order(
  64.     void)
  65. {
  66.     U8 testbuf[4];
  67.     int byte_order;
  68.  
  69.     PUT32(testbuf,0x01020304L);
  70.  
  71.     if (0x01 == *testbuf) {
  72.         byte_order = TIFF_BO_Motorola;
  73.  
  74. #ifndef BIG_ENDIAN
  75.     ASSERT(FALSE);
  76. #endif
  77.         BE_PUT32(testbuf, 0x01020304L);
  78.         if (0x01020304 != GET32(testbuf)) return ERR_BYTE_ORDER;
  79.         LE_PUT32(testbuf, 0x04030201L);
  80.         if (0x01020304 != GET32(testbuf)) return ERR_BYTE_ORDER;
  81.     } else if (0x04 == *testbuf) {
  82.         byte_order = TIFF_BO_Intel;
  83.  
  84. #ifndef LITTLE_ENDIAN
  85.     ASSERT(FALSE);
  86. #endif
  87.         LE_PUT32(testbuf, 0x01020304L);
  88.         if (0x01020304 != GET32(testbuf)) return ERR_BYTE_ORDER;
  89.         BE_PUT32(testbuf, 0x04030201L);
  90.         if (0x01020304 != GET32(testbuf)) return ERR_BYTE_ORDER;
  91.     } else return ERR_BYTE_ORDER;
  92.  
  93.     ASSERT(TIFF_BO_Intel == byte_order || \
  94.       TIFF_BO_Motorola == byte_order);
  95.  
  96.     return byte_order;
  97. }
  98.  
  99. /*
  100.  * Write image specified by IMGINFO structure to TIFF file.
  101.  */
  102.  
  103. int
  104. write_TIFF(
  105.     FILE *outf,
  106.     IMG_INFO *image)
  107. {
  108.     int err;
  109.  
  110.     ASSERT(NULL != outf);
  111.     ASSERT(NULL != image);
  112.     ASSERT(NULL != image->pixel_data_file);
  113.  
  114.     if (NULL == (ts.buf = (U8 *)malloc(IOBUF_SIZE)))
  115.       return ERR_MEMORY;
  116.     ts.outf = outf;
  117.     ts.image = image;
  118.     ts.byte_order = get_local_byte_order();
  119.  
  120.     PUT16(ts.buf, ts.byte_order);
  121.     PUT16(ts.buf+2, TIFF_MagicNumber);
  122.     PUT32(ts.buf+4, 0);                     /* Will be filled in later - ifd size*/
  123.     
  124.     if (8 != fwrite(ts.buf, 1, 8, outf)) return ERR_WRITE;    /* Write TIFF File header */
  125.     
  126.     ts.file_offset = 8;
  127.     ts.tag_count = 0;
  128.     memset(ts.ifd, 0, 12 * MAX_TAGS);                        /* Zero ifd buffers */
  129.  
  130.     if (0 != (err = write_basic_tags())) return err;        /* output width, height, etc... */
  131.  
  132.     if (0 != (err = write_strips())) return err;    
  133.     
  134.     remove(image->pixel_data_file);
  135.     if (0 != (err = write_extended_tags())) return err;        /* Write resolution tags, gamma, etc... */
  136.  
  137.     if (0 != image->png_data_size) {
  138.         ASSERT(NULL != image->png_data_file);
  139.         if (0 != (err = write_png_data())) return err;
  140.         remove(image->png_data_file);
  141.     }
  142.     err = write_ifd();                                        /* Output ifd to disk... */
  143.  
  144.     free(ts.buf);
  145.     return err;
  146. }
  147.  
  148. /*
  149.  * Sizes (in bytes) of the respective TIFF data types
  150.  */
  151. static data_sizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
  152.  
  153. #define DIRENT(index,byte) (ts.ifd+12*(index)+(byte))
  154.  
  155. /*
  156.  * Find where to insert the new tag into the sorted IFD
  157.  * by simple linear search.
  158.  */
  159.  
  160. static int
  161. get_tag_pos( U16 newtag)
  162. {
  163.     int tag, tagpos, newpos = 0;
  164.  
  165.     while (newpos < ts.tag_count) {
  166.         tag = GET16(DIRENT(newpos,0));
  167.         if (tag > newtag) break;
  168.         ++newpos;
  169.         ASSERT(newpos < MAX_TAGS);
  170.     }
  171.     for (tagpos = ++ts.tag_count; tagpos > newpos; --tagpos) {
  172.         memcpy(DIRENT(tagpos,0), DIRENT(tagpos-1,0), 12);
  173.     }
  174.     PUT16(DIRENT(newpos,0), newtag);
  175.     return newpos;
  176. }
  177.  
  178. static int
  179. write_tag( U16 newtag, int data_type,
  180.     U32 count, U8 *buffer)
  181. {
  182.     U32 data_size;
  183.     int newpos;
  184.  
  185.     ASSERT(ts.tag_count < MAX_TAGS);
  186.     ASSERT(data_type > 0 && data_type <= 12);
  187.     ASSERT(NULL != buffer);
  188.     ASSERT(NULL != ts.outf);
  189.  
  190.     newpos = get_tag_pos(newtag);                    // Add tag to idf table
  191.     PUT16(DIRENT(newpos,2), data_type);
  192.     PUT32(DIRENT(newpos,4), count);
  193.  
  194.     data_size = count * data_sizes[data_type];
  195.     if (data_size <= 4) {
  196.         memcpy(DIRENT(newpos,8), buffer, 4);        // insert data into idf tag
  197.         if (data_size < 4)
  198.            memset(DIRENT(newpos,8+data_size), 0, (size_t)(4-data_size));
  199.     } else {
  200.         align_file_offset(2);
  201.         PUT32(DIRENT(newpos,8), ts.file_offset);    // insert offset into idf tag
  202.         fwrite(buffer, data_sizes[data_type], (size_t)count, ts.outf);    // write data.
  203.         ts.file_offset += count * data_sizes[data_type];
  204.     }
  205.     return 0;
  206. }
  207.  
  208. static int write_png_data( void)            // Write PNG unique tag data
  209. {    int newpos;
  210.     FILE *inf;
  211.     size_t bytes;
  212.  
  213.     ASSERT(NULL != ts.image->png_data_file);
  214.  
  215.     if (NULL == (inf = fopen(ts.image->png_data_file, "rb")))
  216.       return ERR_READ;
  217.  
  218.     newpos = get_tag_pos(TIFF_TAG_PNGChunks);
  219.     PUT16(DIRENT(newpos,2), TIFF_DT_UNDEFINED);
  220.     PUT32(DIRENT(newpos,4), ts.image->png_data_size);
  221.  
  222.     align_file_offset(2);
  223.     PUT32(DIRENT(newpos,8), ts.file_offset);
  224.     while (0 != ts.image->png_data_size) {
  225.  
  226.         bytes = fread(ts.buf, 1, (size_t)min(IOBUF_SIZE,
  227.           ts.image->png_data_size), inf);
  228.           
  229.         fwrite(ts.buf, 1, bytes, ts.outf);
  230.         ts.image->png_data_size -= bytes;
  231.         ts.file_offset += bytes;
  232.     }
  233.     fclose(inf);
  234.     return 0;
  235. }
  236.  
  237. #undef DIRENT
  238.  
  239. /*
  240.  * Some data structures must be at even byte offsets in the
  241.  * file. Some must be aligned on 32-bit boundaries. We handle
  242.  * those cases by simply adding pad bytes where needed.
  243.  */
  244.  
  245. static void
  246. align_file_offset(
  247.     int modulus)
  248. {
  249.     ASSERT(modulus > 0 && modulus <= 16);
  250.  
  251.     while (0 != (ts.file_offset % modulus)) {
  252.         putc(0, ts.outf);
  253.         ++ts.file_offset;
  254.     }
  255. }
  256.  
  257. static int
  258. write_basic_tags( void)
  259. {
  260.     U16 short_val;
  261.  
  262.     ASSERT(NULL != ts.buf);
  263.     ASSERT(NULL != ts.image);
  264.  
  265.     PUT32(ts.buf, ts.image->width);
  266.     write_tag(TIFF_TAG_ImageWidth, TIFF_DT_LONG, 1, ts.buf);
  267.  
  268.     PUT32(ts.buf, ts.image->height);
  269.     write_tag(TIFF_TAG_ImageLength, TIFF_DT_LONG, 1, ts.buf);
  270.  
  271.     if (ts.image->is_palette) short_val = TIFF_PI_PLTE;
  272.     else if (ts.image->is_color) short_val = TIFF_PI_RGB;
  273.     else short_val = TIFF_PI_GRAY;
  274.     PUT16(ts.buf, short_val);
  275.     write_tag(TIFF_TAG_PhotometricInterpretation, TIFF_DT_SHORT, 1, ts.buf);
  276.  
  277.     PUT16(ts.buf, TIFF_CT_NONE);
  278.     write_tag(TIFF_TAG_Compression, TIFF_DT_SHORT, 1, ts.buf);
  279.  
  280.     PUT16(ts.buf, TIFF_PC_CONTIG);
  281.     write_tag(TIFF_TAG_PlanarConfiguration, TIFF_DT_SHORT, 1, ts.buf);
  282.  
  283.     PUT16(ts.buf, ts.image->bits_per_sample);
  284.     write_tag(TIFF_TAG_BitsPerSample, TIFF_DT_SHORT, 1, ts.buf);
  285.  
  286.     PUT16(ts.buf, ts.image->samples_per_pixel);
  287.     write_tag(TIFF_TAG_SamplesPerPixel, TIFF_DT_SHORT, 1, ts.buf);
  288.  
  289.     if (ts.image->is_palette) {
  290.         int index, cmap_size;
  291.         U8 *srcp, *redp, *greenp, *bluep;
  292.  
  293.         cmap_size = 1 << ts.image->bits_per_sample;
  294.         if (6 * cmap_size > IOBUF_SIZE) return ERR_WRITE;
  295.         memset(ts.buf, 0, 6 * cmap_size);
  296.  
  297.         srcp = ts.image->palette;
  298.         redp = ts.buf;
  299.         greenp = ts.buf + 2 * cmap_size;
  300.         bluep = ts.buf + 4 * cmap_size;
  301.  
  302.         for (index = 0; index < ts.image->palette_size; ++index) {
  303.             *redp++ = *srcp;
  304.             *redp++ = *srcp++;
  305.             *greenp++ = *srcp;
  306.             *greenp++ = *srcp++;
  307.             *bluep++ = *srcp;
  308.             *bluep++ = *srcp++;
  309.         }
  310.         write_tag(TIFF_TAG_ColorMap, TIFF_DT_SHORT, 3 * cmap_size, ts.buf);
  311.     }
  312.     /*
  313.      * Being truly lossless-minded here, we should check for the
  314.      * transparency information in the structure and expand that
  315.      * into a full alpha channel in the TIFF. This is left as an
  316.      * exercise for the reader. :-)
  317.      */
  318.     if (ts.image->has_alpha /* || ts.image->has_trns */) {
  319.         PUT16(ts.buf, TIFF_ES_UNASSOC);
  320.         write_tag(TIFF_TAG_ExtraSamples, TIFF_DT_SHORT, 1, ts.buf);
  321.     }
  322.     return 0;
  323. }
  324.  
  325. static int
  326. write_extended_tags( void)
  327. {
  328.     int i;
  329.     U16 tiff_unit;
  330.     U32 xoff, yoff, longside, bias;
  331.  
  332.     tiff_unit = 0xFFFF; /* Not yet assigned */
  333.  
  334.     if (0 != ts.image->xres) {        // output resolution if it exists
  335.         if (PNG_MU_None == ts.image->resolution_unit)
  336.           tiff_unit = TIFF_RU_NONE;
  337.         else {
  338.             ASSERT(PNG_MU_Meter == ts.image->resolution_unit);
  339.             tiff_unit = TIFF_RU_CM;
  340.             ts.image->xres /= 100;
  341.             ts.image->yres /= 100;
  342.         }
  343.         PUT16(ts.buf, tiff_unit);
  344.         write_tag(TIFF_TAG_ResolutionUnit, TIFF_DT_SHORT, 1, ts.buf);
  345.  
  346.         PUT32(ts.buf, ts.image->xres);
  347.         write_tag(TIFF_TAG_XResolution, TIFF_DT_LONG, 1, ts.buf);
  348.  
  349.         PUT32(ts.buf, ts.image->yres);
  350.         write_tag(TIFF_TAG_YResolution, TIFF_DT_LONG, 1, ts.buf);
  351.     }
  352.     /*
  353.      * TIFF Assumes the same unit for resolution and offset.
  354.      * PNG does not, so we have to do some converting here.
  355.      * Also, TIFF does not apparently allow offsets when there
  356.      * is no resolution unit (or at least doesn't define that
  357.      * case unambiguously). This is one of the very rare cases
  358.      * where TIFF is inadequately specified.
  359.      */
  360.     if (0 != ts.image->xoffset) {
  361.         if (TIFF_RU_NONE != tiff_unit) {
  362.             if (0xFFFF == tiff_unit) {
  363.                 PUT16(ts.buf, tiff_unit = TIFF_RU_CM);
  364.                 write_tag(TIFF_TAG_ResolutionUnit, TIFF_DT_SHORT, 1, ts.buf);
  365.             }
  366.             ASSERT(TIFF_RU_CM == tiff_unit);
  367.  
  368.             xoff = ts.image->xoffset;
  369.             yoff = ts.image->yoffset;
  370.  
  371.             if (PNG_MU_Micrometer != ts.image->offset_unit) {
  372.                 ASSERT(PNG_MU_Pixel == ts.image->offset_unit);
  373.  
  374.                 if (PNG_MU_None == ts.image->resolution_unit) {
  375.                     /*
  376.                      * Assume 72 DPI
  377.                      */
  378.                     xoff = (ts.image->xoffset * 3175) / 9;
  379.                     yoff = (ts.image->yoffset * 3175) / 9;
  380.                 } else {
  381.                     /*
  382.                      * Guard against overflow
  383.                      */
  384.                     longside = max(ts.image->xoffset,
  385.                       ts.image->yoffset);
  386.                     bias = 1;
  387.  
  388.                     while (longside > 2000) {
  389.                         bias *= 2;
  390.                         longside /= 2;
  391.                     }
  392.                     xoff = (ts.image->xoffset * (1000000 / bias)) /
  393.                       (ts.image->xres / bias);
  394.                     yoff = (ts.image->yoffset * (1000000 / bias)) /
  395.                       (ts.image->yres / bias);
  396.                 }
  397.             }
  398.             PUT32(ts.buf, xoff);
  399.             PUT32(ts.buf + 4, 10000L);
  400.             write_tag(TIFF_TAG_XPosition, TIFF_DT_RATIONAL, 1, ts.buf);
  401.  
  402.             PUT32(ts.buf, yoff);
  403.             PUT32(ts.buf + 4, 10000L);
  404.             write_tag(TIFF_TAG_YPosition, TIFF_DT_RATIONAL, 1, ts.buf);
  405.         }
  406.     }    // end if offset
  407.     
  408.     /*
  409.      * Map cHRM chunk to WhitePoint and PrimaryChromaticities
  410.      */
  411.     if (0.0 != ts.image->chromaticities[0]) {
  412.         int i;
  413.  
  414.         for (i = 0; i < 2; ++i) {
  415.             PUT32(ts.buf + 8 * i, ts.image->chromaticities[i]);
  416.             PUT32(ts.buf + 8 * i + 4, 100000L);
  417.         }
  418.         write_tag(TIFF_TAG_WhitePoint, TIFF_DT_RATIONAL, 2, ts.buf);
  419.  
  420.         for (i = 0; i < 6; ++i) {
  421.             PUT32(ts.buf + 8 * i, ts.image->chromaticities[i+2]);
  422.             PUT32(ts.buf + 8 * i + 4, 100000L);
  423.         }
  424.         write_tag(TIFF_TAG_PrimaryChromaticities, TIFF_DT_RATIONAL, 6, ts.buf);
  425.     }
  426.     /*
  427.      * ASCII Tags
  428.      */
  429.     for (i = 0; i < N_KEYWORDS; ++i) {
  430.         if (NULL != ts.image->keywords[i]) {
  431.             write_tag(ASCII_tags[i], TIFF_DT_ASCII,
  432.               strlen(ts.image->keywords[i]) + 1, (U8 *)ts.image->keywords[i]);
  433.         }
  434.     }
  435.     /*
  436.      * Map gAMA chunk to TransferFunction tag
  437.      */
  438.     if (0.0 != ts.image->source_gamma) {
  439.         U32 count, index;
  440.         double maxval;
  441.  
  442.         count = 1 << ts.image->bits_per_sample;
  443.         if (2 * count > IOBUF_SIZE) return ERR_WRITE;
  444.  
  445.         PUT16(ts.buf, 0);
  446.         maxval = (double)count - 1.0;
  447.  
  448.         for (index = 1; index < count; ++index) {
  449.             PUT16(ts.buf + 2 * index,
  450.               (U16)floor(0.5 + 65535 * pow((double)index / maxval,
  451.               1.0 / ts.image->source_gamma)));
  452.         }
  453.         write_tag(TIFF_TAG_TransferFunction, TIFF_DT_SHORT, count, ts.buf);
  454.     }
  455.     return 0;
  456. }
  457.  
  458. static int
  459. write_ifd( void)
  460. {
  461.     int err;
  462.  
  463.     ASSERT(NULL != ts.buf);
  464.     ASSERT(NULL != ts.outf);
  465.     ASSERT(ts.tag_count <= MAX_TAGS);
  466.  
  467.     align_file_offset(2);                                // Align to even byte in file.
  468.     if (ts.file_offset == (U32)ftell(ts.outf)) err = 0;    // get pos. of file.
  469.     else err = ERR_WRITE;
  470.  
  471.     PUT16(ts.buf, ts.tag_count);                        // number of ifd tags
  472.     fwrite(ts.buf, 2, 1, ts.outf);
  473.     
  474.     fwrite(ts.ifd, 12, ts.tag_count, ts.outf);            // output ifd tags
  475.  
  476.     PUT32(ts.buf, 0L);                                    // finish link list of ifd tags
  477.     fwrite(ts.buf, 4, 1, ts.outf);
  478.  
  479.     PUT32(ts.buf, ts.file_offset);
  480.     fseek(ts.outf, 4L, SEEK_SET);                        // update ifd location
  481.     fwrite(ts.buf, 1, 4, ts.outf);
  482.  
  483.     return 0;
  484. }
  485.  
  486. /*
  487.  * Write out the actual pixel data into approximately 8k strips
  488.  * (larger if needed to fit the StripOffsets data into one I/O
  489.  * buffer) and write the related tags.
  490.  */
  491.  
  492. #define BPS (ts.image->bits_per_sample)
  493. #define SPP (ts.image->samples_per_pixel)
  494. #define OKW(x) ((x)<ts.image->width)
  495.  
  496. static int
  497. write_strips( void)            // assume pixcell data is in: "ts.image->pixel_data_file"
  498. {
  499.     size_t line_size, strip_size;
  500.     U32 strip, total_strips, rows_per_strip;
  501.     U8 *line_buf;
  502.     FILE *inf;
  503.  
  504.     line_size = new_line_size(ts.image, 0, 1);    // see: zchunks.c
  505.     if (line_size > 4096) {
  506.         rows_per_strip = 1;
  507.     } else {
  508.         rows_per_strip = 8192 / line_size;        // multi line / strip of data
  509.     }
  510.     ASSERT(0 != rows_per_strip);
  511.  
  512.     do {
  513.         strip_size = rows_per_strip * line_size;
  514.         total_strips = (ts.image->height + (rows_per_strip - 1)) / rows_per_strip;
  515.         rows_per_strip *= 2;
  516.     } while (4 * total_strips > IOBUF_SIZE);    // make multi 
  517.     rows_per_strip /= 2;
  518.  
  519.     PUT32(ts.buf, rows_per_strip);
  520.     write_tag(TIFF_TAG_RowsPerStrip, TIFF_DT_LONG, 1, ts.buf);
  521.  
  522.     for (strip = 0; strip < total_strips; ++strip) {
  523.         PUT32(ts.buf + 4 * strip, strip_size);
  524.     }
  525.     write_tag(TIFF_TAG_StripByteCounts, TIFF_DT_LONG, total_strips, ts.buf);
  526.  
  527.     align_file_offset(2);
  528.     if (0 != (strip_size & 1)) ++strip_size;
  529.  
  530.     for (strip = 0; strip < total_strips; ++strip) {
  531.         PUT32(ts.buf + 4 * strip, ts.file_offset +
  532.           4 * total_strips + strip * strip_size);
  533.     }
  534.     write_tag(TIFF_TAG_StripOffsets, TIFF_DT_LONG, total_strips, ts.buf);
  535.     /*
  536.      * Write the strip data from the pixel data file.
  537.      */
  538.     if (NULL == (line_buf = (U8 *)malloc(line_size)))
  539.       return ERR_MEMORY;
  540.  
  541.     ASSERT(NULL != ts.image->pixel_data_file);
  542.     if (NULL == (inf = fopen(ts.image->pixel_data_file, "rb"))) {
  543.         free(line_buf);
  544.         return ERR_READ;
  545.     }
  546.     for (strip = 0; strip < total_strips; ++strip) {
  547.         U32 row, col, scanline;
  548.  
  549.         scanline = 0;
  550.         align_file_offset(2);
  551.  
  552.         for (row = 0; row < rows_per_strip; ++row) {
  553.             int bit, byte, step, sample;
  554.             U16 word;
  555.             U8 *lp;
  556.  
  557.             lp = line_buf;
  558.             if (BPS < 8) step = 8 / BPS;
  559.             else step = 1;
  560.  
  561.             for (col = 0; col < ts.image->width; col += step) {
  562.                 switch (BPS) {
  563.                 case 1:
  564.                     ASSERT(1 == SPP);
  565.  
  566.                     *lp = getc(inf) & 0x80;
  567.                     for (bit = 1; bit < 8; ++bit) {
  568.                         if (!OKW(col+bit)) break;
  569.                         byte = getc(inf);
  570.                         if (0 != (byte & 0x80)) {
  571.                             *lp |= (1 << (7 - bit));
  572.                         }
  573.                     }
  574.                     ++lp;
  575.                     break;
  576.                 case 2:
  577.                     ASSERT(1 == SPP);
  578.  
  579.                     *lp = getc(inf) & 0xC0;
  580.                     if OKW(col+1) *lp |= ((getc(inf) >> 2) & 0x30);
  581.                     if OKW(col+2) *lp |= ((getc(inf) >> 4) & 0x0C);
  582.                     if OKW(col+3) *lp |= ((getc(inf) >> 6) & 0x03);
  583.                     ++lp;
  584.                     break;
  585.                 case 4:
  586.                     ASSERT(1 == SPP);
  587.  
  588.                     *lp = getc(inf) & 0xF0;
  589.                     if OKW(col+1) *lp |= ((getc(inf) >> 4) & 0x0F);
  590.                     ++lp;
  591.                     break;
  592.                 case 8:
  593.                     for (sample = 0; sample < SPP; ++sample) {
  594.                         *lp++ = (0xFF & getc(inf));
  595.                     }
  596.                     break;
  597.                 case 16:
  598.                     for (sample = 0; sample < SPP; ++sample) {
  599.                          word = ((getc(inf) << 8) & 0xFF00);
  600.                          word |= (0xFF & getc(inf));
  601.                          PUT16(lp, word);
  602.                          lp += 2;
  603.                     }
  604.                     break;
  605.                 default:
  606.                     ASSERT(FALSE);
  607.                 }
  608.             }
  609.             ASSERT(lp - line_buf == line_size);
  610.             if (line_size != fwrite(line_buf, 1, line_size, ts.outf)) {
  611.                 fclose(inf);
  612.                 free(line_buf);
  613.                 return ERR_WRITE;
  614.             }
  615.             ts.file_offset += line_size;
  616.             if (++scanline >= ts.image->height) break;
  617.         }
  618.     }
  619.     fclose(inf);
  620.     free(line_buf);
  621.     return 0;
  622. }
  623.  
  624. #undef SPP
  625. #undef BPS
  626. #undef OKW
  627.  
  628. /*
  629.  * End of TIFF.C
  630.  */
  631.  
  632.