1 /**********************************************************************
2 * File: imgtiff.c (Formerly tiff.c)
3 * Description: Max format image reader/writer.
4 * Author: Ray Smith
5 * Created: Mon Jun 11 14:00:21 BST 1990
6 *
7 * (C) Copyright 1990, Hewlett-Packard Ltd.
8 ** Licensed under the Apache License, Version 2.0 (the "License");
9 ** you may not use this file except in compliance with the License.
10 ** You may obtain a copy of the License at
11 ** http://www.apache.org/licenses/LICENSE-2.0
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 *
18 **********************************************************************/
19
20 #include "mfcpch.h" //precompiled headers
21 #ifdef __MSW32__
22 #include <io.h>
23 #else
24 #include <unistd.h>
25 #endif
26
27 /*
28 ** Include automatically generated configuration file if running autoconf
29 */
30 #ifdef HAVE_CONFIG_H
31 #include "config_auto.h"
32 #if defined(MOTOROLA_BYTE_ORDER) || defined(WORDS_BIGENDIAN)
33 #define __MOTO__ // Big-endian.
34 #endif
35 #endif
36
37 #include "fileerr.h"
38 #include "imgerrs.h"
39 #include "img.h"
40 #include "bitstrm.h"
41 #include "tprintf.h"
42 #include "serialis.h"
43 #include "imgtiff.h"
44
45 #define INTEL 0x4949
46 #define MOTO 0x4d4d
47
48 /*************************************************************************
49 * NOTE ON BIG-ENDIAN vs LITTLE-ENDIAN
50 *
51 * Intel machines store numbers with LSByte in the left position.
52 * Motorola (and PA_RISC) machines use the opposite byte ordering.
53 *
54 * This code is written so that:
55 * a) it will compile and run on EITHER machine type AND
56 * b) the program (on either machine) will process tiff file written in either
57 * Motorola or Intel format.
58 *
59 * The code is compiled with a __NATIVE__ define which is either MOTO or INTEL.
60 * MOTO and INTEL are defined (above) to be the value of the first two bytes of
61 * a tiff file in either format. (This identifies the filetype).
62 *
63 * Subsequent reads and writes normally just reverse the byte order if the
64 * machine type (__NATIVE__) is not equal to the filetype determined from the
65 * first two bytes of the tiff file.
66 *
67 * A special case is the "value" field of the tag structure. This can contain
68 * EITHER a 16bit or a 32bit value. According to the "type" field. The 4 cases
69 * of machine type / file type combinations need to be treated differently in
70 * the case of 16 bit values
71 *************************************************************************/
72
73 #define ENTRIES 19 /*no of entries */
74 #define START 8 /*start of tag table */
75
76 typedef struct
77 {
78 uinT16 tag; //entry tag
79 uinT16 type;
80 uinT32 length;
81 inT32 value;
82 } TIFFENTRY; //tiff tag entry
83
84 typedef struct myrational
85 {
86 inT32 top;
87 inT32 bottom;
88 } MYRATIONAL; //type 5
89
90 //statics for the run length codes
91 #define EOL_CODE 0x800
92 #define EOL_MASK 0xfff
93 #define EOL_LENGTH 12 //12 bits
94 #define SHORT_CODE_SIZE 64 //no of short codes
95 #define LONG_CODE_SIZE 40 //no of long codes
96
97 static uinT16 short_white_codes[SHORT_CODE_SIZE] = {
98 0xac, 0x38, 0xe, 0x1, 0xd, 0x3, 0x7, 0xf,
99 0x19, 0x5, 0x1c, 0x2, 0x4, 0x30, 0xb, 0x2b,
100 0x15, 0x35, 0x72, 0x18, 0x8, 0x74, 0x60, 0x10,
101 0xa, 0x6a, 0x64, 0x12, 0xc, 0x40, 0xc0, 0x58,
102 0xd8, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x14,
103 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x20, 0xa0, 0x50,
104 0xd0, 0x4a, 0xca, 0x2a, 0xaa, 0x24, 0xa4, 0x1a,
105 0x9a, 0x5a, 0xda, 0x52, 0xd2, 0x4c, 0xcc, 0x2c
106 };
107 static uinT8 short_white_lengths[SHORT_CODE_SIZE] = {
108 8, 6, 4, 4, 4, 4, 4, 4,
109 5, 5, 5, 5, 6, 6, 6, 6,
110 6, 6, 7, 7, 7, 7, 7, 7,
111 7, 7, 7, 7, 7, 8, 8, 8,
112 8, 8, 8, 8, 8, 8, 8, 8,
113 8, 8, 8, 8, 8, 8, 8, 8,
114 8, 8, 8, 8, 8, 8, 8, 8,
115 8, 8, 8, 8, 8, 8, 8, 8
116 };
117 static uinT16 short_black_codes[SHORT_CODE_SIZE] = {
118 0x3b0, 0x2, 0x3, 0x1, 0x6, 0xc, 0x4, 0x18,
119 0x28, 0x8, 0x10, 0x50, 0x70, 0x20, 0xe0, 0x30,
120 0x3a0, 0x60, 0x40, 0x730, 0xb0, 0x1b0, 0x760, 0xa0,
121 0x740, 0xc0, 0x530, 0xd30,
122 0x330, 0xb30, 0x160, 0x960,
123 0x560, 0xd60, 0x4b0, 0xcb0,
124 0x2b0, 0xab0, 0x6b0, 0xeb0,
125 0x360, 0xb60, 0x5b0, 0xdb0,
126 0x2a0, 0xaa0, 0x6a0, 0xea0,
127 0x260, 0xa60, 0x4a0, 0xca0,
128 0x240, 0xec0, 0x1c0, 0xe40,
129 0x140, 0x1a0, 0x9a0, 0xd40,
130 0x340, 0x5a0, 0x660, 0xe60
131 };
132 static uinT8 short_black_lengths[SHORT_CODE_SIZE] = {
133 10, 3, 2, 2, 3, 4, 4, 5,
134 6, 6, 7, 7, 7, 8, 8, 9,
135 10, 10, 10, 11, 11, 11, 11, 11,
136 11, 11, 12, 12, 12, 12, 12, 12,
137 12, 12, 12, 12, 12, 12, 12, 12,
138 12, 12, 12, 12, 12, 12, 12, 12,
139 12, 12, 12, 12, 12, 12, 12, 12,
140 12, 12, 12, 12, 12, 12, 12, 12
141 };
142 static uinT16 long_white_codes[LONG_CODE_SIZE] = {
143 0x1b, 0x9, 0x3a, 0x76, 0x6c, 0xec, 0x26, 0xa6,
144 0x16, 0xe6, 0x66, 0x166, 0x96, 0x196, 0x56, 0x156,
145 0xd6, 0x1d6, 0x36, 0x136, 0xb6, 0x1b6, 0x32, 0x132,
146 0xb2, 0x6, 0x1b2,
147 0x80, 0x180, 0x580, 0x480, 0xc80,
148 0x280, 0xa80, 0x680, 0xe80, 0x380, 0xb80, 0x780, 0xf80
149 };
150 static uinT8 long_white_lengths[LONG_CODE_SIZE] = {
151 5, 5, 6, 7, 8, 8, 8, 8,
152 8, 8, 9, 9, 9, 9, 9, 9,
153 9, 9, 9, 9, 9, 9, 9, 9,
154 9, 6, 9, 11, 11, 11, 12, 12,
155 12, 12, 12, 12, 12, 12, 12, 12
156 };
157 static uinT16 long_black_codes[LONG_CODE_SIZE] = {
158 0x3c0, 0x130, 0x930, 0xda0,
159 0xcc0, 0x2c0, 0xac0, 0x6c0,
160 0x16c0, 0xa40, 0x1a40, 0x640,
161 0x1640, 0x9c0, 0x19c0, 0x5c0,
162 0x15c0, 0xdc0, 0x1dc0, 0x940,
163 0x1940, 0x540, 0x1540, 0xb40,
164 0x1b40, 0x4c0, 0x14c0,
165 0x80, 0x180, 0x580, 0x480, 0xc80,
166 0x280, 0xa80, 0x680, 0xe80, 0x380, 0xb80, 0x780, 0xf80
167 };
168 static uinT8 long_black_lengths[LONG_CODE_SIZE] = {
169 10, 12, 12, 12, 12, 12, 12, 13,
170 13, 13, 13, 13, 13, 13, 13, 13,
171 13, 13, 13, 13, 13, 13, 13, 13,
172 13, 13, 13, 11, 11, 11, 12, 12,
173 12, 12, 12, 12, 12, 12, 12, 12
174 };
175
176 /**********************************************************************
177 * open_tif_image
178 *
179 * Read the header of a tif format image and prepare to read the rest.
180 **********************************************************************/
181
open_tif_image(int fd,inT32 * xsize,inT32 * ysize,inT8 * bpp,inT8 * photo,inT32 * res)182 inT8 open_tif_image( //read header
183 int fd, //file to read
184 inT32 *xsize, //size of image
185 inT32 *ysize,
186 inT8 *bpp, //bits per pixel
187 inT8 *photo, //interpretation
188 inT32 *res //resolution
189 ) {
190 inT16 filetype;
191 inT32 start; //start of tiff directory
192 inT16 entries; //no of tiff entries
193 inT32 imagestart; //location of image in file
194 inT32 resoffset; //location of res
195 TIFFENTRY tiffentry; //tag table entry
196 BOOL8 compressed; //compression control
197 MYRATIONAL resinfo; //resolution
198 BOOL8 strips = false; //if in strips
199
200 *xsize = -1; //illegal values
201 *ysize = -1;
202 *bpp = -1;
203 *res = -1;
204 resoffset = -1;
205 if (read (fd, (char *) &filetype, sizeof filetype) != sizeof filetype
206 || (filetype != INTEL && filetype != MOTO)) {
207 BADIMAGEFORMAT.error ("read_tif_image", TESSLOG, "Filetype");
208 return -1;
209 }
210 lseek (fd, 4L, 0);
211 if (read (fd, (char *) &start, sizeof start) != sizeof start) {
212 READFAILED.error ("read_tif_image", TESSLOG, "Start of tag table");
213 return -1;
214 }
215
216 if (filetype != __NATIVE__)
217 start = reverse32 (start);
218 if (start <= 0) {
219 BADIMAGEFORMAT.error ("read_tif_image", TESSLOG, "Start of tag table");
220 return -1;
221 }
222 lseek (fd, start, 0);
223 if (read (fd, (char *) &entries, sizeof (inT16)) != sizeof (inT16)) {
224 BADIMAGEFORMAT.error ("read_tif_image", TESSLOG, "Size of tag table");
225 return -1;
226 }
227 if (filetype != __NATIVE__)
228 entries = reverse16 (entries);
229 // printf("No of tiff directory entries=%d\n",entries);
230 imagestart = 0;
231 compressed = FALSE;
232 int samples_per_pixel = 1;
233 int bits_per_sample = 1;
234 for (; entries-- > 0;) {
235 if (read (fd, (char *) &tiffentry, sizeof tiffentry) !=
236 sizeof tiffentry) {
237 BADIMAGEFORMAT.error ("read_tif_image", TESSLOG, "Tag table entry");
238 return -1;
239 }
240 if (filetype != __NATIVE__) {
241 tiffentry.type = reverse16 (tiffentry.type);
242 tiffentry.tag = reverse16 (tiffentry.tag);
243 tiffentry.length = reverse32 (tiffentry.length);
244 }
245 if (tiffentry.type != 3) { //Full 32bit value
246 if (filetype != __NATIVE__)
247 tiffentry.value = reverse32 (tiffentry.value);
248 }
249 else {
250 /* A 16bit value in 4 bytes - handle with care. SEE NOTE at start of file */
251 if (__NATIVE__ == MOTO) {
252 if (filetype == MOTO) //MOTO file on MOTO Machine
253 tiffentry.value = tiffentry.value >> 16;
254 else //INTEL file on MOTO Machine
255 tiffentry.value = reverse32 (tiffentry.value);
256 }
257 else { //INTEL Machine
258 if (filetype == MOTO) //MOTO file on INTEL Machine
259 tiffentry.value = reverse16 ((uinT16) tiffentry.value);
260 //INTEL file on INTEL Machine NO ACTION NEEDED
261 }
262 //Clear top 2 MSBytes
263 tiffentry.value &= 0x0000ffff;
264 }
265
266 // printf("Tag=%x, Type=%x, Length=%x, value=%x\n",
267 // tiffentry.tag,tiffentry.type,tiffentry.length,tiffentry.value);
268 switch (tiffentry.tag) {
269 case 0x101:
270 *ysize = tiffentry.value;
271 break;
272 case 0x100:
273 *xsize = tiffentry.value;
274 break;
275 case 0x102:
276 if (tiffentry.length == 1)
277 bits_per_sample = (inT8) tiffentry.value;
278 else
279 bits_per_sample = 8;
280 break;
281 case 0x115:
282 samples_per_pixel = (inT8) tiffentry.value;
283 break;
284 case 0x111:
285 imagestart = tiffentry.value;
286 strips = tiffentry.length > 1;
287 break;
288 case 0x103:
289 if (tiffentry.value == 3) {
290 compressed = TRUE;
291 }
292 else if (tiffentry.value != 1) {
293 BADIMAGEFORMAT.error ("read_tif_image", TESSLOG, "Compression");
294 return -1;
295 }
296 break;
297 case 0x11a:
298 case 0x11b:
299 //resolution
300 resoffset = tiffentry.value;
301 break;
302 case 0x106:
303 *photo = (inT8) tiffentry.value;
304 break;
305 } //endswitch
306 }
307 if (*xsize <= 0 || *ysize <= 0 || imagestart <= 0) {
308 BADIMAGEFORMAT.error ("read_tif_image", TESSLOG, "Vital tag");
309 return -1;
310 }
311 tprintf("Image has %d * %d bit%c per pixel, and size (%d,%d)\n",
312 bits_per_sample, samples_per_pixel, bits_per_sample == 1 ? ' ' : 's',
313 *xsize, *ysize);
314 *bpp = bits_per_sample * samples_per_pixel;
315 if (resoffset >= 0) {
316 lseek (fd, resoffset, 0);
317 if (read (fd, (char *) &resinfo, sizeof (resinfo)) != sizeof (resinfo)) {
318 READFAILED.error ("read_tif_image", TESSLOG, "Resolution");
319 return -1;
320 }
321 if (filetype != __NATIVE__) {
322 resinfo.top = reverse32 (resinfo.top);
323 resinfo.bottom = reverse32 (resinfo.bottom);
324 }
325 *res = resinfo.top / resinfo.bottom;
326 tprintf ("Resolution=%d\n", *res);
327 }
328 lseek (fd, (long) imagestart, 0);
329 if (strips) {
330 if (read (fd, (char *) &imagestart, sizeof (imagestart)) !=
331 sizeof (imagestart)) {
332 READFAILED.error ("read_tif_image", TESSLOG, "Strip offset");
333 return -1;
334 }
335 if (filetype != __NATIVE__)
336 imagestart = reverse32 (imagestart);
337 //indirection
338 lseek (fd, (long) imagestart, 0);
339 }
340 return compressed ? -2 : 0;
341 }
342
343
344 /**********************************************************************
345 * read_tif_image
346 *
347 * Read a whole tif image into memory.
348 **********************************************************************/
349
read_tif_image(int fd,uinT8 * pixels,inT32 xsize,inT32 ysize,inT8 bpp,inT32)350 inT8 read_tif_image( //read whole image
351 int fd, //file to read
352 uinT8 *pixels, //pixels of image
353 inT32 xsize, //size of image
354 inT32 ysize,
355 inT8 bpp, //bits per pixel
356 inT32 //bytes per line
357 ) {
358 inT32 xindex; //indices in image
359 inT32 yindex;
360 inT32 length; //short length
361 inT32 biglength; //extender
362 uinT8 *lengths; //current lengths
363 uinT16 *codes; //current codes
364 uinT16 codeword; //current code word
365 IMAGELINE imageline; //current line
366 IMAGE image; //dummy image
367 R_BITSTREAM bits; //read bitstream
368 uinT8 colour; //current colour
369
370 image.capture (pixels, xsize, ysize, bpp);
371 codeword = bits.open (fd); //open bitstream
372 read_eol(&bits, codeword); //find end of line
373 for (yindex = ysize - 1; yindex >= 0; yindex--) {
374 imageline.init ();
375 colour = TRUE;
376 for (xindex = 0; xindex < xsize;) {
377 if (colour) {
378 lengths = long_white_lengths;
379 codes = long_white_codes;
380 }
381 else {
382 lengths = long_black_lengths;
383 codes = long_black_codes;
384 }
385 for (biglength = 0; biglength < LONG_CODE_SIZE
386 && (codeword & bits.masks (*lengths))
387 != *codes; codes++, lengths++, biglength++);
388 if (biglength < LONG_CODE_SIZE) {
389 codeword = bits.read_code (*lengths);
390 biglength++;
391 biglength *= SHORT_CODE_SIZE;
392 }
393 else
394 biglength = 0;
395 if (colour) {
396 lengths = short_white_lengths;
397 codes = short_white_codes;
398 }
399 else {
400 lengths = short_black_lengths;
401 codes = short_black_codes;
402 }
403 for (length = 0; length < SHORT_CODE_SIZE
404 && (codeword & bits.masks (*lengths))
405 != *codes; codes++, lengths++, length++);
406 if (length < SHORT_CODE_SIZE) {
407 codeword = bits.read_code (*lengths);
408 for (length += biglength; length > 0; length--, xindex++)
409 imageline.pixels[xindex] = colour;
410 colour = !colour;
411 }
412 else
413 break;
414 }
415 if (xindex < xsize) {
416 tprintf ("%d pixels short on line %d", xsize - xindex, yindex);
417 tprintf (", unknown code=%x\n", codeword);
418 }
419 xindex = read_eol (&bits, codeword);
420 if (xindex > 0)
421 tprintf ("Discarding %d bits on line %d\n", xindex, yindex);
422 image.put_line (0, yindex, xsize, &imageline, 0);
423 }
424 return 0;
425 }
426
427
428 /**********************************************************************
429 * read_eol
430 *
431 * Take bits out of the stream until and end-of-line code is hit.
432 **********************************************************************/
433
read_eol(R_BITSTREAM * bits,uinT16 & code)434 inT32 read_eol( //read end of line
435 R_BITSTREAM *bits, //bitstream to read
436 uinT16 &code //current code
437 ) {
438 BOOL8 anyones; //any 1 bits skipped
439 inT32 bitcount; //total bits skipped
440
441 anyones = FALSE;
442 bitcount = 0;
443 while ((code & EOL_MASK) != EOL_CODE) {
444 if (code & 1)
445 anyones = TRUE; //discarded one bit
446 bitcount++; //total discarded bits
447 code = bits->read_code (1); //take single bits
448 }
449 //extract EOL code
450 code = bits->read_code (EOL_LENGTH);
451
452 if (!anyones)
453 bitcount = 0; //ignore filler bits
454 return bitcount;
455 }
456
457
458 /**********************************************************************
459 * write_moto_tif
460 *
461 * Write a whole tif format image and close the file.
462 **********************************************************************/
463
write_moto_tif(int fd,uinT8 * pixels,inT32 xsize,inT32 ysize,inT8 bpp,inT8 photo,inT32 res)464 inT8 write_moto_tif( //write whole image
465 int fd, //file to write on
466 uinT8 *pixels, //image pixels
467 inT32 xsize, //size of image
468 inT32 ysize,
469 inT8 bpp, //bits per pixel
470 inT8 photo,
471 inT32 res //resolution
472 ) {
473 return write_tif_image (fd, pixels, xsize, ysize, bpp, res, MOTO, photo);
474 //use moto format
475 }
476
477
478 /**********************************************************************
479 * write_intel_tif
480 *
481 * Write a whole tif format image and close the file.
482 **********************************************************************/
483
write_intel_tif(int fd,uinT8 * pixels,inT32 xsize,inT32 ysize,inT8 bpp,inT8 photo,inT32 res)484 inT8 write_intel_tif( //write whole image
485 int fd, //file to write on
486 uinT8 *pixels, //image pixels
487 inT32 xsize, //size of image
488 inT32 ysize,
489 inT8 bpp, //bits per pixel
490 inT8 photo,
491 inT32 res //resolution
492 ) {
493 return write_tif_image (fd, pixels, xsize, ysize, bpp, res, INTEL, photo);
494 //use intel format
495 }
496
497
498 /**********************************************************************
499 * write_inverse_tif
500 *
501 * Write a whole tif format image and close the file.
502 **********************************************************************/
503
write_inverse_tif(int fd,uinT8 * pixels,inT32 xsize,inT32 ysize,inT8 bpp,inT8 photo,inT32 res)504 inT8 write_inverse_tif( //write whole image
505 int fd, //file to write on
506 uinT8 *pixels, //image pixels
507 inT32 xsize, //size of image
508 inT32 ysize,
509 inT8 bpp, //bits per pixel
510 inT8 photo,
511 inT32 res //resolution
512 ) {
513 return write_tif_image (fd, pixels, xsize, ysize, bpp, res, INTEL,
514 1 - photo);
515 //use intel format
516 }
517
518
519 /**********************************************************************
520 * write_tif_image
521 *
522 * Write a whole tif format image and close the file.
523 **********************************************************************/
524
write_tif_image(int fd,uinT8 * pixels,inT32 xsize,inT32 ysize,inT8 bpp,inT32 res,inT16 type,inT16 photo)525 inT8 write_tif_image( //write whole image
526 int fd, //file to write on
527 uinT8 *pixels, //image pixels
528 inT32 xsize, //size of image
529 inT32 ysize,
530 inT8 bpp, //bits per pixel
531 inT32 res, //resolution
532 inT16 type, //format type
533 inT16 photo //metric interp
534 ) {
535 inT32 size; //line/image size
536 inT16 entries; //no of tiff entries
537 inT32 start; //start of tag table
538 inT32 zero = 0;
539 MYRATIONAL resolution; //resolution
540 TIFFENTRY entry; //current entry
541
542 static TIFFENTRY tags[ENTRIES] = {
543 {0xfe, 4, 1, 0},
544 {0x100, 3, 1, 0},
545 {0x101, 3, 1, 0},
546 {0x102, 3, 1, 0},
547 {0x103, 3, 1, 1},
548 {0x106, 3, 1, 1},
549 { /*line art */
550 0x107, 3, 1, 1
551 },
552 {0x10a, 3, 1, 1},
553 {
554 0x111, 4, 1, START + ENTRIES * sizeof (TIFFENTRY)
555 + sizeof (inT32) + sizeof (short) + sizeof (MYRATIONAL) * 2
556 }
557 ,
558 {0x112, 3, 1, 1}
559 ,
560 {0x115, 3, 1, 1}
561 ,
562 {0x116, 4, 1, 0}
563 ,
564 {0x117, 4, 1, 0}
565 ,
566 {0x118, 3, 1, 0}
567 ,
568 {0x119, 3, 1, 1}
569 ,
570 {
571 0x11a, 5, 1, START + ENTRIES * sizeof (TIFFENTRY)
572 + sizeof (inT32) + sizeof (short)
573 },
574 {
575 0x11b, 5, 1, START + ENTRIES * sizeof (TIFFENTRY)
576 + sizeof (inT32) + sizeof (short) + sizeof (MYRATIONAL)
577 }
578 ,
579 {0x11c, 3, 1, 1}
580 ,
581 {0x128, 3, 1, 2}
582 };
583
584 resolution.top = res;
585 resolution.bottom = 1;
586 if (write (fd, (char *) &type, sizeof type) != sizeof type
587 || (type != INTEL && type != MOTO)) {
588 WRITEFAILED.error ("write_tif_image", TESSLOG, "Filetype");
589 return -1;
590 }
591 start = START;
592 entries = 0x002a;
593 if (type != __NATIVE__)
594 entries = reverse16 (entries);
595 if (write (fd, (char *) &entries, sizeof entries) != sizeof entries) {
596 WRITEFAILED.error ("write_tif_image", TESSLOG, "Version");
597 return -1;
598 }
599 if (type != __NATIVE__)
600 start = reverse32 (start);
601 if (write (fd, (char *) &start, sizeof start) != sizeof start) {
602 WRITEFAILED.error ("write_tif_image", TESSLOG, "Start");
603 return -1;
604 }
605 lseek (fd, (long) START, 0);
606 entries = ENTRIES;
607 if (type != __NATIVE__)
608 entries = reverse16 (entries);
609 if (write (fd, (char *) &entries, sizeof entries) != sizeof entries) {
610 WRITEFAILED.error ("write_tif_image", TESSLOG, "Entries");
611 return -1;
612 }
613 //line length
614 size = COMPUTE_IMAGE_XDIM (xsize, bpp);
615 size *= ysize; //total image size
616 // if (photo==0)
617 // {
618 // tags[0].tag=0xfe;
619 // tags[0].type=4;
620 // tags[0].value=0;
621 // }
622 // else
623 // {
624 // tags[0].tag=0xff;
625 // tags[0].type=3;
626 // tags[0].value=1;
627 // }
628 tags[1].value = xsize;
629 tags[2].value = ysize;
630 if (bpp == 24) {
631 tags[3].value = 8;
632 tags[10].value = 3;
633 tags[5].value = 2;
634 }
635 else {
636 tags[3].value = bpp;
637 tags[5].value = photo;
638 }
639 tags[11].value = ysize;
640 tags[14].value = (1 << bpp) - 1;
641 tags[12].value = size;
642 for (entries = 0; entries < ENTRIES; entries++) {
643 entry = tags[entries]; //get an entry
644 /* NB Convert entry.value BEFORE converting entry.type!!! */
645 if (entry.type != 3) { //Full 32bit value
646 if (type != __NATIVE__)
647 entry.value = reverse32 (entry.value);
648 }
649 else {
650 /* A 16bit value in 4 bytes - handle with care. SEE NOTE at start of file */
651 entry.value &= 0x0000ffff; //Ensure top 2 MSBytes clear
652 if (__NATIVE__ == MOTO) {
653 if (type == MOTO) //MOTO file on MOTO Machine
654 entry.value = entry.value << 16;
655 else //INTEL file on MOTO Machine
656 entry.value = reverse32 (entry.value);
657 }
658 else { //INTEL Machine
659 if (type == MOTO) //MOTO file on INTEL Machine
660 entry.value = reverse16 ((uinT16) entry.value);
661 //INTEL file on INTEL Machine NO ACTION NEEDED
662 }
663 }
664 if (type != __NATIVE__) {
665 entry.tag = reverse16 (entry.tag);
666 entry.type = reverse16 (entry.type);
667 entry.length = reverse32 (entry.length);
668 }
669 if (write (fd, (char *) &entry, sizeof (TIFFENTRY)) !=
670 sizeof (TIFFENTRY)) {
671 WRITEFAILED.error ("write_tif_image", TESSLOG, "Tag Table");
672 return -1;
673 }
674 }
675 if (write (fd, (char *) &zero, sizeof zero) != sizeof zero) {
676 WRITEFAILED.error ("write_tif_image", TESSLOG, "Tag table Terminator");
677 return -1;
678 }
679 if (type != __NATIVE__) {
680 resolution.top = reverse32 (resolution.top);
681 resolution.bottom = reverse32 (resolution.bottom);
682 }
683 if (write (fd, (char *) &resolution, sizeof resolution) != sizeof resolution
684 || write (fd, (char *) &resolution,
685 sizeof resolution) != sizeof resolution) {
686 WRITEFAILED.error ("write_tif_image", TESSLOG, "Resolution");
687 return -1;
688 }
689 if (write (fd, (char *) pixels, (size_t) size) != size) {
690 WRITEFAILED.error ("write_tif_image", TESSLOG, "Image");
691 return -1;
692 }
693 close(fd);
694 return 0;
695 }
696
697
698 /**********************************************************************
699 * reverse32
700 *
701 * Byte swap the 32 bit number between Motorola & Intel format.
702 **********************************************************************/
703
704 //inT32 reverse32( //reverse 32 bit int
705 //uinT32 value //value to reverse
706 //)
707 //{
708 // return (value>>24) | (value>>8) & 0xff00
709 // | (value<<8) & 0xff0000 | (value<<24);
710 //}
711
712 /**********************************************************************
713 * reverse16
714 *
715 * Byte swap the 16 bit number between Motorola & Intel format.
716 **********************************************************************/
717
718 //inT16 reverse16( //reverse 16 bit int
719 //uinT16 value //value to reverse
720 //)
721 //{
722 // return (value>>8) | (value<<8);
723 //}
724