1 /*
2 * tiff.c --
3 *
4 * A photo image file handler for TIFF files.
5 *
6 * Uses the libtiff.so library, which is dynamically
7 * loaded only when used.
8 */
9
10 /* Author : Jan Nijtmans */
11 /* Date : 7/16/97 */
12
13 /*
14 * Generic initialization code, parameterized via CPACKAGE and PACKAGE.
15 */
16
17 #ifdef _WIN32
18 # define HAVE_BOOLEAN
19 # include <Windows.h>
20 #endif
21 #include "tkimg.h"
22 #ifdef EXTERN
23 # undef EXTERN
24 #endif
25 #include <tiff.h>
26 #include <tiffio.h>
27 #include <zlib.h>
28
29 #ifdef HAVE_STDLIB_H
30 #undef HAVE_STDLIB_H
31 #endif
32 #include <jpeglib.h>
33
34 static int SetupTiffLibrary(Tcl_Interp *interp);
35
36 #define MORE_INITIALIZATION \
37 if (SetupTiffLibrary (interp) != TCL_OK) { return TCL_ERROR; }
38
39 #include "init.c"
40
41 #include "tiffInt.h"
42
43 /*
44 * Prototypes for local procedures defined in this file:
45 */
46
47 static int getint(unsigned char *buf, TIFFDataType format, int order);
48
49 static int CommonMatch(tkimg_MFile *handle, int *widhtPtr, int *heightPtr);
50
51 static int CommonRead(Tcl_Interp *interp, TIFF *tif,
52 Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY,
53 int width, int height, int srcX, int srcY);
54
55 static int CommonWrite(Tcl_Interp *interp, TIFF *tif,
56 int comp, Tk_PhotoImageBlock *blockPtr);
57
58 static int ParseWriteFormat(Tcl_Interp *interp, Tcl_Obj *format,
59 int *comp, const char **mode);
60
61 static void _TIFFerr(const char *, const char *, va_list);
62 static void _TIFFwarn(const char *, const char *, va_list);
63
64 /*
65 * The functions for the TIFF input handler
66 */
67
68 static int mapDummy(thandle_t, tdata_t *, toff_t *);
69 static void unMapDummy(thandle_t, tdata_t, toff_t);
70 static int closeDummy(thandle_t);
71 static tsize_t writeDummy(thandle_t, tdata_t, tsize_t);
72
73 static tsize_t readMFile(thandle_t, tdata_t, tsize_t);
74 static toff_t seekMFile(thandle_t, toff_t, int);
75 static toff_t sizeMFile(thandle_t);
76
77 static tsize_t readString(thandle_t, tdata_t, tsize_t);
78 static tsize_t writeString(thandle_t, tdata_t, tsize_t);
79 static toff_t seekString(thandle_t, toff_t, int);
80 static toff_t sizeString(thandle_t);
81
82 static char *errorMessage = NULL;
83
84 static int
SetupTiffLibrary(Tcl_Interp * interp)85 SetupTiffLibrary (Tcl_Interp *interp)
86 {
87 TIFFSetErrorHandler(_TIFFerr);
88 TIFFSetWarningHandler(_TIFFwarn);
89
90 return TCL_OK;
91 }
92
93 static int
getint(unsigned char * buf,TIFFDataType format,int order)94 getint(
95 unsigned char *buf,
96 TIFFDataType format,
97 int order
98 ) {
99 int result;
100
101 switch (format) {
102 case TIFF_BYTE:
103 result = buf[0]; break;
104 case TIFF_SHORT:
105 result = (buf[order]<<8) + buf[1-order]; break;
106 case TIFF_LONG:
107 if (order) {
108 result = (buf[3]<<24) + (buf[2]<<16) + (buf[1]<<8) + buf[0];
109 } else {
110 result = (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + buf[3];
111 }; break;
112 default:
113 result = -1;
114 }
115 return result;
116 }
117
118 static void
_TIFFerr(const char * module,const char * fmt,va_list ap)119 _TIFFerr(
120 const char *module,
121 const char *fmt,
122 va_list ap
123 ) {
124 char buf [2048];
125 char *cp = buf;
126
127 if (module != NULL) {
128 sprintf(cp, "%s: ", module);
129 cp += strlen(module) + 2;
130 }
131
132 vsprintf(cp, fmt, ap);
133 if (errorMessage) {
134 ckfree(errorMessage);
135 }
136 if (strstr(buf, "Null count for")) {
137 return;
138 }
139 errorMessage = (char *) ckalloc(strlen(buf)+1);
140 strcpy(errorMessage, buf);
141 }
142
143 /* warnings are not processed in Tcl */
144 static void
_TIFFwarn(const char * module,const char * fmt,va_list ap)145 _TIFFwarn(
146 const char *module,
147 const char *fmt,
148 va_list ap
149 ) {
150 }
151
152 static int
mapDummy(thandle_t fd,tdata_t * base,toff_t * size)153 mapDummy(
154 thandle_t fd,
155 tdata_t *base,
156 toff_t *size
157 ) {
158 return (toff_t) 0;
159 }
160
161 static void
unMapDummy(thandle_t fd,tdata_t base,toff_t size)162 unMapDummy(
163 thandle_t fd,
164 tdata_t base,
165 toff_t size
166 ) {
167 }
168
169 static int
closeDummy(thandle_t fd)170 closeDummy(thandle_t fd)
171 {
172 return 0;
173 }
174
175 static tsize_t
writeDummy(thandle_t fd,tdata_t data,tsize_t size)176 writeDummy(
177 thandle_t fd,
178 tdata_t data,
179 tsize_t size
180 ) {
181 return size;
182 }
183
184 static tsize_t
readMFile(thandle_t fd,tdata_t data,tsize_t size)185 readMFile(
186 thandle_t fd,
187 tdata_t data,
188 tsize_t size
189 ) {
190 return (tsize_t) tkimg_Read2((tkimg_MFile *) fd, (char *) data, size) ;
191 }
192
193 static toff_t
seekMFile(thandle_t fd,toff_t off,int whence)194 seekMFile(
195 thandle_t fd,
196 toff_t off,
197 int whence
198 ) {
199 return Tcl_Seek((Tcl_Channel) ((tkimg_MFile *) fd)->data, (int) off, whence);
200 }
201
202 static toff_t
sizeMFile(thandle_t fd)203 sizeMFile(thandle_t fd)
204 {
205 int fsize;
206 return (fsize = Tcl_Seek((Tcl_Channel) ((tkimg_MFile *) fd)->data,
207 (int) 0, SEEK_END)) < 0 ? 0 : (toff_t) fsize;
208 }
209
210 /*
211 * In the following functions "handle" is used differently for speed reasons:
212 *
213 * handle.buffer (writing only) dstring used for writing.
214 * handle.data pointer to first character
215 * handle.length size of data
216 * handle.state "file" position pointer.
217 *
218 * After a read, only the position pointer is adapted, not the other fields.
219 */
220
221 static tsize_t
readString(thandle_t fd,tdata_t data,tsize_t size)222 readString(
223 thandle_t fd,
224 tdata_t data,
225 tsize_t size
226 ) {
227 tkimg_MFile *handle = (tkimg_MFile *) fd;
228
229 if (((size_t)size + handle->state) > handle->length) {
230 size = handle->length - handle->state;
231 }
232 if (size) {
233 memcpy((char *) data, handle->data + handle->state, (size_t) size);
234 handle->state += size;
235 }
236 return size;
237 }
238
239 static tsize_t
writeString(thandle_t fd,tdata_t data,tsize_t size)240 writeString(
241 thandle_t fd,
242 tdata_t data,
243 tsize_t size
244 ) {
245 tkimg_MFile *handle = (tkimg_MFile *) fd;
246
247 if (handle->state + (size_t)size > handle->length) {
248 handle->length = handle->state + size;
249 Tcl_DStringSetLength(handle->buffer, handle->length);
250 handle->data = Tcl_DStringValue(handle->buffer);
251 }
252 memcpy(handle->data + handle->state, (char *) data, (size_t) size);
253 handle->state += size;
254 return size;
255 }
256
257 static toff_t
seekString(thandle_t fd,toff_t off,int whence)258 seekString(
259 thandle_t fd,
260 toff_t off,
261 int whence
262 ) {
263 tkimg_MFile *handle = (tkimg_MFile *) fd;
264
265 switch (whence) {
266 case SEEK_SET:
267 handle->state = (int) off;
268 break;
269 case SEEK_CUR:
270 handle->state += (int) off;
271 break;
272 case SEEK_END:
273 handle->state = handle->length + (int) off;
274 break;
275 }
276 if (handle->state < 0) {
277 handle->state = 0;
278 return -1;
279 }
280 return (toff_t) handle->state;
281 }
282
283 static toff_t
sizeString(thandle_t fd)284 sizeString(thandle_t fd)
285 {
286 return ((tkimg_MFile *) fd)->length;
287 }
288
289
290 /*
291 *----------------------------------------------------------------------
292 *
293 * ObjMatchTIFF --
294 *
295 * This procedure is invoked by the photo image type to see if
296 * a string contains image data in TIFF format.
297 *
298 * Results:
299 * The return value is 1 if the first characters in the string
300 * is like TIFF data, and 0 otherwise.
301 *
302 * Side effects:
303 * the size of the image is placed in widthPre and heightPtr.
304 *
305 *----------------------------------------------------------------------
306 */
307
308 static int
ObjMatch(Tcl_Obj * data,Tcl_Obj * format,int * widthPtr,int * heightPtr,Tcl_Interp * interp)309 ObjMatch(
310 Tcl_Obj *data, /* the object containing the image data */
311 Tcl_Obj *format, /* the image format string */
312 int *widthPtr, /* where to put the string width */
313 int *heightPtr, /* where to put the string height */
314 Tcl_Interp *interp
315 ) {
316 tkimg_MFile handle;
317
318 if (!tkimg_ReadInit(data, '\111', &handle) &&
319 !tkimg_ReadInit(data, '\115', &handle)) {
320 return 0;
321 }
322
323 return CommonMatch(&handle, widthPtr, heightPtr);
324 }
325
ChnMatch(Tcl_Channel chan,const char * fileName,Tcl_Obj * format,int * widthPtr,int * heightPtr,Tcl_Interp * interp)326 static int ChnMatch(
327 Tcl_Channel chan,
328 const char *fileName,
329 Tcl_Obj *format,
330 int *widthPtr,
331 int *heightPtr,
332 Tcl_Interp *interp
333 ) {
334 tkimg_MFile handle;
335
336 handle.data = (char *) chan;
337 handle.state = IMG_CHAN;
338
339 return CommonMatch(&handle, widthPtr, heightPtr);
340 }
341
342 static int
CommonMatch(tkimg_MFile * handle,int * widthPtr,int * heightPtr)343 CommonMatch(
344 tkimg_MFile *handle,
345 int *widthPtr, int *heightPtr
346 ) {
347 unsigned char buf[4096];
348 int i, j, order, w = 0, h = 0;
349
350 i = tkimg_Read2(handle, (char *) buf, 8);
351 order = (buf[0] == '\111');
352 if ((i != 8) || (buf[0] != buf[1])
353 || ((buf[0] != '\111') && (buf[0] != '\115'))
354 || (getint(buf+2,TIFF_SHORT,order) != 42)) {
355 return 0;
356 }
357 i = getint(buf+4,TIFF_LONG,order);
358
359 while (i > 4104) {
360 i -= 4096;
361 tkimg_Read2(handle, (char *) buf, 4096);
362 }
363 if (i>8) {
364 tkimg_Read2(handle, (char *) buf, i-8);
365 }
366 tkimg_Read2(handle, (char *) buf, 2);
367 i = getint(buf,TIFF_SHORT,order);
368 while (i--) {
369 tkimg_Read2(handle, (char *) buf, 12);
370 if (buf[order]!=1) continue;
371 j = getint(buf+2,TIFF_SHORT,order);
372 j = getint(buf+8, (TIFFDataType) j, order);
373 if (buf[1-order]==0) {
374 w = j;
375 if (h>0) break;
376 } else if (buf[1-order]==1) {
377 h = j;
378 if (w>0) break;
379 }
380 }
381
382 if ((w <= 0) || (h <= 0)) {
383 return 0;
384 }
385 *widthPtr = w;
386 *heightPtr = h;
387 return 1;
388 }
389
390 static int
ObjRead(Tcl_Interp * interp,Tcl_Obj * data,Tcl_Obj * format,Tk_PhotoHandle imageHandle,int destX,int destY,int width,int height,int srcX,int srcY)391 ObjRead(
392 Tcl_Interp *interp,
393 Tcl_Obj *data, /* object containing the image */
394 Tcl_Obj *format,
395 Tk_PhotoHandle imageHandle,
396 int destX, int destY,
397 int width, int height,
398 int srcX, int srcY
399 ) {
400 TIFF *tif;
401 int result;
402 tkimg_MFile handle;
403 char *dataPtr = NULL;
404
405 if (!tkimg_ReadInit(data, '\115', &handle)) {
406 tkimg_ReadInit(data, '\111', &handle);
407 }
408
409 if (handle.state != IMG_STRING) {
410 dataPtr = ckalloc((handle.length*3)/4 + 2);
411 handle.length = tkimg_Read2(&handle, dataPtr, handle.length);
412 handle.data = dataPtr;
413 }
414 handle.state = 0;
415 tif = TIFFClientOpen("inline data", "r", (thandle_t) &handle,
416 readString, writeString, seekString, closeDummy,
417 sizeString, mapDummy, unMapDummy);
418
419 if (tif != NULL) {
420 result = CommonRead(interp, tif, format, imageHandle,
421 destX, destY, width, height, srcX, srcY);
422 } else {
423 result = TCL_ERROR;
424 }
425 if (result == TCL_ERROR) {
426 Tcl_AppendResult(interp, errorMessage, (char *) NULL);
427 ckfree(errorMessage);
428 errorMessage = NULL;
429 }
430 if (dataPtr) {
431 ckfree(dataPtr);
432 }
433 return result;
434 }
435
436 static int
ChnRead(Tcl_Interp * interp,Tcl_Channel chan,const char * fileName,Tcl_Obj * format,Tk_PhotoHandle imageHandle,int destX,int destY,int width,int height,int srcX,int srcY)437 ChnRead(
438 Tcl_Interp *interp,
439 Tcl_Channel chan,
440 const char *fileName,
441 Tcl_Obj *format,
442 Tk_PhotoHandle imageHandle,
443 int destX, int destY,
444 int width, int height,
445 int srcX, int srcY
446 ) {
447 TIFF *tif;
448 int result;
449
450 tkimg_MFile handle;
451 handle.data = (char *) chan;
452 handle.state = IMG_CHAN;
453 tif = TIFFClientOpen(fileName, "r", (thandle_t) &handle,
454 readMFile, writeDummy, seekMFile, closeDummy,
455 sizeMFile, mapDummy, unMapDummy);
456
457 if (tif) {
458 result = CommonRead(interp, tif, format, imageHandle,
459 destX, destY, width, height, srcX, srcY);
460 } else {
461 result = TCL_ERROR;
462 }
463 if (result == TCL_ERROR) {
464 Tcl_AppendResult(interp, errorMessage, (char *) NULL);
465 ckfree(errorMessage);
466 errorMessage = 0;
467 }
468 return result;
469 }
470
471 static int
CommonRead(Tcl_Interp * interp,TIFF * tif,Tcl_Obj * format,Tk_PhotoHandle imageHandle,int destX,int destY,int width,int height,int srcX,int srcY)472 CommonRead(
473 Tcl_Interp *interp,
474 TIFF *tif,
475 Tcl_Obj *format,
476 Tk_PhotoHandle imageHandle,
477 int destX, int destY,
478 int width, int height,
479 int srcX, int srcY
480 ) {
481 Tk_PhotoImageBlock block;
482 uint32 w, h;
483 size_t npixels;
484 uint32 *raster;
485 int result = TCL_OK;
486 int nBytes, index = 0, objc = 0;
487 Tcl_Obj **objv = NULL;
488
489 if (tkimg_ListObjGetElements(interp, format, &objc, &objv) != TCL_OK) {
490 return TCL_ERROR;
491 }
492 if (objc > 1) {
493 char *c = Tcl_GetStringFromObj(objv[1], &nBytes);
494 if ((objc > 3) || ((objc == 3) && ((c[0] != '-') ||
495 (c[1] != 'i') || strncmp(c, "-index", strlen(c))))) {
496 Tcl_AppendResult(interp, "invalid format: \"",
497 tkimg_GetStringFromObj2(format, NULL), "\"", (char *) NULL);
498 return TCL_ERROR;
499 }
500 if (Tcl_GetIntFromObj(interp, objv[objc-1], &index) != TCL_OK) {
501 return TCL_ERROR;
502 }
503 }
504 while (index-- != 0) {
505 if (TIFFReadDirectory(tif) != 1) {
506 Tcl_AppendResult(interp,"no image data for this index",
507 (char *) NULL);
508 return TCL_ERROR;
509 }
510 }
511 #ifdef WORDS_BIGENDIAN
512 block.offset[0] = 3;
513 block.offset[1] = 2;
514 block.offset[2] = 1;
515 block.offset[3] = 0;
516 #else
517 block.offset[0] = 0;
518 block.offset[1] = 1;
519 block.offset[2] = 2;
520 block.offset[3] = 3;
521 #endif
522 block.pixelSize = sizeof (uint32);
523
524 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
525 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
526 npixels = w * h;
527
528 raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
529 block.width = w;
530 block.height = h;
531 block.pitch = - (block.pixelSize * (int) w);
532 block.pixelPtr = ((unsigned char *) raster) + ((1-h) * block.pitch);
533 if (raster == NULL) {
534 printf("cannot malloc\n");
535 return TCL_ERROR;
536 }
537
538 if (!TIFFReadRGBAImage(tif, w, h, raster, 0) || errorMessage) {
539 _TIFFfree (raster);
540 if (errorMessage) {
541 Tcl_AppendResult(interp, errorMessage, (char *) NULL);
542 ckfree(errorMessage);
543 errorMessage = NULL;
544 }
545 return TCL_ERROR;
546 }
547
548 block.pixelPtr += srcY * block.pitch + srcX * block.pixelSize;
549 block.offset[3] = block.offset[0]; /* don't use transparency */
550 if (tkimg_PhotoPutBlock(interp, imageHandle, &block, destX,
551 destY, width, height, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) {
552 result = TCL_ERROR;
553 }
554
555 _TIFFfree (raster);
556 TIFFClose(tif);
557 return result;
558 }
559
StringWrite(Tcl_Interp * interp,Tcl_Obj * format,Tk_PhotoImageBlock * blockPtr)560 static int StringWrite(
561 Tcl_Interp *interp,
562 Tcl_Obj *format,
563 Tk_PhotoImageBlock *blockPtr
564 ) {
565 TIFF *tif;
566 int result, comp;
567 tkimg_MFile handle;
568 Tcl_DString dstring;
569 const char *mode;
570 Tcl_DString data;
571
572 Tcl_DStringInit(&data);
573 if (ParseWriteFormat(interp, format, &comp, &mode) != TCL_OK) {
574 return TCL_ERROR;
575 }
576
577 Tcl_DStringInit(&dstring);
578 tkimg_WriteInit(&dstring, &handle);
579 tif = TIFFClientOpen("inline data", mode, (thandle_t) &handle,
580 readString, writeString, seekString, closeDummy,
581 sizeString, mapDummy, unMapDummy);
582
583 result = CommonWrite(interp, tif, comp, blockPtr);
584 TIFFClose(tif);
585
586 if (result != TCL_OK) {
587 Tcl_AppendResult(interp, errorMessage, (char *) NULL);
588 ckfree(errorMessage);
589 errorMessage = NULL;
590 return TCL_ERROR;
591 }
592
593 int length = handle.length;
594 tkimg_WriteInit(&data, &handle);
595 tkimg_Write2(&handle, Tcl_DStringValue(&dstring), length);
596 Tcl_DStringFree(&dstring);
597
598 tkimg_Putc(IMG_DONE, &handle);
599 Tcl_DStringResult(interp, &data);
600
601 return TCL_OK;
602 }
603
604 static int
ChnWrite(Tcl_Interp * interp,const char * filename,Tcl_Obj * format,Tk_PhotoImageBlock * blockPtr)605 ChnWrite(
606 Tcl_Interp *interp,
607 const char *filename,
608 Tcl_Obj *format,
609 Tk_PhotoImageBlock *blockPtr
610 ) {
611 TIFF *tif;
612 int result, comp;
613 Tcl_DString nameBuffer;
614 const char *fullname, *mode;
615
616 if (!(fullname=Tcl_TranslateFileName(interp, filename, &nameBuffer))) {
617 return TCL_ERROR;
618 }
619
620 if (ParseWriteFormat(interp, format, &comp, &mode) != TCL_OK) {
621 Tcl_DStringFree(&nameBuffer);
622 return TCL_ERROR;
623 }
624
625 if (!(tif = TIFFOpen(fullname, mode))) {
626 Tcl_AppendResult(interp, filename, ": ", Tcl_PosixError(interp),
627 (char *)NULL);
628 Tcl_DStringFree(&nameBuffer);
629 return TCL_ERROR;
630 }
631
632 Tcl_DStringFree(&nameBuffer);
633
634 result = CommonWrite(interp, tif, comp, blockPtr);
635 TIFFClose(tif);
636 return result;
637 }
638
639 static int
ParseWriteFormat(Tcl_Interp * interp,Tcl_Obj * format,int * comp,const char ** mode)640 ParseWriteFormat(
641 Tcl_Interp *interp,
642 Tcl_Obj *format,
643 int *comp,
644 const char **mode
645 ) {
646 static const char *const tiffWriteOptions[] = {
647 "-compression",
648 "-byteorder",
649 NULL
650 };
651 int objc, length, c, i, index;
652 Tcl_Obj **objv;
653 const char *compression, *byteorder;
654
655 *comp = COMPRESSION_NONE;
656 *mode = "w";
657 if (tkimg_ListObjGetElements(interp, format, &objc, &objv) != TCL_OK)
658 return TCL_ERROR;
659 if (objc) {
660 compression = "none";
661 byteorder = "";
662 for (i=1; i<objc; i++) {
663 if (Tcl_GetIndexFromObj(interp, objv[i], (const char *CONST86 *)tiffWriteOptions,
664 "format option", 0, &index) !=TCL_OK) {
665 return TCL_ERROR;
666 }
667 if (++i >= objc) {
668 Tcl_AppendResult(interp, "No value for option \"",
669 Tcl_GetStringFromObj(objv[--i], (int *) NULL),
670 "\"", (char *) NULL);
671 return TCL_ERROR;
672 }
673 switch(index) {
674 case 0:
675 compression = Tcl_GetStringFromObj(objv[i], (int *) NULL); break;
676 case 1:
677 byteorder = Tcl_GetStringFromObj(objv[i], (int *) NULL); break;
678 }
679 }
680 c = compression[0]; length = strlen(compression);
681 if ((c == 'n') && (!strncmp(compression, "none", length))) {
682 *comp = COMPRESSION_NONE;
683 } else if ((c == 'd') && (!strncmp(compression, "deflate", length))) {
684 *comp = COMPRESSION_DEFLATE;
685 } else if ((c == 'j') && (!strncmp(compression, "jpeg", length))) {
686 *comp = COMPRESSION_JPEG;
687 } else if ((c == 'l') && (length>1) && (!strncmp(compression, "logluv", length))) {
688 *comp = COMPRESSION_SGILOG;
689 } else if ((c == 'l') && (length>1) && (!strncmp(compression, "lzw", length))) {
690 *comp = COMPRESSION_LZW;
691 } else if ((c == 'p') && (length>1) && (!strncmp(compression, "packbits", length))) {
692 *comp = COMPRESSION_PACKBITS;
693 } else if ((c == 'p') && (length>1) && (!strncmp(compression, "pixarlog", length))) {
694 *comp = COMPRESSION_PIXARLOG;
695 } else {
696 Tcl_AppendResult(interp, "invalid compression mode \"",
697 compression,"\": should be deflate, jpeg, logluv, lzw, ",
698 "packbits, pixarlog, or none", (char *) NULL);
699 return TCL_ERROR;
700 }
701 c = byteorder[0]; length = strlen(byteorder);
702 if (c == 0 || ((c == 'n') && (!strncmp(byteorder, "none", length)))) {
703 *mode = "w";
704 } else if ((c == 's') && (!strncmp(byteorder, "smallendian", length))) {
705 *mode = "wl";
706 } else if ((c == 'l') && (!strncmp(byteorder, "littleendian", length))) {
707 *mode = "wl";
708 } else if ((c == 'b') && (!strncmp(byteorder, "bigendian", length))) {
709 *mode = "wb";
710 } else if ((c == 'n') && (!strncmp(byteorder, "network", length))) {
711 *mode = "wb";
712 } else {
713 Tcl_AppendResult(interp, "invalid byteorder \"",
714 byteorder,"\": should be bigendian, littleendian, ",
715 "network, smallendian, or none", (char *) NULL);
716 return TCL_ERROR;
717 }
718 }
719 return TCL_OK;
720 }
721
722 static int
CommonWrite(Tcl_Interp * interp,TIFF * tif,int comp,Tk_PhotoImageBlock * blockPtr)723 CommonWrite(
724 Tcl_Interp *interp,
725 TIFF *tif,
726 int comp,
727 Tk_PhotoImageBlock *blockPtr
728 ) {
729 int numsamples;
730 unsigned char *data = NULL;
731
732 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, blockPtr->width);
733 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, blockPtr->height);
734 TIFFSetField(tif, TIFFTAG_COMPRESSION, comp);
735
736 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
737 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
738 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
739 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, blockPtr->height);
740
741 TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (int)2);
742 TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)1200.0);
743 TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)1200.0);
744
745 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
746 if ((blockPtr->offset[0] == blockPtr->offset[1])
747 && (blockPtr->offset[0] == blockPtr->offset[2])) {
748 numsamples = 1;
749 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
750 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
751 } else {
752 numsamples = 3;
753 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
754 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
755 }
756
757 if ((blockPtr->pitch == numsamples * blockPtr->width)
758 && (blockPtr->pixelSize == numsamples)) {
759 data = blockPtr->pixelPtr;
760 } else {
761 unsigned char *srcPtr, *dstPtr, *rowPtr;
762 int greenOffset, blueOffset, alphaOffset, x, y;
763 dstPtr = data = (unsigned char *) ckalloc(numsamples *
764 blockPtr->width * blockPtr->height);
765 rowPtr = blockPtr->pixelPtr + blockPtr->offset[0];
766 greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
767 blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
768 alphaOffset = blockPtr->offset[0];
769 if (alphaOffset < blockPtr->offset[2]) {
770 alphaOffset = blockPtr->offset[2];
771 }
772 if (++alphaOffset < blockPtr->pixelSize) {
773 alphaOffset -= blockPtr->offset[0];
774 } else {
775 alphaOffset = 0;
776 }
777 if (blueOffset || greenOffset) {
778 for (y = blockPtr->height; y > 0; y--) {
779 srcPtr = rowPtr;
780 for (x = blockPtr->width; x>0; x--) {
781 if (alphaOffset && !srcPtr[alphaOffset]) {
782 *dstPtr++ = 0xd9;
783 *dstPtr++ = 0xd9;
784 *dstPtr++ = 0xd9;
785 } else {
786 *dstPtr++ = srcPtr[0];
787 *dstPtr++ = srcPtr[greenOffset];
788 *dstPtr++ = srcPtr[blueOffset];
789 }
790 srcPtr += blockPtr->pixelSize;
791 }
792 rowPtr += blockPtr->pitch;
793 }
794 } else {
795 for (y = blockPtr->height; y > 0; y--) {
796 srcPtr = rowPtr;
797 for (x = blockPtr->width; x>0; x--) {
798 *dstPtr++ = srcPtr[0];
799 srcPtr += blockPtr->pixelSize;
800 }
801 rowPtr += blockPtr->pitch;
802 }
803 }
804 }
805
806 TIFFWriteEncodedStrip(tif, 0, data,
807 numsamples * blockPtr->width * blockPtr->height);
808 if (data != blockPtr->pixelPtr) {
809 ckfree((char *) data);
810 }
811
812 return TCL_OK;
813 }
814
815 void
TkimgTIFFfree(tdata_t data)816 TkimgTIFFfree(tdata_t data)
817 {
818 _TIFFfree(data);
819 }
820
821 tdata_t
TkimgTIFFmalloc(tsize_t size)822 TkimgTIFFmalloc(tsize_t size)
823 {
824 return _TIFFmalloc(size);
825 }
826
827 tdata_t
TkimgTIFFrealloc(tdata_t data,tsize_t size)828 TkimgTIFFrealloc(
829 tdata_t data,
830 tsize_t size
831 ) {
832 return _TIFFrealloc(data, size);
833 }
834