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