1 /*
2 * FIG : Facility for Interactive Generation of figures
3 * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4 * Parts Copyright (c) 1989-2015 by Brian V. Smith
5 * Parts Copyright (c) 1991 by Paul King
6 * Parts Copyright (c) 2016-2020 by Thomas Loimer
7 *
8 * Any party obtaining a copy of these files is granted, free of charge, a
9 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10 * nonexclusive right and license to deal in this software and documentation
11 * files (the "Software"), including without limitation the rights to use,
12 * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
13 * the Software, and to permit persons who receive copies from any such
14 * party to do so, with the only requirement being that the above copyright
15 * and this permission notice remain intact.
16 *
17 */
18
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h" /* restrict */
22 #endif
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <tiffio.h>
27
28 #include "resources.h"
29 #include "object.h"
30 #include "f_picobj.h" /* image_size() */
31 #include "f_util.h" /* map_to_palette(), map_to_mono() */
32 #include "w_msgpanel.h"
33
34
35 static void
error_handler(const char * module,const char * fmt,va_list ap)36 error_handler(const char *module, const char *fmt, va_list ap)
37 {
38 char buffer[510]; /* usable size of tmpstr[] in w_msgpanel.c */
39
40 vsnprintf(buffer, sizeof buffer, fmt, ap);
41 file_msg("%s: %s", module, buffer);
42 }
43
44 /* return codes: PicSuccess (1) : success
45 FileInvalid (-2) : invalid file
46 */
47 int
read_tif(F_pic * pic,struct xfig_stream * restrict pic_stream)48 read_tif(F_pic *pic, struct xfig_stream *restrict pic_stream)
49 {
50 int stat = FileInvalid;
51 uint16 unit;
52 uint32 w, h;
53 float res_x, res_y;
54 TIFF *tif;
55
56 if (uncompressed_content(pic_stream))
57 return FileInvalid;
58
59 /* re-direct TIFF errors to file_msg() */
60 (void)TIFFSetErrorHandler(error_handler);
61 /* ignore warnings */
62 (void)TIFFSetWarningHandler(NULL);
63
64 if ((tif = TIFFOpen(pic_stream->content, "r")) == NULL)
65 return stat;
66
67 /* read image width and height */
68 if (TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w) != 1) {
69 TIFFClose(tif);
70 return stat;
71 }
72 if (TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h) != 1) {
73 TIFFClose(tif);
74 return stat;
75 }
76 if (w == 0 || h == 0) {
77 TIFFClose(tif);
78 return stat;
79 }
80
81 /* allocate memory for image data */
82 if ((pic->pic_cache->bitmap = malloc(w * h * sizeof(uint32))) == NULL) {
83 file_msg("Out of memory");
84 TIFFClose(tif);
85 return stat;
86 }
87
88 /* get image resolution, alias density */
89 if (TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &unit) != 1)
90 unit = 1;
91 if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &res_x) != 1 ||
92 TIFFGetField(tif, TIFFTAG_XRESOLUTION, &res_y) != 1) {
93 res_x = 0.0f; /* image_size() will use a default */
94 res_y = 0.0f;
95 unit = 1; /* 1 - none, 2 - per inch, 3 - per cm */
96 }
97 /* set pixmap properties */
98 pic->pixmap = None;
99 pic->pic_cache->subtype = T_PIC_TIF;
100 pic->pic_cache->bit_size.x = (int)w; /* needed in */
101 pic->pic_cache->bit_size.y = (int)h; /* map_to_palette() below */
102 pic->hw_ratio = (float)h / w;
103 image_size(&pic->pic_cache->size_x, &pic->pic_cache->size_y,
104 pic->pic_cache->bit_size.x, pic->pic_cache->bit_size.y,
105 unit == 2u ? 'i': (unit == 3u ? 'c': 'u'), res_x,res_y);
106
107 if (appres.DEBUG)
108 fprintf(stderr, "Reading TIFF image, size %d x %d, resolution "
109 "%.0f x %.0f%s.\n", pic->pic_cache->bit_size.x,
110 pic->pic_cache->bit_size.y, res_x, res_y,
111 unit == 2u ? " pixel per inch" :
112 (unit == 3u ? " pixel per cm" : "" ));
113
114 /* read the image */
115 stat = TIFFReadRGBAImageOriented(tif, w, h,
116 (uint32 *)pic->pic_cache->bitmap, ORIENTATION_TOPLEFT, 0);
117 TIFFClose(tif);
118 if (stat == 0) {
119 if (pic->pic_cache->bitmap)
120 free(pic->pic_cache->bitmap);
121 return FileInvalid;
122 }
123
124 /* provide the pixmap */
125 if (tool_vclass == TrueColor && image_bpp == 4 && !appres.monochrome) {
126 /* either a full-color pixmap, format ARGB */
127 unsigned char *p;
128 unsigned char tmp;
129 #ifdef WORDS_BIGENDIAN
130 /* change RGBA to ARGB */
131 /* as long as the alpha channel is not used, the fastest would
132 be to read the image with an offset of one */
133 p = pic->pic_cache->bitmap;
134 while (p < pic->pic_cache->bitmap + w * h * sizeof(uint32)) {
135 /* tmp = *(p + 3); alpha channel not used */
136 *(p + 3) = *(p + 2);
137 *(p + 2) = *(p + 1);
138 *(p + 1) = *p;
139 p += sizeof(uint32); /* must be 4 */
140 }
141 #else
142 /* swap RGBA to BGRA */
143 p = pic->pic_cache->bitmap;
144 while (p < pic->pic_cache->bitmap + w * h * sizeof(uint32)) {
145 tmp = *p; *p = *(p + 2); *(p + 2) = tmp;
146 p += sizeof(uint32); /* must be 4 */
147 }
148 #endif
149 /* indicate, that this is a TrueColor pixmap */
150 pic->pic_cache->numcols = -1;
151
152 } else { /* tool_vclass != TrueColor || .. */
153 /* or a pixmap with a colormap, one byte per pixel */
154 /* write BGR triples for map_to_palette */
155 unsigned char *src;
156 unsigned char *dst;
157 unsigned char tmp;
158
159 /* write the first two triples */
160 tmp = *pic->pic_cache->bitmap;
161 *pic->pic_cache->bitmap = *(pic->pic_cache->bitmap + 2);
162 *(pic->pic_cache->bitmap + 2) = tmp;
163
164 src = pic->pic_cache->bitmap + 4; /* RGBA RGBA */
165 dst = pic->pic_cache->bitmap + 3; /* BGRB GR */
166 tmp = *src;
167 *dst++ = *(src + 2);
168 *dst++ = *(src + 1);
169 *dst++ = tmp;
170 src += 4; /* sizeof(uint32) */
171 while (src < pic->pic_cache->bitmap + w * h * sizeof(uint32)) {
172 *dst++ = *(src + 2);
173 *dst++ = *(src + 1);
174 *dst++ = *src;
175 src += 4; /* sizeof(uint32) */
176 }
177 pic->pic_cache->bitmap = realloc(pic->pic_cache->bitmap,
178 w * h * 3 * sizeof(char));
179
180 /* map_to_palette() reduces to 256 colors */
181 pic->pic_cache->numcols = 256;
182 if (!map_to_palette(pic)) {
183 /* map_to_palette() frees pic->pic_cache->bitmap */
184 return FileInvalid;
185 }
186 if (tool_cells <= 2 || appres.monochrome)
187 map_to_mono(pic);
188 }
189
190 return PicSuccess;
191 }
192