1 # include "bitmapConfig.h"
2
3 # include <stdlib.h>
4 # include "bmintern.h"
5 # include <appDebugon.h>
6
7 # if USE_LIBTIFF
8
9 # include <tiffio.h>
10
11 /************************************************************************/
12 /* */
13 /* Read a tiff file. */
14 /* */
15 /* 9) Allocate an extra byte as the libtiff fax 3 code scribbles */
16 /* beyond the end of the buffer. */
17 /* */
18 /************************************************************************/
19
bmReadTiffFile(const MemoryBuffer * filename,unsigned char ** pBuffer,BitmapDescription * bd,int * pPrivateFormat)20 int bmReadTiffFile( const MemoryBuffer * filename,
21 unsigned char ** pBuffer,
22 BitmapDescription * bd,
23 int * pPrivateFormat )
24 {
25 int rval= 0;
26
27 TIFF * t= (TIFF *)0;
28 unsigned int col;
29
30 unsigned char * buffer= (unsigned char *)0;
31 int fileFormat;
32
33 unsigned short photometric;
34 unsigned short bitsPerSample;
35 float resolution;
36
37 unsigned short unsignedShort;
38 unsigned short * whatKind;
39 unsigned long unsignedLong;
40
41 unsigned short * redMap= (unsigned short *)0;
42 unsigned short * greenMap= (unsigned short *)0;
43 unsigned short * blueMap= (unsigned short *)0;
44
45 unsigned short planarConfig= 1;
46
47 t= TIFFOpen( utilMemoryBufferGetString( filename ), "r" );
48 if ( ! t )
49 { XDEB(t); rval= -1; goto ready; }
50
51 if ( TIFFGetField( t, TIFFTAG_COMPRESSION, &unsignedShort ) != 1 )
52 { LDEB(TIFFTAG_COMPRESSION); rval= -1; goto ready; }
53 fileFormat= unsignedShort;
54
55 if ( TIFFGetField( t, TIFFTAG_IMAGEWIDTH, &unsignedLong ) != 1 )
56 { LDEB(TIFFTAG_IMAGEWIDTH); rval= -1; goto ready; }
57 bd->bdPixelsWide= unsignedLong;
58
59 if ( TIFFGetField( t, TIFFTAG_IMAGELENGTH, &unsignedLong ) != 1 )
60 { LDEB(TIFFTAG_IMAGELENGTH); rval= -1; goto ready; }
61 bd->bdPixelsHigh= unsignedLong;
62
63 if ( TIFFGetField( t, TIFFTAG_BITSPERSAMPLE, &bitsPerSample ) != 1 )
64 { LDEB(TIFFTAG_BITSPERSAMPLE); rval= -1; goto ready; }
65 if ( bitsPerSample > 8 )
66 { LDEB(bitsPerSample); return -1; }
67 bd->bdBitsPerSample= bitsPerSample;
68
69 if ( TIFFGetField( t, TIFFTAG_SAMPLESPERPIXEL, &unsignedShort ) != 1 )
70 { LDEB(TIFFTAG_SAMPLESPERPIXEL); rval= -1; goto ready; }
71 bd->bdSamplesPerPixel= unsignedShort;
72
73 if ( TIFFGetField( t, TIFFTAG_EXTRASAMPLES, &unsignedShort,
74 &whatKind ) != 1 )
75 { bd->bdHasAlpha= 0; }
76 else{
77 switch( unsignedShort )
78 {
79 case 0:
80 bd->bdHasAlpha= 0;
81 break;
82
83 case 1:
84 if ( whatKind[0] != EXTRASAMPLE_ASSOCALPHA &&
85 whatKind[0] != EXTRASAMPLE_UNASSALPHA )
86 { LLDEB(TIFFTAG_EXTRASAMPLES,whatKind[0]); return -1;}
87 bd->bdHasAlpha= 1;
88 break;
89
90 default:
91 LLDEB(TIFFTAG_EXTRASAMPLES,unsignedShort);
92 return -1;
93 }
94 }
95
96 if ( TIFFGetField( t, TIFFTAG_PHOTOMETRIC, &photometric ) != 1 )
97 { LDEB(TIFFTAG_PHOTOMETRIC); rval= -1; goto ready; }
98
99 switch( photometric )
100 {
101 case PHOTOMETRIC_MINISWHITE:
102 bd->bdColorEncoding= BMcoBLACKWHITE;
103 bd->bdBitsPerPixel= bd->bdBitsPerSample* bd->bdSamplesPerPixel;
104 break;
105
106 case PHOTOMETRIC_MINISBLACK:
107 bd->bdColorEncoding= BMcoWHITEBLACK;
108 bd->bdBitsPerPixel= bd->bdBitsPerSample* bd->bdSamplesPerPixel;
109 break;
110
111 case PHOTOMETRIC_RGB:
112 bd->bdColorEncoding= BMcoRGB;
113 bd->bdBitsPerPixel= bd->bdBitsPerSample* bd->bdSamplesPerPixel;
114 break;
115
116 case PHOTOMETRIC_PALETTE:
117 if ( TIFFGetField( t, TIFFTAG_COLORMAP,
118 &redMap, &greenMap, &blueMap ) != 1 )
119 { LDEB(TIFFTAG_COLORMAP); rval= -1; goto ready; }
120
121 if ( bd->bdHasAlpha )
122 {
123 if ( bd->bdSamplesPerPixel != 2 )
124 { LDEB(bd->bdSamplesPerPixel); rval= -1; goto ready; }
125 }
126 else{
127 if ( bd->bdSamplesPerPixel != 1 )
128 { LDEB(bd->bdSamplesPerPixel); rval= -1; goto ready; }
129 }
130
131 if ( utilPaletteSetCount( &(bd->bdPalette), 1 << bitsPerSample ) )
132 { LDEB(1 << bitsPerSample); rval= -1; goto ready; }
133
134 for ( col= 0; col < bd->bdPalette.cpColorCount; col++ )
135 {
136 bd->bdPalette.cpColors[col].rgb8Red= redMap[col]/256;
137 bd->bdPalette.cpColors[col].rgb8Green= greenMap[col]/256;
138 bd->bdPalette.cpColors[col].rgb8Blue= blueMap[col]/256;
139 }
140
141 bd->bdBitsPerSample= 8;
142 bd->bdColorEncoding= BMcoRGB8PALETTE;
143
144 if ( bd->bdHasAlpha )
145 {
146 bd->bdSamplesPerPixel= 4;
147 bd->bdBitsPerPixel= 2* bitsPerSample;
148 }
149 else{
150 bd->bdSamplesPerPixel= 3;
151 bd->bdBitsPerPixel= bitsPerSample;
152 }
153
154 break;
155 default:
156 LDEB(photometric); rval= -1; goto ready;
157 }
158
159 bd->bdBytesPerRow= ( bd->bdBitsPerPixel* bd->bdPixelsWide + 7 )/ 8;
160 bd->bdBufferLength= bd->bdBytesPerRow* bd->bdPixelsHigh;
161
162 if ( bd->bdSamplesPerPixel != 1 )
163 {
164 if ( TIFFGetField( t, TIFFTAG_PLANARCONFIG, &planarConfig ) != 1 )
165 { LDEB(TIFFTAG_PLANARCONFIG); rval= -1; goto ready; }
166 if ( planarConfig != 1 )
167 {
168 LLDEB(bd->bdSamplesPerPixel,planarConfig);
169 LLDEB(bd->bdBitsPerSample,bd->bdBitsPerPixel);
170 }
171 }
172
173 if ( TIFFGetField( t, TIFFTAG_RESOLUTIONUNIT, &unsignedShort ) != 1 )
174 {
175 /* SLDEB(filename,TIFFTAG_RESOLUTIONUNIT); */
176 bd->bdUnit= BMunPIXEL;
177 bd->bdXResolution= 1;
178 bd->bdYResolution= 1;
179 }
180 else{
181 switch( unsignedShort )
182 {
183 case RESUNIT_INCH:
184 bd->bdUnit= BMunINCH;
185 if ( TIFFGetField( t, TIFFTAG_XRESOLUTION, &resolution ) != 1 )
186 { LDEB(TIFFTAG_XRESOLUTION); rval= -1; goto ready; }
187 bd->bdXResolution= (int)resolution;
188 if ( TIFFGetField( t, TIFFTAG_YRESOLUTION, &resolution ) != 1 )
189 { LDEB(TIFFTAG_YRESOLUTION); rval= -1; goto ready; }
190 bd->bdYResolution= (int)resolution;
191 break;
192 case RESUNIT_CENTIMETER:
193 bd->bdUnit= BMunM;
194 if ( TIFFGetField( t, TIFFTAG_XRESOLUTION, &resolution ) != 1 )
195 { LDEB(TIFFTAG_XRESOLUTION); rval= -1; goto ready; }
196 bd->bdXResolution= (int)100* resolution;
197 if ( TIFFGetField( t, TIFFTAG_YRESOLUTION, &resolution ) != 1 )
198 { LDEB(TIFFTAG_YRESOLUTION); rval= -1; goto ready; }
199 bd->bdYResolution= 100* (int)resolution;
200 break;
201 case RESUNIT_NONE:
202 bd->bdUnit= BMunPIXEL;
203 if ( TIFFGetField( t, TIFFTAG_XRESOLUTION, &resolution ) != 1 )
204 { LDEB(TIFFTAG_XRESOLUTION); resolution= 1; }
205 bd->bdXResolution= (int)resolution;
206 if ( TIFFGetField( t, TIFFTAG_YRESOLUTION, &resolution ) != 1 )
207 { LDEB(TIFFTAG_YRESOLUTION); resolution= 1; }
208 bd->bdYResolution= (int)resolution;
209 break;
210 default:
211 LDEB(unsignedShort); rval= -1; goto ready;
212 }
213
214 if ( bd->bdXResolution == 0 ||
215 bd->bdYResolution == 0 )
216 {
217 LLDEB(bd->bdXResolution,bd->bdYResolution);
218 bd->bdUnit= BMunPIXEL;
219 bd->bdXResolution= 1;
220 bd->bdYResolution= 1;
221 }
222 }
223
224 /* 9 */
225 buffer= (unsigned char *)malloc( bd->bdBufferLength+ 1 );
226 if ( ! buffer )
227 { XDEB(buffer); rval= -1; goto ready; }
228
229 if ( bd->bdBitsPerPixel % 8 == 0 )
230 {
231 int offset= 0;
232 int strip= 0;
233
234 while( offset < bd->bdBufferLength )
235 {
236 int done;
237
238 done= TIFFReadEncodedStrip( t, strip, buffer+ offset,
239 bd->bdBufferLength- offset );
240 if ( done < 1 )
241 { LDEB(done); free( buffer ); TIFFClose( t ); return -1; }
242
243 offset += done; strip++;
244 }
245 }
246 else{
247 int row;
248
249 for ( row= 0; row < bd->bdPixelsHigh; row++ )
250 {
251 if ( TIFFReadScanline( t, buffer+ row* bd->bdBytesPerRow,
252 row, 0 ) < 0 )
253 { LDEB(row); free( buffer ); TIFFClose( t ); return -1; }
254 }
255 }
256
257 if ( planarConfig != 1 )
258 {
259 unsigned char * scratch;
260
261 scratch= (unsigned char *)malloc( bd->bdBufferLength+ 1 );
262 if ( ! scratch )
263 { XDEB(scratch); rval= -1; goto ready; }
264
265 if ( bmPlanarToChunky( scratch, buffer, bd ) )
266 { LDEB(1); free( scratch ); rval= -1; goto ready; }
267
268 free( buffer ); buffer= scratch;
269 }
270
271 *pBuffer= buffer; buffer= (unsigned char *)0; /* steal */
272 *pPrivateFormat= fileFormat;
273
274 ready:
275 if ( t )
276 { TIFFClose( t ); }
277 if ( buffer )
278 { free( buffer ); }
279
280 return rval;
281 }
282
283
bmCanWriteTiffFile(const BitmapDescription * bd,int privateFormat)284 int bmCanWriteTiffFile( const BitmapDescription * bd,
285 int privateFormat )
286 {
287 switch( privateFormat )
288 {
289 case COMPRESSION_NONE:
290 break;
291 case COMPRESSION_CCITTRLE:
292 case COMPRESSION_CCITTFAX3:
293 case COMPRESSION_CCITTFAX4:
294 if ( bd->bdBitsPerPixel == 1 )
295 { break; }
296 else{ return -1; }
297 case COMPRESSION_LZW:
298 return 0;
299 case COMPRESSION_JPEG:
300 if ( bd->bdBitsPerSample == 8 )
301 { break; }
302 else{ return -1; }
303 case COMPRESSION_NEXT:
304 return -1;
305 case COMPRESSION_CCITTRLEW:
306 case COMPRESSION_PACKBITS:
307 case COMPRESSION_THUNDERSCAN:
308 if ( bd->bdBitsPerPixel == 1 )
309 { break; }
310 else{ return -1; }
311 default:
312 LDEB(privateFormat); return -1;
313 }
314
315 switch( bd->bdColorEncoding )
316 {
317 case BMcoRGB8PALETTE:
318 switch( bd->bdBitsPerSample )
319 {
320 case 4:
321 case 8:
322 break;
323 default:
324 /* LDEB(bd->bdBitsPerSample); */ return -1;
325 }
326 break;
327 default:
328 break;
329 }
330
331 return 0;
332 }
333
334 /************************************************************************/
335 /* */
336 /* Write a bitmap to a TIFF file. */
337 /* */
338 /************************************************************************/
339
bmWriteTiffFile(const MemoryBuffer * filename,const unsigned char * buffer,const BitmapDescription * bd,int privateFormat)340 int bmWriteTiffFile( const MemoryBuffer * filename,
341 const unsigned char * buffer,
342 const BitmapDescription * bd,
343 int privateFormat )
344 {
345 TIFF * t;
346 int colorSpace= PHOTOMETRIC_MINISWHITE; /*bah*/
347 unsigned long rowsPerStrip;
348 int unit, xResolution, yResolution;
349 int row;
350 int i;
351
352 t= TIFFOpen( utilMemoryBufferGetString( filename ), "w" );
353 if ( ! t )
354 { XDEB(t); return -1; }
355
356 if ( ! TIFFSetField( t, TIFFTAG_COMPRESSION, privateFormat ) )
357 { LLDEB(TIFFTAG_COMPRESSION,privateFormat); return -1; }
358
359 if ( ! TIFFSetField( t, TIFFTAG_IMAGELENGTH, (long)bd->bdPixelsHigh ) )
360 { LLDEB(TIFFTAG_IMAGELENGTH,(long)bd->bdPixelsHigh); return -1; }
361
362 if ( ! TIFFSetField( t, TIFFTAG_IMAGEWIDTH, (long)bd->bdPixelsWide ) )
363 { LLDEB(TIFFTAG_IMAGEWIDTH,(long)bd->bdPixelsWide); return -1; }
364
365 switch( bd->bdColorEncoding )
366 {
367 case BMcoBLACKWHITE: colorSpace= PHOTOMETRIC_MINISWHITE;
368 break;
369 case BMcoWHITEBLACK: colorSpace= PHOTOMETRIC_MINISBLACK;
370 break;
371 case BMcoRGB: colorSpace= PHOTOMETRIC_RGB;
372 break;
373 case BMcoRGB8PALETTE: colorSpace= PHOTOMETRIC_PALETTE;
374 break;
375 default:
376 LDEB(bd->bdColorEncoding); return -1;
377 }
378
379 if ( ! TIFFSetField( t, TIFFTAG_PHOTOMETRIC, colorSpace ) )
380 { LLDEB(TIFFTAG_PHOTOMETRIC,colorSpace); return -1; }
381
382 if ( colorSpace == PHOTOMETRIC_PALETTE )
383 {
384 int colorCountOut;
385 int colorCountIn;
386 unsigned short * redMap;
387 unsigned short * greenMap;
388 unsigned short * blueMap;
389
390 switch( bd->bdBitsPerPixel )
391 {
392 case 1:
393 colorCountIn= 2;
394 colorCountOut= 16;
395 break;
396
397 case 2:
398 colorCountIn= 4;
399 colorCountOut= 16;
400 break;
401
402 case 4:
403 colorCountIn= 16;
404 colorCountOut= 16;
405 break;
406
407 case 8:
408 colorCountIn= 256;
409 colorCountOut= 256;
410 break;
411
412 case 16:
413 if ( bd->bdHasAlpha )
414 {
415 colorCountIn= 256;
416 colorCountOut= 256;
417 }
418 else{
419 LDEB(bd->bdHasAlpha);
420 LLDEB(bd->bdBitsPerPixel,bd->bdBitsPerSample); return -1;
421 }
422 break;
423
424 default:
425 LLDEB(bd->bdBitsPerPixel,bd->bdBitsPerSample); return -1;
426 }
427
428 if ( bd->bdPalette.cpColorCount > colorCountIn )
429 { LLDEB(bd->bdPalette.cpColorCount,colorCountIn); return -1; }
430
431 /*
432 if ( colorCountIn != colorCountOut )
433 { LLDEB(colorCountIn,colorCountOut); LDEB(bd->bdBitsPerPixel); }
434 */
435
436 redMap=
437 (unsigned short *)malloc( colorCountOut * sizeof(unsigned short) );
438 greenMap=
439 (unsigned short *)malloc( colorCountOut * sizeof(unsigned short) );
440 blueMap=
441 (unsigned short *)malloc( colorCountOut * sizeof(unsigned short) );
442
443 if ( ! redMap || ! greenMap || ! blueMap )
444 { LDEB(colorCountOut); return -1; }
445
446 for ( i= 0; i < bd->bdPalette.cpColorCount; i++ )
447 {
448 redMap[i]= 257* bd->bdPalette.cpColors[i].rgb8Red;
449 greenMap[i]= 257* bd->bdPalette.cpColors[i].rgb8Green;
450 blueMap[i]= 257* bd->bdPalette.cpColors[i].rgb8Blue;
451 }
452 for ( ; i < colorCountOut; i++ )
453 {
454 redMap[i]= redMap[i-1];
455 greenMap[i]= greenMap[i-1];
456 blueMap[i]= blueMap[i-1];
457 }
458
459 if ( bd->bdHasAlpha )
460 {
461 if ( ! TIFFSetField( t, TIFFTAG_BITSPERSAMPLE,
462 bd->bdBitsPerPixel/ 2 ) )
463 { LLDEB(TIFFTAG_BITSPERSAMPLE,bd->bdBitsPerSample); return -1; }
464 if ( ! TIFFSetField( t, TIFFTAG_SAMPLESPERPIXEL, 2 ) )
465 { LLDEB(TIFFTAG_SAMPLESPERPIXEL,1); TIFFClose(t); return -1; }
466 }
467 else{
468 if ( ! TIFFSetField( t, TIFFTAG_BITSPERSAMPLE,
469 bd->bdBitsPerPixel ) )
470 { LLDEB(TIFFTAG_BITSPERSAMPLE,bd->bdBitsPerSample); return -1; }
471 if ( ! TIFFSetField( t, TIFFTAG_SAMPLESPERPIXEL, 1 ) )
472 { LLDEB(TIFFTAG_SAMPLESPERPIXEL,1); TIFFClose(t); return -1; }
473 }
474
475 if ( TIFFSetField( t, TIFFTAG_COLORMAP,
476 redMap, greenMap, blueMap ) != 1 )
477 { LDEB(TIFFTAG_COLORMAP); TIFFClose(t); return -1; }
478
479 free( redMap ); free( greenMap ); free( blueMap );
480 }
481 else{
482 if ( ! TIFFSetField( t, TIFFTAG_BITSPERSAMPLE, bd->bdBitsPerSample ) )
483 { LLDEB(TIFFTAG_BITSPERSAMPLE,bd->bdBitsPerSample); return -1; }
484
485 if ( ! TIFFSetField( t, TIFFTAG_SAMPLESPERPIXEL,
486 bd->bdSamplesPerPixel ) )
487 { LLDEB(TIFFTAG_SAMPLESPERPIXEL,bd->bdSamplesPerPixel); return -1; }
488 }
489
490 if ( ! TIFFSetField( t, TIFFTAG_PLANARCONFIG, 1 ) )
491 { LLDEB(TIFFTAG_PLANARCONFIG,1); TIFFClose(t); return -1; }
492
493 /********************************/
494 /* To make PC's happy, make */
495 /* strips that are a little */
496 /* smaller than 64K. */
497 /* JPEG compression works per */
498 /* strip. It requires that the */
499 /* height of a strip be a */
500 /* multiple of 8. An attempt */
501 /* is made to combine these */
502 /* restrictions. */
503 /********************************/
504
505 rowsPerStrip= 65000/ bd->bdBytesPerRow;
506 if ( rowsPerStrip % 8 )
507 { rowsPerStrip= 8* ( rowsPerStrip/ 8 ); }
508 if ( rowsPerStrip < 1 )
509 { rowsPerStrip= 1; }
510
511 if ( ! TIFFSetField( t, TIFFTAG_ROWSPERSTRIP, rowsPerStrip ) )
512 { LLDEB(TIFFTAG_ROWSPERSTRIP,rowsPerStrip); TIFFClose(t); return -1; }
513
514 if ( bd->bdHasAlpha )
515 {
516 unsigned short value= EXTRASAMPLE_ASSOCALPHA;
517
518 if ( ! TIFFSetField( t, TIFFTAG_EXTRASAMPLES, 1, &value ) )
519 {
520 LLDEB(colorSpace,bd->bdSamplesPerPixel);
521 LLDEB(TIFFTAG_EXTRASAMPLES,bd->bdHasAlpha);
522 TIFFClose(t); return -1;
523 }
524 }
525
526 switch( bd->bdUnit )
527 {
528 case BMunM:
529 unit= RESUNIT_CENTIMETER;
530 xResolution= ( bd->bdXResolution+ 50 )/ 100;
531 yResolution= ( bd->bdYResolution+ 50 )/ 100;
532 break;
533
534 case BMunINCH:
535 unit= RESUNIT_INCH;
536 xResolution= bd->bdXResolution;
537 yResolution= bd->bdYResolution;
538 break;
539
540 case BMunPOINT:
541 unit= RESUNIT_INCH;
542 xResolution= bd->bdXResolution* 72;
543 yResolution= bd->bdYResolution* 72;
544 break;
545
546 case BMunPIXEL:
547 unit= RESUNIT_NONE;
548 xResolution= bd->bdXResolution;
549 yResolution= bd->bdYResolution;
550 break;
551
552 default:
553 LDEB(bd->bdUnit);
554 unit= RESUNIT_NONE;
555 xResolution= bd->bdXResolution;
556 yResolution= bd->bdYResolution;
557 break;
558 }
559
560 if ( ! TIFFSetField( t, TIFFTAG_RESOLUTIONUNIT, unit ) )
561 { LLDEB(TIFFTAG_RESOLUTIONUNIT, unit); return -1; }
562
563 if ( ! TIFFSetField( t, TIFFTAG_XRESOLUTION, (float)xResolution ) )
564 { LLDEB(TIFFTAG_XRESOLUTION, xResolution); return -1; }
565
566 if ( ! TIFFSetField( t, TIFFTAG_YRESOLUTION, (float)yResolution ) )
567 { LLDEB(TIFFTAG_YRESOLUTION, yResolution); return -1; }
568
569 if ( ! TIFFSetField( t, TIFFTAG_SOFTWARE, "appFrame:"
570 " Mark de Does,"
571 " mark@mdedoes.com" ) )
572 { LDEB(TIFFTAG_SOFTWARE); return -1; }
573
574 for ( row= 0; row < bd->bdPixelsHigh; row++ )
575 {
576 if ( TIFFWriteScanline( t, (char *) buffer+ row* bd->bdBytesPerRow,
577 row, 0 ) < 0 )
578 { LDEB(row); return -1; }
579 }
580
581 TIFFClose( t );
582
583 return 0;
584 }
585
586 # endif /* TIFF_FOUND */
587