1 /*
2  * This software is copyrighted as noted below.  It may be freely copied,
3  * modified, and redistributed, provided that the copyright notice is
4  * preserved on all copies.
5  *
6  * There is no warranty or other guarantee of fitness for this software,
7  * it is provided solely "as is".  Bug reports or fixes may be sent
8  * to the author, who may or may not act on them as he desires.
9  *
10  * You may not include this software in a program or other software product
11  * without supplying the source, or without informing the end-user that the
12  * source is available for no extra charge.
13  *
14  * If you modify this software, you should include a notice giving the
15  * name of the person performing the modification, the date of modification,
16  * and the reason for such modification.
17  */
18 /*
19  * tiff.c - interface with Aldus-Microsoft TIFF format.
20  *
21  * Author:      Raul Rivero
22  *              Mathematics Dept.
23  *              University of Oviedo
24  * Date:        Sat Jan 18 1992
25  * Copyright (c) 1992, Raul Rivero
26  *
27  */
28 /*
29  * Raul Rivero  -  04/14/94
30  *      Added support for images with any # of colors.
31  *
32  */
33 
34 #include <lug.h>
35 #include <lugfnts.h>
36 
37 
38 /*
39  * Look here !!!
40  * =============
41  *
42  * This code is valid only if we have defined the iTIFF
43  * macro ( read the root Makefile for more information ).
44  *
45  */
46 
47 #ifdef iTIFF
48 
49 #include <tiffio.h>
50 
51 #define GetField(a,b,c)         if ( TIFFGetField(a,b,c) == 0 ) error( 21 );
52 
53 extern int LUGverbose;
54 
read_tiff_file(name,image)55 read_tiff_file( name, image )
56 char *name;
57 bitmap_hdr *image;
58 {
59   register int i, j;
60   TIFF *handle;
61   long xsize, ysize;
62   ushort samplesperpixel;
63   ushort bitspersample;
64   ushort photometric;
65   ushort planarconfig;
66   ushort iscmyk = 0;
67   ushort c, m, y, k;
68   ushort *rTIFFcmap, *gTIFFcmap, *bTIFFcmap;
69   byte *r, *g, *b;
70   int totalsize;
71   byte *ptr;
72   byte *TIFFline;
73   double val, inc;
74 
75   /*
76    * Open the file.
77    */
78   if ( name )
79     handle = TIFFOpen( name, "rb" );
80   else handle = TIFFFdOpen( 0, "stdin", "rb" );
81   if ( handle == NULL )
82     error( 1 );
83 
84   /*
85    * Get TIFF configuration.
86    */
87   GetField( handle, TIFFTAG_IMAGEWIDTH,  &xsize );
88   GetField( handle, TIFFTAG_IMAGELENGTH, &ysize );
89   GetField( handle, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel );
90   GetField( handle, TIFFTAG_BITSPERSAMPLE, &bitspersample );
91   GetField( handle, TIFFTAG_PHOTOMETRIC, &photometric );
92   GetField( handle, TIFFTAG_PLANARCONFIG, &planarconfig );
93 
94   /*
95    * ... ok. Fill our header.
96    */
97   image->magic = LUGUSED;
98   image->xsize = (int) xsize;
99   image->ysize = (int) ysize;
100   image->depth = ( samplesperpixel < 4 ? samplesperpixel : 3 ) * bitspersample;
101   image->colors = 1 << image->depth;
102 
103   /*
104    * New LIBTIFF library has changed the calling parameters
105    * of the TIFFPrintDirectory functions, so ... what version
106    * are you using ?.
107    */
108   if ( LUGverbose )
109 #if TIFF_VERSION >= 42
110     TIFFPrintDirectory( handle, stderr,  0L );
111 #else
112     TIFFPrintDirectory( handle, stderr, 1, 0, 0 );
113 #endif
114 
115   switch ( photometric ) {
116     case PHOTOMETRIC_MINISBLACK :
117                 /* Get the increments while building the cmap table */
118                 inc = 255. / (((double)image->colors)-1.);
119                 /* Allocate memory for our cmap and build it */
120                 ptr = image->cmap = (byte *) Malloc( 3 * image->colors );
121                 for ( i = 0, val = 0.; i < image->colors; i++, val += inc ) {
122                   *ptr++ = (byte) val;
123                   *ptr++ = *(ptr-1);
124                   *ptr++ = *(ptr-1);
125                 }
126                 break;
127     case PHOTOMETRIC_MINISWHITE :
128                 /* Get the increments while building the cmap table */
129                 inc = 255. / (((double)image->colors)-1.);
130                 /* Allocate memory for our cmap and build it */
131                 ptr = image->cmap = (byte *) Malloc( 3 * image->colors );
132                 for ( i = 0, val = 255.; i < image->colors; i++, val -=inc ) {
133                   *ptr++ = (byte) val;
134                   *ptr++ = *(ptr-1);
135                   *ptr++ = *(ptr-1);
136                 }
137                 break;
138     case PHOTOMETRIC_PALETTE :
139                 /* Read the TIFF cmap */
140                 if ( !TIFFGetField( handle, TIFFTAG_COLORMAP,
141                                     &rTIFFcmap, &gTIFFcmap, &bTIFFcmap ) )
142                   error( 9 );
143                 /* Allocate memory for our cmap and get it */
144                 ptr = image->cmap = (byte *) Malloc( 3 * image->colors );
145                 for ( i = 0; i < image->colors; i++ ) {
146                   *ptr++ = ( rTIFFcmap[i] >> 8 );
147                   *ptr++ = ( gTIFFcmap[i] >> 8 );
148                   *ptr++ = ( bTIFFcmap[i] >> 8 );
149                 }
150                 break;
151     case PHOTOMETRIC_RGB :
152                 break;
153     case PHOTOMETRIC_SEPARATED:
154                 if ( TIFFGetField( handle, TIFFTAG_INKSET, &iscmyk ) == 0 ) {
155                   if ( samplesperpixel == 4 ) {
156                     /*
157                      * Photoshop doesn't save the INKSET tag. So ... we hope
158                      * in a good CMYK's file if we have 4 samples per pixel.
159                      */
160                     VPRINTF( stderr, "Warning, cannot get the INKSET tag (possible further errors)\n" );
161                     iscmyk = 4;
162                   }else {
163                     VPRINTF( stderr, "A possible CMYK image without INKSET tag neither 4 samples per pixel\n" );
164                     error( 99 );
165                   }
166                 }else {
167                   if ( iscmyk != INKSET_CMYK ) {
168                     fprintf( stderr, "Separated Photometric image but not CMYK\n" );
169                     error( 99 );
170                    }
171                 }
172                 break;
173     default:
174                 fprintf( stderr, "Not supported photometric configuration\n");
175                 error( 99 );
176   }
177   if (  image->depth > 8 ) {
178     switch ( planarconfig ) {
179       case PLANARCONFIG_CONTIG   :
180                 break;
181       case PLANARCONFIG_SEPARATE :
182                 fprintf( stderr, "Separate planar configuration is not supported, yet.\n");
183                 error( 99 );
184                 break;
185       default:
186                 fprintf( stderr, "Unknown planar configuration\n");
187                 error( 99 );
188     }
189   }
190 
191 
192   /*
193    * Allocate memory for bitmap.
194    */
195   totalsize = (int) (xsize * ysize);
196   r = image->r = (byte *) Malloc( totalsize );
197   if ( image->depth > 8 ) {
198     /* A real RGB image */
199     g = image->g = (byte *) Malloc( totalsize );
200     b = image->b = (byte *) Malloc( totalsize );
201   }
202 
203   /*
204    * Get TIFF raster lines.
205    */
206   TIFFline = (byte *) Malloc( TIFFScanlineSize(handle) );
207   /*
208    * This ...if... could be done inside the loop but what we
209    * wanna is efficacy :-), so ...
210    */
211   if ( image->depth >= 8 ) {
212     /* We have a 'beatiful' raw image */
213     for ( i = 0; i < ysize; i++ ) {
214       TIFFReadScanline( handle, TIFFline, i, 0 );
215       if ( !iscmyk ) {
216         /* Great!, a RGB image :) */
217         for ( j = 0, ptr = TIFFline; j < xsize; j++ ) {
218           *r++ = *ptr++;
219           if ( image->depth > 8 ) {
220             *g++ = *ptr++;
221             *b++ = *ptr++;
222             if ( samplesperpixel == 4 ) {
223               /* Skip alpha channel */
224               ptr++;
225             }
226           }
227         }
228       }else {
229         /* Oooopss!, a CMYK image */
230         for ( j = 0, ptr = TIFFline; j < xsize; j++ ) {
231           c = 255 - *ptr++;
232           m = 255 - *ptr++;
233           y = 255 - *ptr++;
234           k = 255 - *ptr++;
235           *r++ = ((int)k*c/255);
236           *g++ = ((int)k*m/255);
237           *b++ = ((int)k*y/255);
238         }
239       }
240     }
241   }else {
242     /* Ooopss, we have packed bits */
243     int mask = ( 1 << bitspersample ) - 1;
244     int offset;
245 
246     for ( i = 0; i < ysize; i++ ) {
247       TIFFReadScanline( handle, TIFFline, i, 0 );
248       for ( j = 0, ptr = TIFFline, offset = 8 - bitspersample;
249             j < xsize;
250             j++, offset -= bitspersample) {
251         *r++ = (*ptr >> offset ) & mask;
252         if ( !offset ) {
253           offset = 8;
254           ptr++;
255         }
256       }
257     }
258   }
259 
260   /*
261    * Free our raster line and close the TIFF file.
262    */
263   free( TIFFline );
264   TIFFClose( handle );
265 }
266 
write_tiff_file(name,image)267 write_tiff_file( name, image )
268 char *name;
269 bitmap_hdr *image;
270 {
271   register int i, j;
272   TIFF *handle;
273   byte *r, *g, *b;
274   byte *buffer, *ptr;
275   long rows_per_strip;
276   int banks = (image->depth > 8 ? 3 : 1);
277   long xsize, ysize;
278   ushort *rTIFFcmap, *gTIFFcmap, *bTIFFcmap;
279 
280   if ( image->magic != LUGUSED )
281     error( 19 );
282 
283   VPRINTF( stderr, "Writting TIFF file\n" );
284   /*
285    * Open the TIFF file.
286    */
287   if ( name )
288     handle = TIFFOpen( name, "wb" );
289   else handle = TIFFFdOpen( 1, "stdout", "wb" );
290   if ( handle == NULL)
291     error( 1 );
292 
293   /*
294    * Configure the TIFF image.
295    */
296   xsize = image->xsize;
297   ysize = image->ysize;
298   TIFFSetField( handle,TIFFTAG_IMAGEWIDTH, xsize );
299   TIFFSetField( handle,TIFFTAG_IMAGELENGTH, ysize );
300   TIFFSetField( handle, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
301   TIFFSetField( handle, TIFFTAG_PREDICTOR, 2);
302   rows_per_strip = 16*1024 / (image->xsize);
303   if ( rows_per_strip < 1 )
304     rows_per_strip = 1;
305   TIFFSetField( handle, TIFFTAG_ROWSPERSTRIP, rows_per_strip);
306   TIFFSetField( handle, TIFFTAG_XRESOLUTION, 72.0 );
307   TIFFSetField( handle, TIFFTAG_YRESOLUTION, 72.0 );
308   TIFFSetField( handle, TIFFTAG_RESOLUTIONUNIT, 1 );
309   TIFFSetField( handle, TIFFTAG_BITSPERSAMPLE, 8 );
310   TIFFSetField( handle, TIFFTAG_SAMPLESPERPIXEL, banks );
311   TIFFSetField( handle, TIFFTAG_PLANARCONFIG, 1 );
312   if ( banks > 1 ) {
313     /*
314      * A true color image.
315      */
316     TIFFSetField( handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
317   }else {
318     /*
319      * If a mapped image, the we need build the cmap.
320      */
321     TIFFSetField( handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
322     rTIFFcmap = (ushort *) Malloc( sizeof(short) * 256 );
323     gTIFFcmap = (ushort *) Malloc( sizeof(short) * 256 );
324     bTIFFcmap = (ushort *) Malloc( sizeof(short) * 256 );
325     for ( i = 0, ptr = image->cmap; i < image->colors; i++ ) {
326       rTIFFcmap[i] = ( *ptr++ << 8 );
327       gTIFFcmap[i] = ( *ptr++ << 8 );
328       bTIFFcmap[i] = ( *ptr++ << 8 );
329     }
330     TIFFSetField( handle, TIFFTAG_COLORMAP, rTIFFcmap, gTIFFcmap, bTIFFcmap );
331   }
332 
333   /*
334    * Set pointers.
335    */
336   r = image->r;
337   if ( image->depth > 8 ) {
338     g = image->g;
339     b = image->b;
340   }
341   buffer = (byte *) Malloc( banks * image->xsize );
342 
343   /*
344    * Dump each line.
345    */
346   for ( i = 0; i < image->ysize; i++ ) {
347     /* TIFF library needs a RGBRGB...RGB raster line so ... */
348     for ( j = 0, ptr = buffer; j < image->xsize; j++ ) {
349       *ptr++ = *r++;
350       if ( banks > 1 ) {
351         *ptr++ = *g++;
352         *ptr++ = *b++;
353       }
354     }
355     TIFFWriteScanline( handle, buffer, i, 1);
356   }
357 
358   /*
359    * Close the TIFF file.
360    */
361   TIFFClose( handle );
362 
363   /*
364    * Free memory.
365    */
366   free( buffer );
367   if ( banks < 3 ) {
368     free( rTIFFcmap );
369     free( gTIFFcmap );
370     free( bTIFFcmap );
371   }
372   TIFFClose( handle );
373 }
374 
375 
376 #endif  /* iTIFF */
377