Various changes:
[imager.git] / tiff.c
CommitLineData
92bda632 1#include "imager.h"
02d1d628
AMH
2#include "tiffio.h"
3#include "iolayer.h"
92bda632 4#include "imageri.h"
5c829fcf 5
02d1d628
AMH
6/*
7=head1 NAME
8
9tiff.c - implements reading and writing tiff files, uses io layer.
10
11=head1 SYNOPSIS
12
13 io_glue *ig = io_new_fd( fd );
14 i_img *im = i_readtiff_wiol(ig, -1); // no limit on how much is read
15 // or
16 io_glue *ig = io_new_fd( fd );
17 return_code = i_writetiff_wiol(im, ig);
18
19=head1 DESCRIPTION
20
21tiff.c implements the basic functions to read and write tiff files.
22It uses the iolayer and needs either a seekable source or an entire
23memory mapped buffer.
24
25=head1 FUNCTION REFERENCE
26
27Some of these functions are internal.
28
b8c2033e 29=over
02d1d628
AMH
30
31=cut
32*/
33
5c829fcf
AMH
34#define byteswap_macro(x) \
35 ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
36 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
37
fd9a31d2
TC
38struct tag_name {
39 char *name;
40 uint32 tag;
41};
42
43static struct tag_name text_tag_names[] =
44{
45 { "tiff_documentname", TIFFTAG_DOCUMENTNAME, },
46 { "tiff_imagedescription", TIFFTAG_IMAGEDESCRIPTION, },
47 { "tiff_make", TIFFTAG_MAKE, },
48 { "tiff_model", TIFFTAG_MODEL, },
49 { "tiff_pagename", TIFFTAG_PAGENAME, },
50 { "tiff_software", TIFFTAG_SOFTWARE, },
51 { "tiff_datetime", TIFFTAG_DATETIME, },
52 { "tiff_artist", TIFFTAG_ARTIST, },
53 { "tiff_hostcomputer", TIFFTAG_HOSTCOMPUTER, },
54};
55
56static const int text_tag_count =
57 sizeof(text_tag_names) / sizeof(*text_tag_names);
5c829fcf 58
5bb828f1
TC
59static void error_handler(char const *module, char const *fmt, va_list ap) {
60 i_push_errorvf(0, fmt, ap);
61}
62
ffeb4a67
TC
63#define WARN_BUFFER_LIMIT 10000
64static char *warn_buffer = NULL;
65static int warn_buffer_size = 0;
66
be371490 67static void warn_handler(char const *module, char const *fmt, va_list ap) {
ffeb4a67
TC
68 char buf[1000];
69
70 buf[0] = '\0';
71#ifdef HAVE_SNPRINTF
72 vsnprintf(buf, sizeof(buf), fmt, ap);
73#else
74 vsprintf(buf, fmt, ap);
75#endif
76 if (!warn_buffer || strlen(warn_buffer)+strlen(buf)+2 > warn_buffer_size) {
77 int new_size = warn_buffer_size + strlen(buf) + 2;
78 char *old_buffer = warn_buffer;
79 if (new_size > WARN_BUFFER_LIMIT) {
80 new_size = WARN_BUFFER_LIMIT;
81 }
82 warn_buffer = myrealloc(warn_buffer, new_size);
83 if (!old_buffer) *warn_buffer = '\0';
84 warn_buffer_size = new_size;
85 }
86 if (strlen(warn_buffer)+strlen(buf)+2 <= warn_buffer_size) {
87 strcat(warn_buffer, buf);
88 strcat(warn_buffer, "\n");
89 }
be371490
TC
90}
91
5bb828f1
TC
92static int save_tiff_tags(TIFF *tif, i_img *im);
93
94static void expand_4bit_hl(unsigned char *buf, int count);
95
f62b2d84
TC
96static void pack_4bit_hl(unsigned char *buf, int count);
97
caa833d5
AMH
98
99static toff_t sizeproc(thandle_t x) {
100 return 0;
101}
102
103
02d1d628
AMH
104/*
105=item comp_seek(h, o, w)
106
107Compatability for 64 bit systems like latest freebsd (internal)
108
109 h - tiff handle, cast an io_glue object
110 o - offset
111 w - whence
112
113=cut
114*/
115
116static
117toff_t
118comp_seek(thandle_t h, toff_t o, int w) {
119 io_glue *ig = (io_glue*)h;
120 return (toff_t) ig->seekcb(ig, o, w);
121}
122
e18f39b3
TC
123/*
124=item comp_mmap(thandle_t, tdata_t*, toff_t*)
125
126Dummy mmap stub.
127
128This shouldn't ever be called but newer tifflibs want it anyway.
129
130=cut
131*/
132
133static
134int
135comp_mmap(thandle_t h, tdata_t*p, toff_t*off) {
136 return -1;
137}
138
139/*
140=item comp_munmap(thandle_t h, tdata_t p, toff_t off)
141
142Dummy munmap stub.
143
144This shouldn't ever be called but newer tifflibs want it anyway.
145
146=cut
147*/
148
149static void
150comp_munmap(thandle_t h, tdata_t p, toff_t off) {
151 /* do nothing */
152}
153
9c106321 154static i_img *read_one_tiff(TIFF *tif, int allow_partial) {
02d1d628
AMH
155 i_img *im;
156 uint32 width, height;
157 uint16 channels;
5bb828f1 158 uint32* raster = NULL;
02d1d628 159 int tiled, error;
faa9b3e7
TC
160 float xres, yres;
161 uint16 resunit;
162 int gotXres, gotYres;
fd9a31d2 163 uint16 photometric;
5bb828f1 164 uint16 bits_per_sample;
fd9a31d2 165 int i;
5bb828f1 166 int ch;
02d1d628
AMH
167
168 error = 0;
169
02d1d628
AMH
170 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
171 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
5bb828f1 172 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &channels);
02d1d628 173 tiled = TIFFIsTiled(tif);
5bb828f1
TC
174 TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric);
175 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
02d1d628
AMH
176
177 mm_log((1, "i_readtiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
178 mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not "));
179 mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not "));
faa9b3e7 180
a50608d2
TC
181 /* separated defaults to CMYK, but if the user is using some strange
182 ink system we can't work out the color anyway */
183 if (photometric == PHOTOMETRIC_SEPARATED && channels >= 4) {
184 /* TIFF can have more than one alpha channel on an image,
185 but Imager can't, only store the first one */
186
187 channels = channels == 4 ? 3 : 4;
188
189 /* unfortunately the RGBA functions don't try to deal with the alpha
190 channel on CMYK images, at some point I'm planning on expanding
191 TIFF support to handle 16-bit/sample images and I'll deal with
192 it then */
193 }
194
195 /* TIFF images can have more than one alpha channel, but Imager can't
196 this ignores the possibility of 2 channel images with 2 alpha,
197 but there's not much I can do about that */
198 if (channels > 4)
199 channels = 4;
200
5bb828f1
TC
201 if (photometric == PHOTOMETRIC_PALETTE && bits_per_sample <= 8) {
202 channels = 3;
203 im = i_img_pal_new(width, height, channels, 256);
204 }
205 else {
206 im = i_img_empty_ch(NULL, width, height, channels);
207 }
8c3af7b3
TC
208
209 if (!im)
210 return NULL;
f00e06a0
TC
211
212 /* general metadata */
213 i_tags_addn(&im->tags, "tiff_bitspersample", 0, bits_per_sample);
214 i_tags_addn(&im->tags, "tiff_photometric", 0, photometric);
5bb828f1 215
fd9a31d2 216 /* resolution tags */
5bb828f1 217 TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
faa9b3e7
TC
218 gotXres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
219 gotYres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
220 if (gotXres || gotYres) {
221 if (!gotXres)
222 xres = yres;
223 else if (!gotYres)
224 yres = xres;
3cff89e2 225 i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
faa9b3e7
TC
226 if (resunit == RESUNIT_CENTIMETER) {
227 /* from dots per cm to dpi */
228 xres *= 2.54;
229 yres *= 2.54;
616b2541 230 i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "centimeter", -1, 0);
faa9b3e7 231 }
3cff89e2 232 else if (resunit == RESUNIT_NONE) {
faa9b3e7 233 i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
3cff89e2
TC
234 i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "none", -1, 0);
235 }
236 else if (resunit == RESUNIT_INCH) {
237 i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "inch", -1, 0);
238 }
239 else {
240 i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "unknown", -1, 0);
241 }
2e41e30b
TC
242 /* tifflib doesn't seem to provide a way to get to the original rational
243 value of these, which would let me provide a more reasonable
244 precision. So make up a number. */
245 i_tags_set_float2(&im->tags, "i_xres", 0, xres, 6);
246 i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6);
faa9b3e7 247 }
fd9a31d2
TC
248
249 /* Text tags */
250 for (i = 0; i < text_tag_count; ++i) {
251 char *data;
252 if (TIFFGetField(tif, text_tag_names[i].tag, &data)) {
253 mm_log((1, "i_readtiff_wiol: tag %d has value %s\n",
254 text_tag_names[i].tag, data));
255 i_tags_add(&im->tags, text_tag_names[i].name, 0, data,
256 strlen(data), 0);
257 }
258 }
8c3af7b3
TC
259
260 i_tags_add(&im->tags, "i_format", 0, "tiff", -1, 0);
ffeb4a67
TC
261 if (warn_buffer && *warn_buffer) {
262 i_tags_add(&im->tags, "i_warning", 0, warn_buffer, -1, 0);
263 *warn_buffer = '\0';
264 }
02d1d628
AMH
265
266 /* TIFFPrintDirectory(tif, stdout, 0); good for debugging */
02d1d628 267
5bb828f1
TC
268 if (photometric == PHOTOMETRIC_PALETTE &&
269 (bits_per_sample == 4 || bits_per_sample == 8)) {
270 uint16 *maps[3];
271 char used[256];
272 int maxused;
273 uint32 row, col;
274 unsigned char *buffer;
02d1d628 275
5bb828f1
TC
276 if (!TIFFGetField(tif, TIFFTAG_COLORMAP, maps+0, maps+1, maps+2)) {
277 i_push_error(0, "Cannot get colormap for paletted image");
5bb828f1 278 i_img_destroy(im);
02d1d628
AMH
279 return NULL;
280 }
5bb828f1
TC
281 buffer = (unsigned char *)_TIFFmalloc(width+2);
282 if (!buffer) {
283 i_push_error(0, "out of memory");
5bb828f1 284 i_img_destroy(im);
5bb828f1
TC
285 return NULL;
286 }
287 row = 0;
288 memset(used, 0, sizeof(used));
289 while (row < height && TIFFReadScanline(tif, buffer, row, 0) > 0) {
290 if (bits_per_sample == 4)
291 expand_4bit_hl(buffer, (width+1)/2);
292 for (col = 0; col < width; ++col) {
293 used[buffer[col]] = 1;
02d1d628 294 }
5bb828f1
TC
295 i_ppal(im, 0, width, row, buffer);
296 ++row;
02d1d628 297 }
5bb828f1 298 if (row < height) {
9c106321
TC
299 if (allow_partial) {
300 i_tags_setn(&im->tags, "i_lines_read", row);
301 }
302 else {
303 i_img_destroy(im);
304 _TIFFfree(buffer);
305 return NULL;
306 }
5bb828f1 307 error = 1;
02d1d628 308 }
5bb828f1
TC
309 /* Ideally we'd optimize the palette, but that could be expensive
310 since we'd have to re-index every pixel.
311
312 Optimizing the palette (even at this level) might not
313 be what the user wants, so I don't do it.
314
315 We'll add a function to optimize a paletted image instead.
316 */
317 maxused = (1 << bits_per_sample)-1;
318 if (!error) {
319 while (maxused >= 0 && !used[maxused])
320 --maxused;
321 }
322 for (i = 0; i < 1 << bits_per_sample; ++i) {
323 i_color c;
324 for (ch = 0; ch < 3; ++ch) {
325 c.channel[ch] = Sample16To8(maps[ch][i]);
326 }
327 i_addcolors(im, &c, 1);
328 }
329 _TIFFfree(buffer);
330 }
331 else {
332 if (tiled) {
333 int ok = 1;
334 uint32 row, col;
335 uint32 tile_width, tile_height;
336
337 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
338 TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
339 mm_log((1, "i_readtiff_wiol: tile_width=%d, tile_height=%d\n", tile_width, tile_height));
02d1d628 340
5bb828f1
TC
341 raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
342 if (!raster) {
343 i_img_destroy(im);
344 i_push_error(0, "No space for raster buffer");
5bb828f1 345 return NULL;
02d1d628
AMH
346 }
347
5bb828f1
TC
348 for( row = 0; row < height; row += tile_height ) {
349 for( col = 0; ok && col < width; col += tile_width ) {
350 uint32 i_row, x, newrows, newcols;
351
352 /* Read the tile into an RGBA array */
353 if (!TIFFReadRGBATile(tif, col, row, raster)) {
354 ok = 0;
355 break;
356 }
357 newrows = (row+tile_height > height) ? height-row : tile_height;
358 mm_log((1, "i_readtiff_wiol: newrows=%d\n", newrows));
359 newcols = (col+tile_width > width ) ? width-row : tile_width;
360 for( i_row = 0; i_row < tile_height; i_row++ ) {
361 for(x = 0; x < newcols; x++) {
362 i_color val;
363 uint32 temp = raster[x+tile_width*(tile_height-i_row-1)];
364 val.rgba.r = TIFFGetR(temp);
365 val.rgba.g = TIFFGetG(temp);
366 val.rgba.b = TIFFGetB(temp);
367 val.rgba.a = TIFFGetA(temp);
368 i_ppix(im, col+x, row+i_row, &val);
369 }
370 }
371 }
372 }
373 } else {
374 uint32 rowsperstrip, row;
1b0554d1
AMH
375 int rc = TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
376 mm_log((1, "i_readtiff_wiol: rowsperstrip=%d rc = %d\n", rowsperstrip, rc));
377
378 if (rc != 1 || rowsperstrip==-1) {
379 rowsperstrip = height;
380 }
381
5bb828f1
TC
382 raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
383 if (!raster) {
384 i_img_destroy(im);
385 i_push_error(0, "No space for raster buffer");
5bb828f1
TC
386 return NULL;
387 }
02d1d628 388
5bb828f1
TC
389 for( row = 0; row < height; row += rowsperstrip ) {
390 uint32 newrows, i_row;
391
392 if (!TIFFReadRGBAStrip(tif, row, raster)) {
9c106321
TC
393 if (allow_partial) {
394 i_tags_setn(&im->tags, "i_lines_read", row);
395 error++;
396 break;
397 }
398 else {
399 i_push_error(0, "could not read TIFF image strip");
400 _TIFFfree(raster);
401 i_img_destroy(im);
402 return NULL;
403 }
5bb828f1
TC
404 }
405
406 newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip;
407 mm_log((1, "newrows=%d\n", newrows));
408
409 for( i_row = 0; i_row < newrows; i_row++ ) {
410 uint32 x;
411 for(x = 0; x<width; x++) {
412 i_color val;
413 uint32 temp = raster[x+width*(newrows-i_row-1)];
414 val.rgba.r = TIFFGetR(temp);
415 val.rgba.g = TIFFGetG(temp);
416 val.rgba.b = TIFFGetB(temp);
417 val.rgba.a = TIFFGetA(temp);
418 i_ppix(im, x, i_row+row, &val);
419 }
420 }
02d1d628
AMH
421 }
422 }
02d1d628
AMH
423 }
424 if (error) {
425 mm_log((1, "i_readtiff_wiol: error during reading\n"));
9c106321 426 i_tags_setn(&im->tags, "i_incomplete", 1);
02d1d628 427 }
5bb828f1
TC
428 if (raster)
429 _TIFFfree( raster );
10461f9a
TC
430
431 return im;
432}
433
434/*
435=item i_readtiff_wiol(im, ig)
436
437=cut
438*/
439i_img*
9c106321 440i_readtiff_wiol(io_glue *ig, int allow_partial, int page) {
10461f9a
TC
441 TIFF* tif;
442 TIFFErrorHandler old_handler;
be371490 443 TIFFErrorHandler old_warn_handler;
10461f9a
TC
444 i_img *im;
445
446 i_clear_error();
447 old_handler = TIFFSetErrorHandler(error_handler);
be371490 448 old_warn_handler = TIFFSetWarningHandler(warn_handler);
ffeb4a67
TC
449 if (warn_buffer)
450 *warn_buffer = '\0';
10461f9a
TC
451
452 /* Add code to get the filename info from the iolayer */
453 /* Also add code to check for mmapped code */
454
455 io_glue_commit_types(ig);
9c106321 456 mm_log((1, "i_readtiff_wiol(ig %p, allow_partial %d, page %d)\n", ig, allow_partial, page));
10461f9a
TC
457
458 tif = TIFFClientOpen("(Iolayer)",
459 "rm",
460 (thandle_t) ig,
461 (TIFFReadWriteProc) ig->readcb,
462 (TIFFReadWriteProc) ig->writecb,
463 (TIFFSeekProc) comp_seek,
464 (TIFFCloseProc) ig->closecb,
caa833d5 465 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
e18f39b3
TC
466 (TIFFMapFileProc) comp_mmap,
467 (TIFFUnmapFileProc) comp_munmap);
10461f9a
TC
468
469 if (!tif) {
470 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
2691d220 471 i_push_error(0, "Error opening file");
10461f9a 472 TIFFSetErrorHandler(old_handler);
be371490 473 TIFFSetWarningHandler(old_warn_handler);
10461f9a
TC
474 return NULL;
475 }
476
8f8bd9aa
TC
477 if (page != 0) {
478 if (!TIFFSetDirectory(tif, page)) {
479 mm_log((1, "i_readtiff_wiol: Unable to switch to directory %d\n", page));
480 i_push_errorf(0, "could not switch to page %d", page);
481 TIFFSetErrorHandler(old_handler);
482 TIFFSetWarningHandler(old_warn_handler);
01f2d357 483 TIFFClose(tif);
8f8bd9aa
TC
484 return NULL;
485 }
486 }
487
9c106321 488 im = read_one_tiff(tif, allow_partial);
10461f9a 489
02d1d628 490 if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
5bb828f1 491 TIFFSetErrorHandler(old_handler);
be371490 492 TIFFSetWarningHandler(old_warn_handler);
5bb828f1 493 TIFFClose(tif);
02d1d628
AMH
494 return im;
495}
496
10461f9a
TC
497/*
498=item i_readtiff_multi_wiol(ig, length, *count)
02d1d628 499
10461f9a 500Reads multiple images from a TIFF.
02d1d628 501
10461f9a
TC
502=cut
503*/
504i_img**
505i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
506 TIFF* tif;
507 TIFFErrorHandler old_handler;
be371490 508 TIFFErrorHandler old_warn_handler;
10461f9a
TC
509 i_img **results = NULL;
510 int result_alloc = 0;
511 int dirnum = 0;
02d1d628 512
10461f9a
TC
513 i_clear_error();
514 old_handler = TIFFSetErrorHandler(error_handler);
be371490 515 old_warn_handler = TIFFSetWarningHandler(warn_handler);
ffeb4a67
TC
516 if (warn_buffer)
517 *warn_buffer = '\0';
02d1d628 518
10461f9a
TC
519 /* Add code to get the filename info from the iolayer */
520 /* Also add code to check for mmapped code */
02d1d628 521
10461f9a
TC
522 io_glue_commit_types(ig);
523 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
524
525 tif = TIFFClientOpen("(Iolayer)",
526 "rm",
527 (thandle_t) ig,
528 (TIFFReadWriteProc) ig->readcb,
529 (TIFFReadWriteProc) ig->writecb,
530 (TIFFSeekProc) comp_seek,
531 (TIFFCloseProc) ig->closecb,
e18f39b3
TC
532 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
533 (TIFFMapFileProc) comp_mmap,
534 (TIFFUnmapFileProc) comp_munmap);
10461f9a
TC
535
536 if (!tif) {
537 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
2691d220 538 i_push_error(0, "Error opening file");
10461f9a 539 TIFFSetErrorHandler(old_handler);
be371490 540 TIFFSetWarningHandler(old_warn_handler);
10461f9a
TC
541 return NULL;
542 }
02d1d628 543
10461f9a
TC
544 *count = 0;
545 do {
9c106321 546 i_img *im = read_one_tiff(tif, 0);
10461f9a
TC
547 if (!im)
548 break;
549 if (++*count > result_alloc) {
550 if (result_alloc == 0) {
551 result_alloc = 5;
552 results = mymalloc(result_alloc * sizeof(i_img *));
553 }
554 else {
555 i_img **newresults;
556 result_alloc *= 2;
557 newresults = myrealloc(results, result_alloc * sizeof(i_img *));
be371490
TC
558 if (!newresults) {
559 i_img_destroy(im); /* don't leak it */
560 break;
561 }
562 results = newresults;
10461f9a
TC
563 }
564 }
565 results[*count-1] = im;
566 } while (TIFFSetDirectory(tif, ++dirnum));
567
be371490 568 TIFFSetWarningHandler(old_warn_handler);
10461f9a
TC
569 TIFFSetErrorHandler(old_handler);
570 TIFFClose(tif);
571 return results;
572}
02d1d628
AMH
573
574undef_int
10461f9a
TC
575i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) {
576 uint32 width, height;
577 unsigned char *linebuf = NULL;
578 uint32 y;
579 int rc;
580 uint32 x;
10461f9a
TC
581 uint32 rowsperstrip;
582 float vres = fine ? 196 : 98;
583 int luma_chan;
584
585 width = im->xsize;
586 height = im->ysize;
587
588 switch (im->channels) {
589 case 1:
590 case 2:
591 luma_chan = 0;
592 break;
593 case 3:
594 case 4:
595 luma_chan = 1;
596 break;
597 default:
598 /* This means a colorspace we don't handle yet */
599 mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
600 return 0;
601 }
602
603 /* Add code to get the filename info from the iolayer */
604 /* Also add code to check for mmapped code */
605
606
607 mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
608
609 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) )
610 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
611 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) )
612 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
613 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
614 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
615 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT))
616 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
617 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1) )
618 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
619 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
620 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
799d55a6 621 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE))
10461f9a
TC
622 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
623 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
624 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
625
626 linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
627
628 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
629 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
630
631 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
632 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
633
634 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
635 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
636 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
637
638 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
639 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
640 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
641 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
642 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
643 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0;
644 }
645
646 if (!save_tiff_tags(tif, im)) {
647 return 0;
648 }
649
650 for (y=0; y<height; y++) {
651 int linebufpos=0;
652 for(x=0; x<width; x+=8) {
653 int bits;
654 int bitpos;
655 i_sample_t luma[8];
656 uint8 bitval = 128;
657 linebuf[linebufpos]=0;
658 bits = width-x; if(bits>8) bits=8;
659 i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
660 for(bitpos=0;bitpos<bits;bitpos++) {
799d55a6 661 linebuf[linebufpos] |= ((luma[bitpos] < 128) ? bitval : 0);
10461f9a
TC
662 bitval >>= 1;
663 }
664 linebufpos++;
665 }
666 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
667 mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
668 break;
669 }
670 }
671 if (linebuf) _TIFFfree(linebuf);
672
673 return 1;
674}
675
676undef_int
677i_writetiff_low(TIFF *tif, i_img *im) {
02d1d628
AMH
678 uint32 width, height;
679 uint16 channels;
680 uint16 predictor = 0;
681 int quality = 75;
682 int jpegcolormode = JPEGCOLORMODE_RGB;
683 uint16 compression = COMPRESSION_PACKBITS;
684 i_color val;
685 uint16 photometric;
686 uint32 rowsperstrip = (uint32) -1; /* Let library pick default */
02d1d628
AMH
687 unsigned char *linebuf = NULL;
688 uint32 y;
689 tsize_t linebytes;
690 int ch, ci, rc;
691 uint32 x;
a659442a 692 int got_xres, got_yres, aspect_only, resunit;
faa9b3e7 693 double xres, yres;
f62b2d84
TC
694 uint16 bitspersample = 8;
695 uint16 samplesperpixel;
696 uint16 *colors = NULL;
02d1d628 697
02d1d628
AMH
698 width = im->xsize;
699 height = im->ysize;
700 channels = im->channels;
701
702 switch (channels) {
703 case 1:
704 photometric = PHOTOMETRIC_MINISBLACK;
705 break;
706 case 3:
707 photometric = PHOTOMETRIC_RGB;
708 if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR;
f62b2d84
TC
709 else if (im->type == i_palette_type) {
710 photometric = PHOTOMETRIC_PALETTE;
711 }
02d1d628
AMH
712 break;
713 default:
714 /* This means a colorspace we don't handle yet */
715 mm_log((1, "i_writetiff_wiol: don't handle %d channel images.\n", channels));
716 return 0;
717 }
718
719 /* Add code to get the filename info from the iolayer */
720 /* Also add code to check for mmapped code */
721
10461f9a
TC
722 /*io_glue_commit_types(ig);*/
723 /*mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));*/
02d1d628 724
10461f9a 725 mm_log((1, "i_writetiff_low: width=%d, height=%d, channels=%d\n", width, height, channels));
02d1d628 726
10461f9a
TC
727 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) ) {
728 mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width));
729 return 0;
730 }
731 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) ) {
732 mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height));
733 return 0;
734 }
735 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)) {
736 mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n"));
737 return 0;
738 }
739 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
740 mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n"));
741 return 0;
742 }
743 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) {
744 mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric));
745 return 0;
746 }
747 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, compression)) {
748 mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression));
749 return 0;
02d1d628 750 }
f62b2d84
TC
751 samplesperpixel = channels;
752 if (photometric == PHOTOMETRIC_PALETTE) {
753 uint16 *out[3];
754 i_color c;
755 int count = i_colorcount(im);
756 int size;
f62b2d84
TC
757 int ch, i;
758
759 samplesperpixel = 1;
760 if (count > 16)
761 bitspersample = 8;
762 else
763 bitspersample = 4;
764 size = 1 << bitspersample;
765 colors = (uint16 *)_TIFFmalloc(sizeof(uint16) * 3 * size);
766 out[0] = colors;
767 out[1] = colors + size;
768 out[2] = colors + 2 * size;
769
770 for (i = 0; i < count; ++i) {
771 i_getcolors(im, i, &c, 1);
772 for (ch = 0; ch < 3; ++ch)
773 out[ch][i] = c.channel[ch] * 257;
774 }
775 for (; i < size; ++i) {
776 for (ch = 0; ch < 3; ++ch)
777 out[ch][i] = 0;
778 }
779 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
780 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
781 bitspersample));
782 return 0;
783 }
784 if (!TIFFSetField(tif, TIFFTAG_COLORMAP, out[0], out[1], out[2])) {
785 mm_log((1, "i_writetiff_wiol: TIFFSetField colormap\n"));
786 return 0;
787 }
788 }
789 else {
790 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
791 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
792 bitspersample));
793 return 0;
794 }
795 }
796 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel)) {
797 mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", samplesperpixel));
798 return 0;
799 }
02d1d628
AMH
800
801 switch (compression) {
802 case COMPRESSION_JPEG:
803 mm_log((1, "i_writetiff_wiol: jpeg compression\n"));
10461f9a
TC
804 if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality) ) {
805 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality));
806 return 0;
807 }
808 if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) {
809 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode));
810 return 0;
811 }
02d1d628
AMH
812 break;
813 case COMPRESSION_LZW:
814 mm_log((1, "i_writetiff_wiol: lzw compression\n"));
815 break;
816 case COMPRESSION_DEFLATE:
817 mm_log((1, "i_writetiff_wiol: deflate compression\n"));
818 if (predictor != 0)
10461f9a
TC
819 if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) {
820 mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor));
821 return 0;
822 }
02d1d628
AMH
823 break;
824 case COMPRESSION_PACKBITS:
825 mm_log((1, "i_writetiff_wiol: packbits compression\n"));
826 break;
827 default:
828 mm_log((1, "i_writetiff_wiol: unknown compression %d\n", compression));
829 return 0;
830 }
831
832 linebytes = channels * width;
f62b2d84
TC
833 linebytes = TIFFScanlineSize(tif) > linebytes ? linebytes
834 : TIFFScanlineSize(tif);
835 /* working space for the scanlines - we go from 8-bit/pixel to 4 */
836 if (photometric == PHOTOMETRIC_PALETTE && bitspersample == 4)
837 linebytes += linebytes + 1;
838 linebuf = (unsigned char *)_TIFFmalloc(linebytes);
02d1d628
AMH
839
840 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, rowsperstrip))) {
841 mm_log((1, "i_writetiff_wiol: TIFFSetField rowsperstrip=%d\n", rowsperstrip)); return 0; }
842
843 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
844 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
845
846 mm_log((1, "i_writetiff_wiol: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
847 mm_log((1, "i_writetiff_wiol: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
848 mm_log((1, "i_writetiff_wiol: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
230e675b 849 mm_log((1, "i_writetiff_wiol: bitspersample = %d\n", bitspersample));
02d1d628 850
faa9b3e7
TC
851 got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
852 got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
853 if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
854 aspect_only = 0;
855 if (!i_tags_get_int(&im->tags, "tiff_resolutionunit", 0, &resunit))
856 resunit = RESUNIT_INCH;
857 if (got_xres || got_yres) {
858 if (!got_xres)
859 xres = yres;
860 else if (!got_yres)
861 yres = xres;
862 if (aspect_only) {
863 resunit = RESUNIT_NONE;
864 }
865 else {
866 if (resunit == RESUNIT_CENTIMETER) {
867 xres /= 2.54;
868 yres /= 2.54;
869 }
870 else {
871 resunit = RESUNIT_INCH;
872 }
873 }
874 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres)) {
faa9b3e7
TC
875 i_push_error(0, "cannot set TIFFTAG_XRESOLUTION tag");
876 return 0;
877 }
878 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres)) {
faa9b3e7
TC
879 i_push_error(0, "cannot set TIFFTAG_YRESOLUTION tag");
880 return 0;
881 }
882 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)resunit)) {
faa9b3e7
TC
883 i_push_error(0, "cannot set TIFFTAG_RESOLUTIONUNIT tag");
884 return 0;
02d1d628
AMH
885 }
886 }
fd9a31d2
TC
887
888 if (!save_tiff_tags(tif, im)) {
fd9a31d2
TC
889 return 0;
890 }
891
f62b2d84
TC
892 if (photometric == PHOTOMETRIC_PALETTE) {
893 for (y = 0; y < height; ++y) {
894 i_gpal(im, 0, width, y, linebuf);
895 if (bitspersample == 4)
896 pack_4bit_hl(linebuf, width);
897 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
898 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
10461f9a
TC
899 if (linebuf) _TIFFfree(linebuf);
900 if (colors) _TIFFfree(colors);
901 return 0;
f62b2d84 902 }
02d1d628 903 }
f62b2d84
TC
904 }
905 else {
906 for (y=0; y<height; y++) {
907 ci = 0;
908 for(x=0; x<width; x++) {
909 (void) i_gpix(im, x, y,&val);
910 for(ch=0; ch<channels; ch++)
911 linebuf[ci++] = val.channel[ch];
912 }
913 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
914 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
10461f9a
TC
915 if (linebuf) _TIFFfree(linebuf);
916 if (colors) _TIFFfree(colors);
917 return 0;
f62b2d84 918 }
02d1d628
AMH
919 }
920 }
02d1d628 921 if (linebuf) _TIFFfree(linebuf);
f62b2d84 922 if (colors) _TIFFfree(colors);
02d1d628
AMH
923 return 1;
924}
925
d2dfdcc9 926/*
10461f9a 927=item i_writetiff_multi_wiol(ig, imgs, count, fine_mode)
d2dfdcc9 928
10461f9a 929Stores an image in the iolayer object.
d2dfdcc9 930
d2dfdcc9 931 ig - io_object that defines source to write to
10461f9a 932 imgs,count - the images to write
d2dfdcc9 933
10461f9a 934=cut
d2dfdcc9
TC
935*/
936
937undef_int
10461f9a 938i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
d2dfdcc9 939 TIFF* tif;
2691d220 940 TIFFErrorHandler old_handler;
10461f9a 941 int i;
d2dfdcc9 942
2691d220
TC
943 old_handler = TIFFSetErrorHandler(error_handler);
944
10461f9a
TC
945 io_glue_commit_types(ig);
946 i_clear_error();
947 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
948 ig, imgs, count));
d2dfdcc9 949
10461f9a
TC
950 /* FIXME: Enable the mmap interface */
951
952 tif = TIFFClientOpen("No name",
953 "wm",
954 (thandle_t) ig,
955 (TIFFReadWriteProc) ig->readcb,
956 (TIFFReadWriteProc) ig->writecb,
957 (TIFFSeekProc) comp_seek,
958 (TIFFCloseProc) ig->closecb,
e18f39b3
TC
959 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
960 (TIFFMapFileProc) comp_mmap,
961 (TIFFUnmapFileProc) comp_munmap);
10461f9a
TC
962
963
964
965 if (!tif) {
2691d220
TC
966 mm_log((1, "i_writetiff_multi_wiol: Unable to open tif file for writing\n"));
967 i_push_error(0, "Could not create TIFF object");
968 TIFFSetErrorHandler(old_handler);
d2dfdcc9
TC
969 return 0;
970 }
971
10461f9a
TC
972 for (i = 0; i < count; ++i) {
973 if (!i_writetiff_low(tif, imgs[i])) {
974 TIFFClose(tif);
2691d220 975 TIFFSetErrorHandler(old_handler);
10461f9a
TC
976 return 0;
977 }
978
979 if (!TIFFWriteDirectory(tif)) {
980 i_push_error(0, "Cannot write TIFF directory");
981 TIFFClose(tif);
2691d220 982 TIFFSetErrorHandler(old_handler);
10461f9a
TC
983 return 0;
984 }
985 }
986
2691d220 987 TIFFSetErrorHandler(old_handler);
10461f9a 988 (void) TIFFClose(tif);
2691d220 989
10461f9a
TC
990 return 1;
991}
992
993/*
994=item i_writetiff_multi_wiol_faxable(ig, imgs, count, fine_mode)
995
996Stores an image in the iolayer object.
997
998 ig - io_object that defines source to write to
999 imgs,count - the images to write
1000 fine_mode - select fine or normal mode fax images
1001
1002=cut
1003*/
1004
1005
1006undef_int
1007i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
1008 TIFF* tif;
1009 int i;
2691d220
TC
1010 TIFFErrorHandler old_handler;
1011
1012 old_handler = TIFFSetErrorHandler(error_handler);
d2dfdcc9
TC
1013
1014 io_glue_commit_types(ig);
10461f9a
TC
1015 i_clear_error();
1016 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
1017 ig, imgs, count));
d2dfdcc9
TC
1018
1019 /* FIXME: Enable the mmap interface */
1020
1021 tif = TIFFClientOpen("No name",
1022 "wm",
1023 (thandle_t) ig,
1024 (TIFFReadWriteProc) ig->readcb,
1025 (TIFFReadWriteProc) ig->writecb,
1026 (TIFFSeekProc) comp_seek,
1027 (TIFFCloseProc) ig->closecb,
e18f39b3
TC
1028 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1029 (TIFFMapFileProc) comp_mmap,
1030 (TIFFUnmapFileProc) comp_munmap);
10461f9a
TC
1031
1032
d2dfdcc9
TC
1033
1034 if (!tif) {
10461f9a 1035 mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
2691d220
TC
1036 i_push_error(0, "Could not create TIFF object");
1037 TIFFSetErrorHandler(old_handler);
d2dfdcc9
TC
1038 return 0;
1039 }
1040
10461f9a
TC
1041 for (i = 0; i < count; ++i) {
1042 if (!i_writetiff_low_faxable(tif, imgs[i], fine)) {
1043 TIFFClose(tif);
2691d220 1044 TIFFSetErrorHandler(old_handler);
10461f9a
TC
1045 return 0;
1046 }
d2dfdcc9 1047
10461f9a
TC
1048 if (!TIFFWriteDirectory(tif)) {
1049 i_push_error(0, "Cannot write TIFF directory");
1050 TIFFClose(tif);
2691d220 1051 TIFFSetErrorHandler(old_handler);
10461f9a
TC
1052 return 0;
1053 }
1054 }
d2dfdcc9 1055
10461f9a 1056 (void) TIFFClose(tif);
2691d220
TC
1057 TIFFSetErrorHandler(old_handler);
1058
10461f9a
TC
1059 return 1;
1060}
d2dfdcc9 1061
10461f9a
TC
1062/*
1063=item i_writetiff_wiol(im, ig)
d2dfdcc9 1064
10461f9a
TC
1065Stores an image in the iolayer object.
1066
1067 im - image object to write out
1068 ig - io_object that defines source to write to
1069
1070=cut
1071*/
1072undef_int
1073i_writetiff_wiol(i_img *img, io_glue *ig) {
1074 TIFF* tif;
2691d220
TC
1075 TIFFErrorHandler old_handler;
1076
1077 old_handler = TIFFSetErrorHandler(error_handler);
10461f9a
TC
1078
1079 io_glue_commit_types(ig);
1080 i_clear_error();
1081 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", img, ig));
1082
1083 /* FIXME: Enable the mmap interface */
2691d220 1084
10461f9a
TC
1085 tif = TIFFClientOpen("No name",
1086 "wm",
1087 (thandle_t) ig,
1088 (TIFFReadWriteProc) ig->readcb,
1089 (TIFFReadWriteProc) ig->writecb,
1090 (TIFFSeekProc) comp_seek,
1091 (TIFFCloseProc) ig->closecb,
e18f39b3
TC
1092 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1093 (TIFFMapFileProc) comp_mmap,
1094 (TIFFUnmapFileProc) comp_munmap);
10461f9a
TC
1095
1096
1097
1098 if (!tif) {
1099 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
2691d220
TC
1100 i_push_error(0, "Could not create TIFF object");
1101 TIFFSetErrorHandler(old_handler);
10461f9a 1102 return 0;
d2dfdcc9 1103 }
d2dfdcc9 1104
10461f9a 1105 if (!i_writetiff_low(tif, img)) {
fd9a31d2 1106 TIFFClose(tif);
2691d220 1107 TIFFSetErrorHandler(old_handler);
fd9a31d2
TC
1108 return 0;
1109 }
1110
10461f9a 1111 (void) TIFFClose(tif);
2691d220
TC
1112 TIFFSetErrorHandler(old_handler);
1113
10461f9a
TC
1114 return 1;
1115}
1116
1117
1118
1119/*
1120=item i_writetiff_wiol_faxable(i_img *, io_glue *)
1121
1122Stores an image in the iolayer object in faxable tiff format.
1123
1124 im - image object to write out
1125 ig - io_object that defines source to write to
1126
1127Note, this may be rewritten to use to simply be a call to a
1128lower-level function that gives more options for writing tiff at some
1129point.
1130
1131=cut
1132*/
1133
1134undef_int
1135i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
1136 TIFF* tif;
2691d220
TC
1137 TIFFErrorHandler old_handler;
1138
1139 old_handler = TIFFSetErrorHandler(error_handler);
10461f9a
TC
1140
1141 io_glue_commit_types(ig);
1142 i_clear_error();
1143 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", im, ig));
1144
1145 /* FIXME: Enable the mmap interface */
1146
1147 tif = TIFFClientOpen("No name",
1148 "wm",
1149 (thandle_t) ig,
1150 (TIFFReadWriteProc) ig->readcb,
1151 (TIFFReadWriteProc) ig->writecb,
1152 (TIFFSeekProc) comp_seek,
1153 (TIFFCloseProc) ig->closecb,
e18f39b3
TC
1154 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1155 (TIFFMapFileProc) comp_mmap,
1156 (TIFFUnmapFileProc) comp_munmap);
10461f9a
TC
1157
1158
1159
1160 if (!tif) {
1161 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
2691d220
TC
1162 i_push_error(0, "Could not create TIFF object");
1163 TIFFSetErrorHandler(old_handler);
10461f9a 1164 return 0;
d2dfdcc9 1165 }
10461f9a
TC
1166
1167 if (!i_writetiff_low_faxable(tif, im, fine)) {
1168 TIFFClose(tif);
2691d220 1169 TIFFSetErrorHandler(old_handler);
10461f9a
TC
1170 return 0;
1171 }
1172
d2dfdcc9 1173 (void) TIFFClose(tif);
2691d220
TC
1174 TIFFSetErrorHandler(old_handler);
1175
d2dfdcc9
TC
1176 return 1;
1177}
1178
fd9a31d2
TC
1179static int save_tiff_tags(TIFF *tif, i_img *im) {
1180 int i;
10461f9a 1181
fd9a31d2
TC
1182 for (i = 0; i < text_tag_count; ++i) {
1183 int entry;
1184 if (i_tags_find(&im->tags, text_tag_names[i].name, 0, &entry)) {
1185 if (!TIFFSetField(tif, text_tag_names[i].tag,
10461f9a
TC
1186 im->tags.tags[entry].data)) {
1187 i_push_errorf(0, "cannot save %s to TIFF", text_tag_names[i].name);
1188 return 0;
fd9a31d2
TC
1189 }
1190 }
1191 }
10461f9a 1192
fd9a31d2
TC
1193 return 1;
1194}
b8c2033e 1195
10461f9a 1196
5bb828f1
TC
1197/*
1198=item expand_4bit_hl(buf, count)
1199
1200Expands 4-bit/entry packed data into 1 byte/entry.
1201
1202buf must contain count bytes to be expanded and have 2*count bytes total
1203space.
1204
1205The data is expanded in place.
1206
1207=cut
1208*/
1209
1210static void expand_4bit_hl(unsigned char *buf, int count) {
1211 while (--count >= 0) {
1212 buf[count*2+1] = buf[count] & 0xF;
1213 buf[count*2] = buf[count] >> 4;
1214 }
1215}
1216
f62b2d84 1217static void pack_4bit_hl(unsigned char *buf, int count) {
230e675b 1218 int i = 0;
f62b2d84
TC
1219 while (i < count) {
1220 buf[i/2] = (buf[i] << 4) + buf[i+1];
1221 i += 2;
1222 }
1223}
5bb828f1 1224
b8c2033e
AMH
1225/*
1226=back
1227
1228=head1 AUTHOR
1229
1230Arnar M. Hrafnkelsson <addi@umich.edu>
1231
1232=head1 SEE ALSO
1233
1234Imager(3)
1235
1236=cut
1237*/