1 /* loadtiff.c - loads a tiff file into memory
2 Copyright (C) 1996-2017 Paul Sheer
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307, USA.
18 */
19
20 /* this file is highly dependent on a long int being 4 bytes */
21
22 /* NLS through this whole file ? */
23
24 #include <config.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30
31 #include <math.h>
32
33 #include "stringtools.h"
34 #include "app_glob.c"
35
36 #include "coolwidget.h"
37
38 #include "mad.h"
39
40
41 #define TPRINTF tiffprintf
42 /*tiffprintf*/
43
44 /* #define ABORT_ON_ERROR */
45
46
47
48 short highbytefirst = 0;
49
fgetshort(FILE * f)50 short fgetshort(FILE *f)
51 {
52 if(highbytefirst)
53 return (getc(f)<<8) + getc(f);
54 else
55 return getc(f) + (getc(f) << 8);
56 }
57
58
fgetlong(FILE * f)59 long fgetlong (FILE * f)
60 {
61 if (highbytefirst)
62 return (getc (f) << 24) + (getc (f) << 16) + (getc (f) << 8) + getc (f);
63 else
64 return getc (f) + (getc (f) << 8) + (getc (f) << 16) + (getc (f) << 24);
65 }
66
67 /*
68 Gets an array of unsigned char at offset 'offset' from the beginning
69 of the file, of length 'length' bytes. It returns a pointer to the data
70 although the data is malloced from within the function, the function
71 checks on each call to free previous mallocs, and does so
72 if necessary. Therefore DO NOT FREE the pointer returned by this function.
73 Also copy the results before the next call to fgetstring.
74 */
75
fgetstring(FILE * f,long offset,long length)76 unsigned char *fgetstring (FILE * f, long offset, long length)
77 {
78 static unsigned char *str = NULL;
79
80 if (str)
81 free (str);
82 if ((str = malloc (length + 1)) == NULL) {
83 /* Not essential to translate */
84 printf(_("Could not allocate memory in fgetstring.\n"));
85 abort();
86 }
87
88 fseek (f, offset, SEEK_SET);
89 fread (str, length, 1, f);
90 str[length] = 0;
91
92 return str;
93 }
94
tiffprintf(const char * str,...)95 void tiffprintf(const char *str, ...)
96 {
97
98 }
99
100
101 struct IFDentry {
102 short tag;
103 short fieldtype;
104 long length;
105 long valueoffset;
106 short shortvalue; /*this is duplicate of the lower numbered
107 two bytes of valueoffset, for when valueoffset contains a
108 short value */
109 };
110
111
112 /*gets the value of an IFD entry. If the value is small enough
113 to fit in the valueoffset it gets it from there.
114 Handles correctly both arrays and single numbers */
getvalue(FILE * fp,struct IFDentry * entry,long * retval,long numtoget,int size)115 void getvalue (FILE * fp, struct IFDentry *entry, long *retval, long numtoget, int size)
116 {
117 int j;
118 if (size == 2 || (entry->fieldtype == 3 && size == 0)) {
119 TPRINTF (" (short) ");
120 if (numtoget <= 2) {
121 retval[0] = entry->shortvalue;
122 if (numtoget == 2)
123 if (highbytefirst)
124 retval[1] = entry->valueoffset && 0xFFFF;
125 else
126 retval[1] = entry->valueoffset >> 16;
127 } else {
128 fseek (fp, entry->valueoffset, SEEK_SET);
129 for (j = 0; j < numtoget; j++)
130 retval[j] = fgetshort (fp);
131 }
132 }
133 if (size == 4 || (entry->fieldtype == 4 && size == 0)) {
134 TPRINTF (" (long) ");
135 if (numtoget <= 1) {
136 retval[0] = entry->valueoffset;
137 } else {
138 fseek (fp, entry->valueoffset, SEEK_SET);
139 for (j = 0; j < numtoget; j++)
140 retval[j] = fgetlong (fp);
141 }
142 }
143 }
144
145
146
147
148
tifferror(const char * errmessage)149 void tifferror (const char *errmessage)
150 {
151 fprintf(stderr, errmessage); /* OR for the application: */
152 #ifdef ABORT_ON_ERROR
153 abort();
154 #endif
155 /* CError (errmessage); */
156 /********/
157 }
158
159 /*
160 The return value must be free'd by the calling application
161 since the function malloc's it.
162
163 loads an uncompressed class G tiff file. This is a greyscale file.
164 Presently, this routine only supports, topdown orientation (Orientation = 1)
165 1 sample per pixel of 8 bits. It uses the greyresponse curve and assumes the
166 monitor to have a linear response.
167 It will interprete PhotometricInterpretation of 0 or 1 (reverse or normal).
168 It can handle multiple strips of any size and reads and displays most of the
169 important fields (although it only actually interprets class G fields).
170
171 rowstart and rowend are used to specify what part of the image to load
172 for very large files. If they go past the end of a file. The calling
173 application must check the size of the returned data by looking
174 at the height returned. To load the whole file,set rowstart = 0,
175 rowend = 2^31 - 1.
176 loadgreytiff returns contigous rows, 1 byte/pixel (0-255, black-white),
177 exclusive of rowend. Hence rowend-rowstart rows/scanlines are returned.
178 The first row/scanline is number zero, the last is numbered height - 1.
179 */
180
181
loadgreytiff(const char * fname,long * width,long * height,long rowstart,long rowend,float gamma)182 unsigned char *loadgreytiff (const char *fname, long *width, long *height, long rowstart, long rowend, float gamma)
183 {
184
185 FILE *fp = NULL;
186 int i, j, c;
187 long IFDoffset;
188 struct IFDentry *theIFD = NULL;
189 short numberofIFDentries;
190 int numinterpreted;
191 long *greyresponsecurve = NULL;
192 long *stripbytecounts = NULL, *stripoffsets = NULL;
193 long numstrips;
194 float xresolution, yresolution;
195 long bitspersample[3] =
196 {8, 8, 8};
197 long index;
198 long maxgrey, mingrey;
199
200 unsigned char *pic8 = NULL;
201 unsigned char *pp = NULL;
202
203 int numgreylevels = 0; /*number of entries in the grey response curve array */
204
205 /*options: */
206 int photointerp = 1, spp = 1, comptype = 1, fillorder = 1, planarconfig = 1,
207 orient = 1;
208 long rps = 0x7FFFFFFF;
209
210
211 if ((fp = fopen (fname, "r")) == NULL) {
212 /* NLS ? */
213 tifferror ("Cannot open tiff image file.\n");
214 goto freeall;
215 }
216
217 if ((c = fgetshort (fp)) != 'I' + 256 * 'I')
218 highbytefirst = 1;
219 TPRINTF ("00; %c%c\n", (unsigned char) c, (unsigned char) c);
220 if ((c = fgetshort (fp)) != 42) {
221 tifferror ("Not a recognised (meaning of life) tiff file.\n");
222 goto freeall;
223 }
224 TPRINTF ("02; %d\n", c);
225 IFDoffset = fgetlong (fp);
226 if (IFDoffset < 8) {
227 tifferror ("Not a recognised tiff file.\n");
228 goto freeall;
229 }
230 TPRINTF ("04; %ld\n", IFDoffset);
231
232 if (fseek (fp, IFDoffset, SEEK_SET)) {
233 tifferror ("Tiff IFD passed end of file.\n");
234 goto freeall;
235 }
236 /*now read the Image File Directory (IFD) */
237
238 numberofIFDentries = fgetshort (fp);
239 TPRINTF ("\nNumber IFD entries = %d\n", numberofIFDentries);
240
241 if ((theIFD = malloc (numberofIFDentries * sizeof (struct IFDentry))) == NULL) {
242 tifferror ("Cannot allocate memory for tiff file.\n");
243 goto freeall;
244 }
245 for (i = 0; i < numberofIFDentries; i++) {
246 /*TPRINTF's are for debug */
247 /* TPRINTF ("\n"); */
248 theIFD[i].tag = fgetshort (fp);
249 /* TPRINTF ("IFD %ld;%d\n", IFDoffset + 0 + 12 * i, theIFD[i].tag); */
250 theIFD[i].fieldtype = fgetshort (fp);
251 /* TPRINTF ("IFD %ld;%d\n", IFDoffset + 2 + 12 * i, theIFD[i].fieldtype); */
252 theIFD[i].length = fgetlong (fp);
253 /* TPRINTF ("IFD %ld;%ld\n", IFDoffset + 4 + 12 * i, theIFD[i].length); */
254 theIFD[i].valueoffset = fgetlong (fp);
255 /* TPRINTF ("IFD %ld;%ld\n", IFDoffset + 8 + 12 * i, theIFD[i].valueoffset); */
256 if (!highbytefirst)
257 theIFD[i].shortvalue = (long) theIFD[i].valueoffset & 0xFFFF;
258 else
259 theIFD[i].shortvalue = (long) theIFD[i].valueoffset >> 16;
260 }
261
262
263 /*now loop through the IFD and check tags */
264
265 TPRINTF ("\n");
266
267 numinterpreted = numberofIFDentries;
268
269 for (i = 0; i < numberofIFDentries; i++) {
270 switch (theIFD[i].tag) {
271 case 254:
272 TPRINTF ("NewSubfileType = %ld\n", theIFD[i].valueoffset);
273 break;
274 case 256:
275 getvalue (fp, theIFD + i, width, 1, 0);
276 TPRINTF ("Image width = %ld\n", *width);
277 break;
278 case 257:
279 getvalue (fp, theIFD + i, height, 1, 0);
280 TPRINTF ("Image length = %ld\n", *height);
281 break;
282 case 258:
283 getvalue (fp, theIFD + i, bitspersample, theIFD[i].length, 2);
284 TPRINTF ("BitsPerSample\n");
285 for (j = 0; j < theIFD[i].length; j++)
286 TPRINTF ("%ld ", bitspersample[j]);
287 TPRINTF ("\n");
288 break;
289 case 259:
290 TPRINTF ("Compressing is type %d\n", theIFD[i].shortvalue);
291 comptype = theIFD[i].shortvalue;
292 break;
293 case 262:
294 TPRINTF ("Photometric interpretation = %d\n", (int) theIFD[i].shortvalue);
295 photointerp = theIFD[i].shortvalue;
296 break;
297 case 266:
298 TPRINTF ("Fillorder = %d\n", theIFD[i].shortvalue);
299 fillorder = theIFD[i].shortvalue;
300 break;
301 case 269:
302 TPRINTF ("DocumentName: %s\n", fgetstring (fp, theIFD[i].valueoffset, theIFD[i].length));
303 break;
304 case 270:
305 TPRINTF ("ImageDescription: %s\n", fgetstring (fp, theIFD[i].valueoffset, theIFD[i].length));
306 break;
307 case 271:
308 TPRINTF ("Make: %s\n", fgetstring (fp, theIFD[i].valueoffset, theIFD[i].length));
309 break;
310 case 272:
311 TPRINTF ("Model: %s\n", fgetstring (fp, theIFD[i].valueoffset, theIFD[i].length));
312 break;
313 case 273:
314 numstrips = theIFD[i].length;
315
316 if ((stripoffsets = malloc (numstrips * sizeof (long))) == NULL) {
317 tifferror ("Cannot allocate memory for tiff file.\n");
318 goto freeall;
319 }
320 getvalue (fp, theIFD + i, stripoffsets, numstrips, 0);
321 TPRINTF ("StripOffsets: %ld\n", numstrips);
322 for (j = 0; j < numstrips; j++)
323 TPRINTF ("%ld ", stripoffsets[j]);
324 TPRINTF ("\n");
325 break;
326 case 274:
327 TPRINTF ("Orientation = %d\n", theIFD[i].shortvalue);
328 orient = theIFD[i].shortvalue;
329 break;
330 case 277:
331 TPRINTF ("SamplesPerPixel = %d\n", theIFD[i].shortvalue);
332 spp = theIFD[i].shortvalue;
333 break;
334 case 278:
335 getvalue (fp, theIFD + i, &rps, 1, 0);
336 TPRINTF ("RowsPerStrip = %ld\n", rps);
337 break;
338 case 279:
339 numstrips = theIFD[i].length;
340 if ((stripbytecounts = malloc (numstrips * sizeof (long))) == NULL) {
341 tifferror ("Cannot allocate memory for tiff file.\n");
342 goto freeall;
343 }
344 getvalue (fp, theIFD + i, stripbytecounts, numstrips, 0);
345 TPRINTF ("StripByteCounts: %ld\n", numstrips);
346 for (j = 0; j < numstrips; j++)
347 TPRINTF ("%ld ", stripbytecounts[j]);
348 TPRINTF ("\n");
349 break;
350 case 282:
351 TPRINTF ("Xresolution at %ld\n", theIFD[i].valueoffset);
352 fseek (fp, theIFD[i].valueoffset, SEEK_SET);
353 xresolution = (float) fgetlong (fp) / fgetlong (fp);
354 TPRINTF (" %f\n", xresolution);
355 break;
356 case 283:
357 TPRINTF ("Yresolution at %ld\n", theIFD[i].valueoffset);
358 fseek (fp, theIFD[i].valueoffset, SEEK_SET);
359 yresolution = (float) fgetlong (fp) / fgetlong (fp);
360 TPRINTF (" %f\n", yresolution);
361 break;
362 case 284:
363 TPRINTF ("PlanarConfiguration = %d\n", theIFD[i].shortvalue);
364 planarconfig = theIFD[i].shortvalue;
365 break;
366 case 285:
367 TPRINTF ("PageName: %s\n", fgetstring (fp, theIFD[i].valueoffset, theIFD[i].length));
368 break;
369 case 290:
370 TPRINTF ("GrayResponseUnit = %d\n", theIFD[i].shortvalue);
371 break;
372 case 291:
373 TPRINTF ("GrayResponseCurve at %ld, length %ld\n", theIFD[i].valueoffset, theIFD[i].length);
374 numgreylevels = theIFD[i].length;
375
376 if ((greyresponsecurve = malloc (numgreylevels * sizeof (long))) == NULL) {
377 abort();
378 tifferror ("Cannot allocate memory for tiff file.\n");
379 goto freeall;
380 }
381 getvalue (fp, theIFD + i, greyresponsecurve, numgreylevels, 2);
382 for (j = 0; j < numgreylevels; j++)
383 TPRINTF ("%ld ", greyresponsecurve[j]);
384 TPRINTF ("\n");
385 break;
386 case 296:
387 TPRINTF ("ResolutionUnit = %d\n", theIFD[i].shortvalue);
388 break;
389 case 301:
390 TPRINTF ("Color response curve present at %ld, length %ld\n", theIFD[i].valueoffset, theIFD[i].length);
391 break;
392 case 320:
393 TPRINTF ("Colormap present at %ld\n", theIFD[i].valueoffset);
394 break;
395 default:
396 TPRINTF ("Tag %d unread.\n", theIFD[i].tag);
397 numinterpreted--;
398 }
399 }
400
401 TPRINTF ("Number of fields interpreted = %d\n\n", numinterpreted);
402
403 /*now that we've read most of what we might want to know, we can't
404 scratch all images that are too tedious to interpret. What we
405 are looking for is a class G greyscale with no compression */
406
407 if (spp != 1 || bitspersample[0] != 8 || comptype != 1 || fillorder != 1
408 || orient != 1) {
409 tifferror ("This kind of tiff file is not supported.\n");
410 goto freeall;
411 }
412
413 /*printf("rowstart = %ld, rowend = %ld.\n", rowstart, rowend);
414 */
415
416 /*check that rowstart and rowend are ok*/
417
418 if(rowstart > rowend) {
419 tifferror("Tiff called with rowstart > rowend.\n");
420 goto freeall;
421 }
422
423 if(rowstart > *height) rowstart = *height;
424
425 if(rowstart < 0) rowstart = 0;
426
427 if(rowend > *height) rowend = *height;
428
429 /*printf("width = %ld\n", *width);
430 printf("changeto rowstart = %ld, rowend = %ld.\n", rowstart, rowend);
431 */
432
433 if (( pic8 = malloc ((rowend-rowstart) * *width + 1) ) == NULL) {
434 tifferror ("Cannot allocate memory for tiff file.\n");
435 goto freeall;
436 }
437
438 index = 0;
439 if(gamma == 0) gamma = 1.5;
440
441 maxgrey = 0; mingrey = 1 << 30;
442 if(numgreylevels) {
443 for(i=0;i<numgreylevels;i++) {
444 maxgrey = max(maxgrey, greyresponsecurve[i]);
445 mingrey = min(mingrey, greyresponsecurve[i]);
446 }
447 for(i=0;i<numgreylevels;i++)
448 greyresponsecurve[i] = (double) 255 * pow((double) 1 - (double) ((double) greyresponsecurve[i] - mingrey) / (maxgrey - mingrey), (double) 1 / gamma);
449 }
450
451 if(rowend > rowstart)
452 for(i=rowstart;i<rowend;i++) {
453 /*:loop through all rows*/
454
455 pp = fgetstring (fp, stripoffsets[i/rps] + (i%rps) * *width, *width);
456 /*:load the row*/
457
458 /*OR pp = fdecodeLZW (fp, stripoffsets[i/rps] + (i%rps) * *width, *width); <-- for later*/
459
460 if(numgreylevels) {
461 for(j=0;j<*width;j++)
462 pic8[index++] = greyresponsecurve[pp[j]];
463 } else {
464 if(photointerp == 1)
465 for(j=0;j<*width;j++)
466 pic8[index++] = pp[j];
467 else
468 for(j=0;j<*width;j++)
469 pic8[index++] = 255 - pp[j];
470 }
471 if(index > (rowend-rowstart) * *width) {
472 printf("Index past end of array\n\n");
473 abort();
474 }
475 }
476
477 freeall:
478
479
480 if (greyresponsecurve)
481 free (greyresponsecurve);
482 if (stripbytecounts)
483 free (stripbytecounts);
484 if (stripoffsets)
485 free (stripoffsets);
486 if (theIFD)
487 free (theIFD);
488
489 if(fp) fclose(fp);
490
491 return pic8;
492 }
493
494
495