-#include "image.h"
+#include "imager.h"
#include "tiffio.h"
#include "iolayer.h"
-#include "imagei.h"
+#include "imageri.h"
/*
=head1 NAME
=cut
*/
-
#define byteswap_macro(x) \
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
i_push_errorvf(0, fmt, ap);
}
+#define WARN_BUFFER_LIMIT 10000
+static char *warn_buffer = NULL;
+static int warn_buffer_size = 0;
+
+static void warn_handler(char const *module, char const *fmt, va_list ap) {
+ char buf[1000];
+
+ buf[0] = '\0';
+#ifdef HAVE_SNPRINTF
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+#else
+ vsprintf(buf, fmt, ap);
+#endif
+ if (!warn_buffer || strlen(warn_buffer)+strlen(buf)+2 > warn_buffer_size) {
+ int new_size = warn_buffer_size + strlen(buf) + 2;
+ char *old_buffer = warn_buffer;
+ if (new_size > WARN_BUFFER_LIMIT) {
+ new_size = WARN_BUFFER_LIMIT;
+ }
+ warn_buffer = myrealloc(warn_buffer, new_size);
+ if (!old_buffer) *warn_buffer = '\0';
+ warn_buffer_size = new_size;
+ }
+ if (strlen(warn_buffer)+strlen(buf)+2 <= warn_buffer_size) {
+ strcat(warn_buffer, buf);
+ strcat(warn_buffer, "\n");
+ }
+}
+
static int save_tiff_tags(TIFF *tif, i_img *im);
static void expand_4bit_hl(unsigned char *buf, int count);
return (toff_t) ig->seekcb(ig, o, w);
}
+/*
+=item comp_mmap(thandle_t, tdata_t*, toff_t*)
+
+Dummy mmap stub.
+
+This shouldn't ever be called but newer tifflibs want it anyway.
+
+=cut
+*/
+
+static
+int
+comp_mmap(thandle_t h, tdata_t*p, toff_t*off) {
+ return -1;
+}
+
+/*
+=item comp_munmap(thandle_t h, tdata_t p, toff_t off)
+
+Dummy munmap stub.
+
+This shouldn't ever be called but newer tifflibs want it anyway.
+
+=cut
+*/
+
+static void
+comp_munmap(thandle_t h, tdata_t p, toff_t off) {
+ /* do nothing */
+}
+
static i_img *read_one_tiff(TIFF *tif) {
i_img *im;
uint32 width, height;
mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not "));
mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not "));
+ /* separated defaults to CMYK, but if the user is using some strange
+ ink system we can't work out the color anyway */
+ if (photometric == PHOTOMETRIC_SEPARATED && channels >= 4) {
+ /* TIFF can have more than one alpha channel on an image,
+ but Imager can't, only store the first one */
+
+ channels = channels == 4 ? 3 : 4;
+
+ /* unfortunately the RGBA functions don't try to deal with the alpha
+ channel on CMYK images, at some point I'm planning on expanding
+ TIFF support to handle 16-bit/sample images and I'll deal with
+ it then */
+ }
+
+ /* TIFF images can have more than one alpha channel, but Imager can't
+ this ignores the possibility of 2 channel images with 2 alpha,
+ but there's not much I can do about that */
+ if (channels > 4)
+ channels = 4;
+
if (photometric == PHOTOMETRIC_PALETTE && bits_per_sample <= 8) {
channels = 3;
im = i_img_pal_new(width, height, channels, 256);
else {
im = i_img_empty_ch(NULL, width, height, channels);
}
+
+ if (!im)
+ return NULL;
+
+ /* general metadata */
+ i_tags_addn(&im->tags, "tiff_bitspersample", 0, bits_per_sample);
+ i_tags_addn(&im->tags, "tiff_photometric", 0, photometric);
/* resolution tags */
TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
xres = yres;
else if (!gotYres)
yres = xres;
+ i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
if (resunit == RESUNIT_CENTIMETER) {
/* from dots per cm to dpi */
xres *= 2.54;
yres *= 2.54;
+ i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "centimeter", -1, 0);
}
- i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
- if (resunit == RESUNIT_NONE)
+ else if (resunit == RESUNIT_NONE) {
i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
- i_tags_set_float(&im->tags, "i_xres", 0, xres);
- i_tags_set_float(&im->tags, "i_yres", 0, yres);
+ i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "none", -1, 0);
+ }
+ else if (resunit == RESUNIT_INCH) {
+ i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "inch", -1, 0);
+ }
+ else {
+ i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "unknown", -1, 0);
+ }
+ /* tifflib doesn't seem to provide a way to get to the original rational
+ value of these, which would let me provide a more reasonable
+ precision. So make up a number. */
+ i_tags_set_float2(&im->tags, "i_xres", 0, xres, 6);
+ i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6);
}
/* Text tags */
strlen(data), 0);
}
}
+
+ i_tags_add(&im->tags, "i_format", 0, "tiff", -1, 0);
+ if (warn_buffer && *warn_buffer) {
+ i_tags_add(&im->tags, "i_warning", 0, warn_buffer, -1, 0);
+ *warn_buffer = '\0';
+ }
/* TIFFPrintDirectory(tif, stdout, 0); good for debugging */
=cut
*/
i_img*
-i_readtiff_wiol(io_glue *ig, int length) {
+i_readtiff_wiol(io_glue *ig, int length, int page) {
TIFF* tif;
TIFFErrorHandler old_handler;
+ TIFFErrorHandler old_warn_handler;
i_img *im;
i_clear_error();
old_handler = TIFFSetErrorHandler(error_handler);
+ old_warn_handler = TIFFSetWarningHandler(warn_handler);
+ if (warn_buffer)
+ *warn_buffer = '\0';
/* Add code to get the filename info from the iolayer */
/* Also add code to check for mmapped code */
(TIFFSeekProc) comp_seek,
(TIFFCloseProc) ig->closecb,
ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
- (TIFFMapFileProc) NULL,
- (TIFFUnmapFileProc) NULL);
+ (TIFFMapFileProc) comp_mmap,
+ (TIFFUnmapFileProc) comp_munmap);
if (!tif) {
mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
- i_push_error(0, "opening file");
+ i_push_error(0, "Error opening file");
TIFFSetErrorHandler(old_handler);
+ TIFFSetWarningHandler(old_warn_handler);
return NULL;
}
+ if (page != 0) {
+ if (!TIFFSetDirectory(tif, page)) {
+ mm_log((1, "i_readtiff_wiol: Unable to switch to directory %d\n", page));
+ i_push_errorf(0, "could not switch to page %d", page);
+ TIFFSetErrorHandler(old_handler);
+ TIFFSetWarningHandler(old_warn_handler);
+ TIFFClose(tif);
+ return NULL;
+ }
+ }
+
im = read_one_tiff(tif);
if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
TIFFSetErrorHandler(old_handler);
+ TIFFSetWarningHandler(old_warn_handler);
TIFFClose(tif);
return im;
}
i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
TIFF* tif;
TIFFErrorHandler old_handler;
+ TIFFErrorHandler old_warn_handler;
i_img **results = NULL;
int result_alloc = 0;
int dirnum = 0;
i_clear_error();
old_handler = TIFFSetErrorHandler(error_handler);
+ old_warn_handler = TIFFSetWarningHandler(warn_handler);
+ if (warn_buffer)
+ *warn_buffer = '\0';
/* Add code to get the filename info from the iolayer */
/* Also add code to check for mmapped code */
(TIFFReadWriteProc) ig->writecb,
(TIFFSeekProc) comp_seek,
(TIFFCloseProc) ig->closecb,
- (TIFFSizeProc) ig->sizecb,
- (TIFFMapFileProc) NULL,
- (TIFFUnmapFileProc) NULL);
+ ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+ (TIFFMapFileProc) comp_mmap,
+ (TIFFUnmapFileProc) comp_munmap);
if (!tif) {
mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
- i_push_error(0, "opening file");
+ i_push_error(0, "Error opening file");
TIFFSetErrorHandler(old_handler);
+ TIFFSetWarningHandler(old_warn_handler);
return NULL;
}
i_img **newresults;
result_alloc *= 2;
newresults = myrealloc(results, result_alloc * sizeof(i_img *));
+ if (!newresults) {
+ i_img_destroy(im); /* don't leak it */
+ break;
+ }
+ results = newresults;
}
}
results[*count-1] = im;
} while (TIFFSetDirectory(tif, ++dirnum));
+ TIFFSetWarningHandler(old_warn_handler);
TIFFSetErrorHandler(old_handler);
TIFFClose(tif);
return results;
uint32 y;
int rc;
uint32 x;
- int luma_mask;
uint32 rowsperstrip;
float vres = fine ? 196 : 98;
int luma_chan;
{ mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
{ mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
- if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK))
+ if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE))
{ mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
{ mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
bits = width-x; if(bits>8) bits=8;
i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
for(bitpos=0;bitpos<bits;bitpos++) {
- linebuf[linebufpos] |= ((luma[bitpos]>=128)?bitval:0);
+ linebuf[linebufpos] |= ((luma[bitpos] < 128) ? bitval : 0);
bitval >>= 1;
}
linebufpos++;
tsize_t linebytes;
int ch, ci, rc;
uint32 x;
- int got_xres, got_yres, got_aspectonly, aspect_only, resunit;
+ int got_xres, got_yres, aspect_only, resunit;
double xres, yres;
uint16 bitspersample = 8;
uint16 samplesperpixel;
i_color c;
int count = i_colorcount(im);
int size;
- int bits;
int ch, i;
samplesperpixel = 1;
undef_int
i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
TIFF* tif;
+ TIFFErrorHandler old_handler;
int i;
+ old_handler = TIFFSetErrorHandler(error_handler);
+
io_glue_commit_types(ig);
i_clear_error();
mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
(TIFFReadWriteProc) ig->writecb,
(TIFFSeekProc) comp_seek,
(TIFFCloseProc) ig->closecb,
- (TIFFSizeProc) ig->sizecb,
- (TIFFMapFileProc) NULL,
- (TIFFUnmapFileProc) NULL);
+ ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+ (TIFFMapFileProc) comp_mmap,
+ (TIFFUnmapFileProc) comp_munmap);
if (!tif) {
- mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
+ mm_log((1, "i_writetiff_multi_wiol: Unable to open tif file for writing\n"));
+ i_push_error(0, "Could not create TIFF object");
+ TIFFSetErrorHandler(old_handler);
return 0;
}
for (i = 0; i < count; ++i) {
if (!i_writetiff_low(tif, imgs[i])) {
TIFFClose(tif);
+ TIFFSetErrorHandler(old_handler);
return 0;
}
if (!TIFFWriteDirectory(tif)) {
i_push_error(0, "Cannot write TIFF directory");
TIFFClose(tif);
+ TIFFSetErrorHandler(old_handler);
return 0;
}
}
+ TIFFSetErrorHandler(old_handler);
(void) TIFFClose(tif);
+
return 1;
}
i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
TIFF* tif;
int i;
+ TIFFErrorHandler old_handler;
+
+ old_handler = TIFFSetErrorHandler(error_handler);
io_glue_commit_types(ig);
i_clear_error();
(TIFFReadWriteProc) ig->writecb,
(TIFFSeekProc) comp_seek,
(TIFFCloseProc) ig->closecb,
- (TIFFSizeProc) ig->sizecb,
- (TIFFMapFileProc) NULL,
- (TIFFUnmapFileProc) NULL);
+ ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+ (TIFFMapFileProc) comp_mmap,
+ (TIFFUnmapFileProc) comp_munmap);
if (!tif) {
mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
+ i_push_error(0, "Could not create TIFF object");
+ TIFFSetErrorHandler(old_handler);
return 0;
}
for (i = 0; i < count; ++i) {
if (!i_writetiff_low_faxable(tif, imgs[i], fine)) {
TIFFClose(tif);
+ TIFFSetErrorHandler(old_handler);
return 0;
}
if (!TIFFWriteDirectory(tif)) {
i_push_error(0, "Cannot write TIFF directory");
TIFFClose(tif);
+ TIFFSetErrorHandler(old_handler);
return 0;
}
}
(void) TIFFClose(tif);
+ TIFFSetErrorHandler(old_handler);
+
return 1;
}
undef_int
i_writetiff_wiol(i_img *img, io_glue *ig) {
TIFF* tif;
- int i;
+ TIFFErrorHandler old_handler;
+
+ old_handler = TIFFSetErrorHandler(error_handler);
io_glue_commit_types(ig);
i_clear_error();
mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", img, ig));
/* FIXME: Enable the mmap interface */
-
+
tif = TIFFClientOpen("No name",
"wm",
(thandle_t) ig,
(TIFFReadWriteProc) ig->writecb,
(TIFFSeekProc) comp_seek,
(TIFFCloseProc) ig->closecb,
- (TIFFSizeProc) ig->sizecb,
- (TIFFMapFileProc) NULL,
- (TIFFUnmapFileProc) NULL);
+ ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+ (TIFFMapFileProc) comp_mmap,
+ (TIFFUnmapFileProc) comp_munmap);
if (!tif) {
mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
+ i_push_error(0, "Could not create TIFF object");
+ TIFFSetErrorHandler(old_handler);
return 0;
}
if (!i_writetiff_low(tif, img)) {
TIFFClose(tif);
+ TIFFSetErrorHandler(old_handler);
return 0;
}
(void) TIFFClose(tif);
+ TIFFSetErrorHandler(old_handler);
+
return 1;
}
undef_int
i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
TIFF* tif;
- int i;
+ TIFFErrorHandler old_handler;
+
+ old_handler = TIFFSetErrorHandler(error_handler);
io_glue_commit_types(ig);
i_clear_error();
(TIFFReadWriteProc) ig->writecb,
(TIFFSeekProc) comp_seek,
(TIFFCloseProc) ig->closecb,
- (TIFFSizeProc) ig->sizecb,
- (TIFFMapFileProc) NULL,
- (TIFFUnmapFileProc) NULL);
+ ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+ (TIFFMapFileProc) comp_mmap,
+ (TIFFUnmapFileProc) comp_munmap);
if (!tif) {
mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
+ i_push_error(0, "Could not create TIFF object");
+ TIFFSetErrorHandler(old_handler);
return 0;
}
if (!i_writetiff_low_faxable(tif, im, fine)) {
TIFFClose(tif);
+ TIFFSetErrorHandler(old_handler);
return 0;
}
(void) TIFFClose(tif);
+ TIFFSetErrorHandler(old_handler);
+
return 1;
}