1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /*  Grafx2 - The Ultimate 256-color bitmap paint program
4 
5 	Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6 
7     Grafx2 is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; version 2
10     of the License.
11 
12     Grafx2 is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20 
21 ///@file tifformat.c
22 /// Support of TIFF
23 ///
24 
25 #ifndef __no_tifflib__
26 
27 #ifdef _MSC_VER
28 #include <stdio.h>
29 #if _MSC_VER < 1900
30 #define snprintf _snprintf
31 #define fileno _fileno
32 #endif
33 #endif
34 #include <string.h>
35 #include <stdlib.h>
36 #include <tiffio.h>
37 #include "global.h"
38 #include "io.h"
39 #include "loadsave.h"
40 #include "loadsavefuncs.h"
41 #include "gfx2log.h"
42 
43 /**
44  * @defgroup TIFF TIFF
45  * @ingroup loadsaveformats
46  * Tagged Image File Format
47  *
48  * Uses libtiff http://www.simplesystems.org/libtiff/
49  *
50  * @{
51  */
52 
53 /// GrafX2 private TIFF tag : 4 bytes
54 ///
55 /// - bkg/transp color
56 /// - background transparent
57 /// - image mode
58 /// - reserved (0)
59 ///
60 /// This TAG is read only if the Software tag begins with "GrafX2"
61 #define TIFFTAG_GRAFX2 65500
62 
63 extern char Program_version[]; // generated in pversion.c
64 extern const char SVN_revision[]; // generated in version.c
65 
66 
TIFF_LogError(const char * module,const char * fmt,va_list ap)67 static void TIFF_LogError(const char* module, const char* fmt, va_list ap)
68 {
69   char format[256];
70   snprintf(format, sizeof(format), "%s: %s\n", module, fmt);
71   GFX2_LogV(GFX2_ERROR, format, ap);
72 }
73 
TIFF_LogWarning(const char * module,const char * fmt,va_list ap)74 static void TIFF_LogWarning(const char* module, const char* fmt, va_list ap)
75 {
76   char format[256];
77   snprintf(format, sizeof(format), "%s: %s\n", module, fmt);
78   GFX2_LogV(GFX2_WARNING, format, ap);
79 }
80 
81 /// old TIFF extender procedure to be recursively called
82 static TIFFExtendProc TIFFParentExtender = NULL;
83 
84 /// Our TIFF Tag Extender procedure
85 ///
86 /// Used to add ::TIFFTAG_GRAFX2 handling
GFX2_TIFFTagExtender(TIFF * tif)87 static void GFX2_TIFFTagExtender(TIFF *tif)
88 {
89   static const TIFFFieldInfo gfx2_fields[] = {
90     // 4 bytes
91     {TIFFTAG_GRAFX2, 4, 4, TIFF_BYTE, FIELD_CUSTOM, 1, 0, "GrafX2Private"}
92   };
93   TIFFMergeFieldInfo(tif, gfx2_fields, 1);
94   if (TIFFParentExtender != NULL)
95     (*TIFFParentExtender)(tif);
96 }
97 
98 /// Initialisation for using the TIFF library
TIFF_Init(void)99 static void TIFF_Init(void)
100 {
101   static int init_done = 0;
102 
103   if (init_done)
104     return;
105 
106   /// use TIFFSetErrorHandler() and TIFFSetWarningHandler() to
107   /// redirect warning/error output to our own functions
108   TIFFSetErrorHandler(TIFF_LogError);
109   TIFFSetWarningHandler(TIFF_LogWarning);
110   TIFFParentExtender = TIFFSetTagExtender(GFX2_TIFFTagExtender);
111   GFX2_Log(GFX2_DEBUG, "TIFF_Init() TIFFParentExtender=%p\n", TIFFParentExtender);
112 
113   init_done = 1;
114 }
115 
116 /// test for a valid TIFF
Test_TIFF(T_IO_Context * context,FILE * file)117 void Test_TIFF(T_IO_Context * context, FILE * file)
118 {
119   char buffer[4];
120 
121   (void)context;
122   File_error = 1;
123   if (!Read_bytes(file, buffer, 4))
124     return;
125   if (0 == memcmp(buffer, "MM\0*", 4) || 0 == memcmp(buffer, "II*\0", 4))
126     File_error = 0;
127 }
128 
129 /// Load current image in TIFF
Load_TIFF_image(T_IO_Context * context,TIFF * tif,word spp,word bps)130 static void Load_TIFF_image(T_IO_Context * context, TIFF * tif, word spp, word bps)
131 {
132   tsize_t size;
133   int x, y;
134   unsigned int i, j;
135 
136   if (TIFFIsTiled(tif))
137   {
138     // Tiled image
139     dword tile_width, tile_height;
140     if (!TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) || !TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height))
141     {
142       File_error = 2;
143       return;
144     }
145     if (spp > 1 || bps > 8)
146     {
147       dword * buffer;
148       dword x2, y2;
149 
150       buffer = malloc(sizeof(dword) * tile_width * tile_height);
151       for (y = 0; y < context->Height; y += tile_height)
152       {
153         for (x = 0; x < context->Width; x += tile_width)
154         {
155           if (!TIFFReadRGBATile(tif, x, y, buffer))
156           {
157             free(buffer);
158             File_error = 2;
159             return;
160           }
161           j = 0;
162           // Note that the raster is assume to be organized such that the pixel at
163           // location (x,y) is raster[y*width+x]; with the raster origin in the
164           // lower-left hand corner of the tile. That is bottom to top organization.
165           // Edge tiles which partly fall off the image will be filled out with
166           // appropriate zeroed areas.
167           for (y2 = 0; y2 < tile_height; y2++)
168           {
169             int y_pos = y + tile_height - 1 - y2;
170             for (x2 = 0; x2 < tile_width ; x2++)
171             {
172               Set_pixel_24b(context, x + x2, y_pos, TIFFGetR(buffer[j]), TIFFGetG(buffer[j]), TIFFGetB(buffer[j]));
173               j++;
174             }
175           }
176         }
177       }
178       free(buffer);
179     }
180     else
181     {
182       byte * buffer;
183       //ttile_t tile;
184 
185       size = TIFFTileSize(tif);
186       buffer = malloc(size);
187       for (y = 0; y < context->Height; y += tile_height)
188       {
189         for (x = 0; x < context->Width; x += tile_width)
190         {
191           dword x2, y2;
192           if (TIFFReadTile(tif, buffer, x, y, 0, 0) == -1)
193           {
194             free(buffer);
195             File_error = 2;
196             return;
197           }
198           j = 0;
199           for (y2 = 0; y2 < tile_height; y2++)
200           {
201             for (x2 = 0; x2 < tile_width ; x2++)
202             {
203               Set_pixel(context, x + x2, y + y2, buffer[j]);
204               j++;
205             }
206           }
207         }
208       }
209       free(buffer);
210     }
211   }
212   else
213   {
214     dword rows_per_strip = 0;
215     tstrip_t strip, strip_count;
216     // "Striped" image
217     TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
218     if (rows_per_strip == 0)
219     {
220       File_error = 2;
221       return;
222     }
223     if (spp > 1 || bps > 8)
224     {
225       // if not 8bit with colormap, use TIFFReadRGBAStrip
226       dword * buffer;
227 
228       strip_count = (context->Height + rows_per_strip - 1) / rows_per_strip;
229       buffer = malloc(sizeof(dword) * rows_per_strip * context->Width);
230       for (strip = 0, y = 0; strip < strip_count; strip++)
231       {
232         if (!TIFFReadRGBAStrip(tif, strip * rows_per_strip, buffer))
233         {
234           free(buffer);
235           File_error = 2;
236           return;
237         }
238         // 	Note that the raster is assume to be organized such that the
239         // pixel at location (x,y) is raster[y*width+x]; with the raster
240         // origin in the lower-left hand corner of the strip. That is bottom
241         // to top organization. When reading a partial last strip in the
242         // file the last line of the image will begin at the beginning of
243         // the buffer.
244         y = (strip + 1) * rows_per_strip - 1;
245         if (y >= context->Height)
246           y = context->Height - 1;
247         for (i = 0, j = 0;
248              i < rows_per_strip && y >= (int)(strip * rows_per_strip);
249              i++, y--)
250         {
251           for (x = 0; x < context->Width; x++)
252           {
253             Set_pixel_24b(context, x, y, TIFFGetR(buffer[j]), TIFFGetG(buffer[j]), TIFFGetB(buffer[j]));
254             j++;
255           }
256         }
257       }
258       free(buffer);
259     }
260     else
261     {
262       byte * buffer = NULL;
263 
264       strip_count = TIFFNumberOfStrips(tif);
265       size = TIFFStripSize(tif);
266       GFX2_Log(GFX2_DEBUG, "TIFF %u strips of %u bytes\n", strip_count, size);
267       buffer = malloc(size);
268       for (strip = 0, y = 0; strip < strip_count; strip++)
269       {
270         tsize_t r = TIFFReadEncodedStrip(tif, strip, buffer, size);
271         if (r == -1)
272         {
273           free(buffer);
274           File_error = 2;
275           return;
276         }
277         for (i = 0, j = 0; i < rows_per_strip && y < context->Height; i++, y++)
278         {
279           for (x = 0; x < context->Width; x++)
280           {
281             switch (bps)
282             {
283               case 8:
284                 Set_pixel(context, x, y, buffer[j++]);
285                 break;
286               case 6: // 3 bytes => 4 pixels
287                 Set_pixel(context, x++, y, buffer[j] >> 2);
288                 if (x < context->Width)
289                 {
290                   Set_pixel(context, x++, y, (buffer[j] & 3) << 4 | (buffer[j+1] & 0xf0) >> 4);
291                   j++;
292                   if (x < context->Width)
293                   {
294                     Set_pixel(context, x++, y, (buffer[j] & 0x0f) << 2 | (buffer[j+1] & 0xc0) >> 6);
295                     j++;
296                     Set_pixel(context, x, y, buffer[j] & 0x3f);
297                   }
298                 }
299                 j++;
300                 break;
301               case 4:
302                 Set_pixel(context, x++, y, buffer[j] >> 4);
303                 Set_pixel(context, x, y, buffer[j++] & 0x0f);
304                 break;
305               case 2:
306                 Set_pixel(context, x++, y, buffer[j] >> 6);
307                 Set_pixel(context, x++, y, (buffer[j] >> 4) & 3);
308                 Set_pixel(context, x++, y, (buffer[j] >> 2) & 3);
309                 Set_pixel(context, x, y, buffer[j++] & 3);
310                 break;
311               case 1:
312                 Set_pixel(context, x++, y, (buffer[j] >> 7) & 1);
313                 Set_pixel(context, x++, y, (buffer[j] >> 6) & 1);
314                 Set_pixel(context, x++, y, (buffer[j] >> 5) & 1);
315                 Set_pixel(context, x++, y, (buffer[j] >> 4) & 1);
316                 Set_pixel(context, x++, y, (buffer[j] >> 3) & 1);
317                 Set_pixel(context, x++, y, (buffer[j] >> 2) & 1);
318                 Set_pixel(context, x++, y, (buffer[j] >> 1) & 1);
319                 Set_pixel(context, x, y, buffer[j++] & 1);
320                 break;
321               default:
322                 File_error = 2;
323                 GFX2_Log(GFX2_ERROR, "TIFF : %u bps unsupported\n", bps);
324                 free(buffer);
325                 return;
326             }
327           }
328         }
329       }
330       free(buffer);
331     }
332   }
333 }
334 
335 
336 /// Load TIFF
Load_TIFF_Sub(T_IO_Context * context,TIFF * tif,unsigned long file_size)337 void Load_TIFF_Sub(T_IO_Context * context, TIFF * tif, unsigned long file_size)
338 {
339   enum IMAGE_MODES mode = IMAGE_MODE_LAYERED;
340   int layer = 0;
341   enum PIXEL_RATIO ratio = PIXEL_SIMPLE;
342   dword width, height;
343   word bps, spp;
344   word photometric = PHOTOMETRIC_RGB;
345   char * desc;
346   char * software = NULL;
347   float xresol, yresol;
348 
349 #ifdef _DEBUG
350   TIFFPrintDirectory(tif, stdout, TIFFPRINT_NONE);
351 #endif
352   if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) || !TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))
353     return;
354   if (!TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps) || !TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp))
355     return;
356   GFX2_Log(GFX2_DEBUG, "TIFF #0 : %ux%u %ux%ubps\n", width, height, spp, bps);
357   if (TIFFGetField(tif, TIFFTAG_IMAGEDESCRIPTION, &desc))
358   {
359     size_t len = strlen(desc);
360     if (len <= COMMENT_SIZE)
361       memcpy(context->Comment, desc, len + 1);
362     else
363     {
364       memcpy(context->Comment, desc, COMMENT_SIZE);
365       context->Comment[COMMENT_SIZE] = '\0';
366     }
367   }
368   TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
369   if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xresol) && TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yresol))
370   {
371     float ratiof = xresol / yresol;
372     if (ratiof > 1.6f)
373       ratio = PIXEL_TALL;
374     else if (ratiof > 1.4f)
375       ratio = PIXEL_TALL3;
376     else if (ratiof < 0.7f)
377       ratio = PIXEL_WIDE;
378   }
379 
380   File_error = 0;
381   Pre_load(context, width, height, file_size, FORMAT_TIFF, ratio, bps * spp);
382   if (File_error != 0)
383     return;
384 
385   if (TIFFGetField(tif, TIFFTAG_SOFTWARE, &software))
386   {
387     if (0 == memcmp(software, "GrafX2", 6)) // Check if the file was written by GrafX2
388     {
389       byte * grafx2_private; // bkg/transp color, background transparent, image mode, reserved (0)
390       if (TIFFGetField(tif, TIFFTAG_GRAFX2, &grafx2_private))
391       {
392         GFX2_Log(GFX2_DEBUG, "bkg/transp color #%u, bkg transp %u, mode %u, reserved %u\n",
393                  grafx2_private[0], grafx2_private[1], grafx2_private[2], grafx2_private[3]);
394         context->Transparent_color = grafx2_private[0]; // need to be set after calling Pre_load()
395         context->Background_transparent = grafx2_private[1];
396         mode = grafx2_private[2];
397       }
398     }
399   }
400   Set_image_mode(context, (mode == IMAGE_MODE_ANIMATION) ? mode : IMAGE_MODE_LAYERED);
401   if (spp == 1)
402   {
403     struct {
404       word * r;
405       word * g;
406       word * b;
407     } colormap;
408     unsigned i, count;
409 
410     count = (bps <= 8) ? 1 << bps : 256;
411     if (TIFFGetField(tif, TIFFTAG_COLORMAP, &colormap.r, &colormap.g, &colormap.b))
412     {
413       for (i = 0; i < count; i++)
414       {
415         context->Palette[i].R = colormap.r[i] >> 8;
416         context->Palette[i].G = colormap.g[i] >> 8;
417         context->Palette[i].B = colormap.b[i] >> 8;
418       }
419     }
420     else
421     {
422       // Grayscale palette
423       for (i = 0; i < count; i++)
424       {
425         unsigned int value = 255
426           * (photometric == PHOTOMETRIC_MINISWHITE ? (count - 1 - i) : i)
427           / (count - 1);
428         context->Palette[i].R = value;
429         context->Palette[i].G = value;
430         context->Palette[i].B = value;
431       }
432     }
433   }
434 
435   for (;;)
436   {
437     word subifd_count;
438 #if TIFFLIB_VERSION <= 20120218
439     uint32 * subifd_array;
440 #else
441     uint64 * subifd_array;
442 #endif
443     if (TIFFGetField(tif, TIFFTAG_SUBIFD, &subifd_count, &subifd_array))
444     {
445       GFX2_Log(GFX2_DEBUG, "TIFFTAG_SUBIFD : count = %u\n", subifd_count);
446     }
447     Load_TIFF_image(context, tif, spp, bps);
448     if (File_error != 0)
449       return;
450 
451     if (context->Type != CONTEXT_MAIN_IMAGE)
452       return;
453     if (!TIFFReadDirectory(tif))
454       return;
455     if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) || !TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))
456       return;
457     if (!TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps) || !TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp))
458       return;
459     layer++;
460     GFX2_Log(GFX2_DEBUG, "TIFF #%d : %ux%u %ux%ubps\n", layer, width, height, spp, bps);
461     if ((int)width != context->Width || (int)height != context->Height)
462       return;
463     if (context->bpp != (spp * bps))
464       return;
465     Set_loading_layer(context, layer);
466 #ifdef _DEBUG
467     TIFFPrintDirectory(tif, stdout, TIFFPRINT_NONE);
468 #endif
469   }
470   if (mode > IMAGE_MODE_ANIMATION)
471     Set_image_mode(context, mode);
472 }
473 
474 struct memory_buffer
475 {
476   char * buffer;
477   unsigned long offset;
478   unsigned long size;
479   unsigned long alloc_size;
480 };
481 
lTIFF_read(thandle_t p,void * data,tsize_t size)482 tsize_t lTIFF_read(thandle_t p, void * data, tsize_t size)
483 {
484   struct memory_buffer * mbuffer = (struct memory_buffer *)p;
485   GFX2_Log(GFX2_DEBUG, "lTIFF_read(%p, %p, %u)\n", p, data, size);
486   memcpy(data, mbuffer->buffer + mbuffer->offset, size);
487   mbuffer->offset += size;
488   return size;
489 }
490 
lTIFF_write(thandle_t p,void * data,tsize_t size)491 tsize_t lTIFF_write(thandle_t p, void * data, tsize_t size)
492 {
493   struct memory_buffer * mbuffer = (struct memory_buffer *)p;
494   GFX2_Log(GFX2_DEBUG, "lTIFF_write(%p, %p, %u)\n", p, data, size);
495   if (mbuffer->offset + size > mbuffer->alloc_size)
496   {
497     char * tmp = realloc(mbuffer->buffer, mbuffer->offset + size + 1024);
498     if (tmp == NULL)
499     {
500       GFX2_Log(GFX2_ERROR, "lTIFF_write() failed to allocate %u bytes of memory\n", mbuffer->offset + size + 1024);
501       return -1;
502     }
503     mbuffer->buffer = tmp;
504     mbuffer->alloc_size = mbuffer->offset + size + 1024;
505   }
506   memcpy(mbuffer->buffer + mbuffer->offset, data, size);
507   mbuffer->offset += size;
508   if (mbuffer->offset > mbuffer->size)
509     mbuffer->size = mbuffer->offset;
510   return size;
511 }
512 
lTIFF_seek(thandle_t p,toff_t offset,int whence)513 toff_t lTIFF_seek(thandle_t p, toff_t offset, int whence)
514 {
515   struct memory_buffer * mbuffer = (struct memory_buffer *)p;
516   switch (whence)
517   {
518     case SEEK_SET:
519       mbuffer->offset = offset;
520       break;
521     case SEEK_CUR:
522       mbuffer->offset += offset;
523       break;
524     case SEEK_END:
525       mbuffer->offset = mbuffer->size - offset;
526       break;
527     default:
528       return -1;
529   }
530   GFX2_Log(GFX2_DEBUG, "lTIFF_seek(%p, %u, %d) new offset=%u (size=%u)\n",
531            p, offset, whence, mbuffer->offset, mbuffer->size);
532   if (mbuffer->offset > mbuffer->alloc_size)
533   {
534     char * tmp = realloc(mbuffer->buffer, mbuffer->offset + 1024);
535     if (tmp == NULL)
536     {
537       GFX2_Log(GFX2_ERROR, "lTIFF_seek() failed to allocate %u bytes of memory\n", mbuffer->offset + 1024);
538       return -1;
539     }
540     mbuffer->buffer = tmp;
541     mbuffer->alloc_size = mbuffer->offset + 1024;
542   }
543   if (mbuffer->offset > mbuffer->size)
544   {
545     memset(mbuffer->buffer + mbuffer->size, 0, mbuffer->offset - mbuffer->size);
546     GFX2_Log(GFX2_ERROR, "  seeking %d bytes after end of buffer, filling with 0s\n", mbuffer->offset - mbuffer->size);
547     mbuffer->size = mbuffer->offset;
548   }
549   return mbuffer->offset;
550 }
551 
552 
lTIFF_size(thandle_t p)553 toff_t lTIFF_size(thandle_t p)
554 {
555   struct memory_buffer * mbuffer = (struct memory_buffer *)p;
556   GFX2_Log(GFX2_DEBUG, "lTIFF_size(%p) = %u\n", p, mbuffer->size);
557   return mbuffer->size;
558 }
559 
lTIFF_close(thandle_t p)560 int lTIFF_close(thandle_t p)
561 {
562   (void)p;
563   return 0;
564 }
565 
lTIFF_map(thandle_t p,void ** base,toff_t * size)566 int lTIFF_map(thandle_t p, void ** base, toff_t * size)
567 {
568   struct memory_buffer * mbuffer = (struct memory_buffer *)p;
569   GFX2_Log(GFX2_DEBUG, "lTIFF_map(%p, %p, %p)\n", p, base, size);
570   *base = mbuffer->buffer;
571   *size = mbuffer->size;
572   return 1;
573 }
574 
lTIFF_unmap(thandle_t p,void * base,toff_t size)575 void lTIFF_unmap(thandle_t p, void *base, toff_t size)
576 {
577   GFX2_Log(GFX2_DEBUG, "lTIFF_unmap(%p, %p, %u)\n", p, base, size);
578   return;
579 }
580 
581 /// Load TIFF from memory
Load_TIFF_from_memory(T_IO_Context * context,const void * buffer,unsigned long size)582 void Load_TIFF_from_memory(T_IO_Context * context, const void * buffer, unsigned long size)
583 {
584   TIFF * tif;
585   struct memory_buffer memory_buffer;
586 
587   memory_buffer.buffer = (char *)buffer;
588   memory_buffer.offset = 0;
589   memory_buffer.size = size;
590   memory_buffer.alloc_size = 0; // unused for read
591 
592   TIFF_Init();
593   tif = TIFFClientOpen("memory.tiff", "r", &memory_buffer,
594                        lTIFF_read, lTIFF_write, lTIFF_seek, lTIFF_close,
595                        lTIFF_size, lTIFF_map, lTIFF_unmap);
596   if (tif != NULL)
597   {
598     Load_TIFF_Sub(context, tif, size);
599     TIFFClose(tif);
600   }
601 }
602 
603 /// Load TIFF from file
Load_TIFF(T_IO_Context * context)604 void Load_TIFF(T_IO_Context * context)
605 {
606   TIFF * tif;
607 #if !defined(WIN32)
608   FILE * file;
609 
610   File_error = 1;
611 
612   file = Open_file_read(context);
613   if (file != NULL)
614   {
615     TIFF_Init();
616     tif = TIFFFdOpen(fileno(file), context->File_name, "r");
617     if (tif != NULL)
618     {
619       Load_TIFF_Sub(context, tif, File_length_file(file));
620       TIFFClose(tif);
621     }
622     fclose(file);
623   }
624 #else
625   char * filename; // filename with full path
626 
627   File_error = 1;
628   filename = Filepath_append_to_dir(context->File_directory, context->File_name);
629   TIFF_Init();
630   tif = TIFFOpen(filename, "r");
631   if (tif != NULL)
632   {
633     Load_TIFF_Sub(context, tif, File_length(filename));
634     TIFFClose(tif);
635   }
636   free(filename);
637 #endif
638 }
639 
640 
641 /// Save (already open) TIFF
Save_TIFF_Sub(T_IO_Context * context,TIFF * tif)642 void Save_TIFF_Sub(T_IO_Context * context, TIFF * tif)
643 {
644   char version[64];
645   int i;
646   int layer = 0;
647   dword width, height;
648   dword y;
649   tstrip_t strip;
650   struct {
651     word r[256];
652     word g[256];
653     word b[256];
654   } colormap;
655   const word bps = 8;
656   const word spp = 1;
657   const dword rowsperstrip = 64;
658   const word photometric = PHOTOMETRIC_PALETTE;
659   float xresol = 1.0f, yresol = 1.0f;
660   // bkg/transp color, background transparent, image mode, reserved (0)
661   byte grafx2_private[4] = { context->Transparent_color, context->Background_transparent, 0, 0 };
662 
663   if (context->Type == CONTEXT_MAIN_IMAGE)
664     grafx2_private[2] = Main.backups->Pages->Image_mode;
665 
666   switch (context->Ratio)
667   {
668     case PIXEL_WIDE:
669     case PIXEL_WIDE2:
670       yresol = 2.0f;
671       break;
672     case PIXEL_TALL:
673     case PIXEL_TALL2:
674       xresol = 2.0f;
675       break;
676     case PIXEL_TALL3:
677       xresol = 4.0f;
678       yresol = 3.0f;
679       break;
680     default:
681       break;
682   }
683 
684   snprintf(version, sizeof(version), "GrafX2 %s.%s", Program_version, SVN_revision);
685   width = context->Width;
686   height = context->Height;
687   for (i = 0; i < 256; i++)
688   {
689     colormap.r[i] = 0x101 * context->Palette[i].R;
690     colormap.g[i] = 0x101 * context->Palette[i].G;
691     colormap.b[i] = 0x101 * context->Palette[i].B;
692   }
693 
694   for (;;)
695   {
696     GFX2_Log(GFX2_DEBUG, "TIFF save layer #%d\n", layer);
697 //TIFFTAG_SUBFILETYPE
698     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
699     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
700     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps);
701     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
702     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric);
703     TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
704     TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp);
705     //TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // not relevant if SAMPLESPERPIXEL == 1
706     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
707     if (context->Comment[0] != '\0')
708       TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, context->Comment);
709     TIFFSetField(tif, TIFFTAG_SOFTWARE, version);
710     TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE);
711     // RESUNIT_NONE : No absolute unit of measurement.
712     // Used for images that may have a non-square aspect ratio,
713     // but no meaningful absolute dimensions.
714     TIFFSetField(tif, TIFFTAG_XRESOLUTION, xresol);
715     TIFFSetField(tif, TIFFTAG_YRESOLUTION, yresol);
716     TIFFSetField(tif, TIFFTAG_COLORMAP, colormap.r, colormap.g, colormap.b);
717 
718 //    TIFFTAG_SUBIFD  // point to thumbnail, etc.
719 //    TIFFSetField(tif, TIFFTAG_PAGENUMBER, current_page, page_count);
720 
721     // extensions :
722     TIFFSetField(tif, TIFFTAG_GRAFX2, grafx2_private);
723 
724 
725 #if 0
726     for (y = 0; y < height; y++)
727     {
728       if (TIFFWriteScanline(tif, context->Target_address + y*context->Pitch, y, 0) < 0)
729         return;
730     }
731 #else
732     for (y = 0, strip = 0; y < height; y += rowsperstrip, strip++)
733     {
734       if (TIFFWriteEncodedStrip(tif, strip, context->Target_address + y*context->Pitch, rowsperstrip * context->Pitch) < 0)
735         return;
736     }
737 #endif
738     layer++;
739 
740     if (layer >= context->Nb_layers)
741     {
742       TIFFFlushData(tif);
743       File_error = 0; // everything was fine
744       return;
745     }
746     Set_saving_layer(context, layer);
747     if (!TIFFWriteDirectory(tif))
748       return;
749     TIFFFlushData(tif);
750   }
751 }
752 
753 /// Save TIFF to memory
Save_TIFF_to_memory(T_IO_Context * context,void ** buffer,unsigned long * size)754 void Save_TIFF_to_memory(T_IO_Context * context, void * * buffer, unsigned long * size)
755 {
756   TIFF * tif;
757   struct memory_buffer memory_buffer;
758 
759   memory_buffer.buffer = NULL;
760   memory_buffer.offset = 0;
761   memory_buffer.size = 0;
762   memory_buffer.alloc_size = 0;
763 
764   TIFF_Init();
765   tif = TIFFClientOpen("memory.tiff", "w", &memory_buffer,
766                        lTIFF_read, lTIFF_write, lTIFF_seek, lTIFF_close,
767                        lTIFF_size, lTIFF_map, lTIFF_unmap);
768   if (tif != NULL)
769   {
770     Save_TIFF_Sub(context, tif);
771     TIFFClose(tif);
772     *buffer = memory_buffer.buffer;
773     *size = memory_buffer.size;
774   }
775 }
776 
777 /// Save TIFF
Save_TIFF(T_IO_Context * context)778 void Save_TIFF(T_IO_Context * context)
779 {
780   TIFF * tif;
781   char * filename; // filename with full path
782 
783   filename = Filepath_append_to_dir(context->File_directory, context->File_name);
784 
785   File_error = 1;
786 
787   TIFF_Init();
788 #if defined(WIN32)
789   if (context->File_name_unicode != NULL && context->File_name_unicode[0] != 0)
790     tif = TIFFOpenW(context->File_name_unicode, "w");
791   else
792 #endif
793     tif = TIFFOpen(filename, "w");
794   if (tif != NULL)
795   {
796     Save_TIFF_Sub(context, tif);
797     TIFFClose(tif);
798   }
799   free(filename);
800 }
801 
802 /** @} */
803 
804 #endif
805