This is tiff.c in view mode; [Download] [Up]
/* tiff - Functions for dealing with tiff images Copyright (C) 1994, Adam Fedor Some of this code is derived from tif_getimage, by Sam Leffler. See the copyright below. */ /* * Copyright (c) 1991, 1992, 1993, 1994 Sam Leffler * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #include <math.h> #include <stdlib.h> #include <string.h> #include <unistd.h> /* for L_SET, etc definitions */ #include "streams/streams.h" #include "appkit/tiff.h" #include "appkit/stdmacros.h" /* Define this to use the "old" version 3.0 with patches */ /* Use the Makefile if possible */ /* #define HAVE_LIBTIFF_3_0 1 */ typedef struct { NXStream *stream; int my_stream; int mode; const char *name; } chandle_t; #define MCHECK(m, tif) \ if (!m) { TIFFError(TIFFFileName(tif), "Malloc failed.\n"); return(NULL); } static const char * type_for_mode(int mode) { char *type = NULL; if (mode == NX_READONLY) type = "r"; else if (mode == NX_WRITEONLY) type = "w"; else if (mode == NX_READWRITE) type = "wr"; return type; } #ifdef HAVE_LIBTIFF #ifndef HAVE_LIBTIFF_3_0 /* Client functions that provide reading/writing of file data for libtiff */ static tsize_t HandleTiffRead(thandle_t handle, tdata_t buf, toff_t count) { chandle_t *h = (chandle_t *)handle; return NXRead(h->stream, buf, (size_t)count); } static tsize_t HandleTiffWrite(thandle_t handle, tdata_t buf, toff_t count) { chandle_t *h = (chandle_t *)handle; return NXWrite(h->stream, buf, (size_t)count); } static toff_t HandleTiffSeek(thandle_t handle, toff_t offset, int mode) { chandle_t *h = (chandle_t *)handle; switch(mode) { case SEEK_SET: mode = NX_FROMSTART; break; case SEEK_CUR: mode = NX_FROMCURRENT; break; case SEEK_END: mode = NX_FROMEND; break; default: mode = NX_FROMSTART; } NXSeek(h->stream, offset, mode); return NXTell(h->stream); } static int HandleTiffClose(thandle_t handle) { chandle_t *h = (chandle_t *)handle; /* If we don't own the stream, don't do anything */ if (h->my_stream == 0) return 0; /* If we wrote to the file, we need to save it */ if (h->mode != NX_READONLY) NXSaveToFile(h->stream, h->name); NXCloseMemory(h->stream, NX_FREEBUFFER); /* Presumably, we don't need the handle anymore */ NX_FREE(h); return 0; } static toff_t HandleTiffSize(thandle_t handle) { int pos, len; chandle_t *h = (chandle_t *)handle; /* Ugly way to find the size of a file/stream */ pos = NXTell(h->stream); if (pos < 0) return 0; NXSeek(h->stream, 0, NX_FROMEND); len = NXTell(h->stream); NXSeek(h->stream, pos, NX_FROMSTART); return (len > 0) ? len : 0; } static int HandleTiffMap(thandle_t handle, tdata_t *data, toff_t *size) { int maxsize; chandle_t *h = (chandle_t *)handle; /* If we've got true streams, then we're already mapped, if not, we don't even try to map the file. */ *size = 0; NXGetMemoryBuffer(h->stream, (char **)data, (int *)size, &maxsize); return (*size) ? 1 : 0; } static void HandleTiffUnmap(thandle_t handle, tdata_t data, toff_t size) { /* Nothing to do. This is handled by HandleTiffClose. */ } #endif /* not HAVE_LIBTIFF_3_0 */ /* Open a tiff file. Returns NULL if can't read tiff information */ TIFF * NXOpenTiffFile(const char *filename, int mode) { #ifndef HAVE_LIBTIFF_3_0 chandle_t *handle; NX_MALLOC(handle, chandle_t, 1); if ((handle->stream = NXMapFile(filename, mode)) == NULL) return NULL; handle->my_stream = 1; handle->mode = mode; handle->name = filename; return TIFFClientOpen(filename, (char *)type_for_mode(mode), (thandle_t)handle, HandleTiffRead, HandleTiffWrite, HandleTiffSeek, HandleTiffClose, HandleTiffSize, HandleTiffMap, HandleTiffUnmap); #else return TIFFOpen((char *)filename, (char *)type_for_mode(mode)); #endif } /* Open a tiff from a stream. Returns NULL if can't read tiff information. */ TIFF * NXOpenTiffStream(NXStream *stream, int mode) { #ifndef HAVE_LIBTIFF_3_0 chandle_t *handle; NX_MALLOC(handle, chandle_t, 1); handle->stream = stream; handle->my_stream = 0; handle->mode = mode; handle->name = "NXStream"; return TIFFClientOpen("NXStream", (char *)type_for_mode(mode), (thandle_t)handle, HandleTiffRead, HandleTiffWrite, HandleTiffSeek, HandleTiffClose, HandleTiffSize, HandleTiffMap, HandleTiffUnmap); #else return TIFFFdOpen((int)stream, NULL, (char *)type_for_mode(mode)); #endif } int NXCloseTiff(TIFF *image) { TIFFClose(image); return 0; } /* Read some information about the image. Note that currently we don't determine numImages. */ NXTiffInfo * NXGetTiffInfo(int imageNumber, TIFF *image) { NXTiffInfo *info; if (imageNumber >= 0 && !TIFFSetDirectory(image, imageNumber)) { return NULL; } NX_MALLOC(info, NXTiffInfo, 1); memset(info, 0, sizeof(NXTiffInfo)); if (imageNumber >= 0) info->imageNumber = imageNumber; TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &info->width); TIFFGetField(image, TIFFTAG_IMAGELENGTH, &info->height); TIFFGetField(image, TIFFTAG_COMPRESSION, &info->compression); TIFFGetField(image, TIFFTAG_SUBFILETYPE, &info->subfileType); /* * If the following tags aren't present then use the TIFF defaults. */ TIFFGetFieldDefaulted(image, TIFFTAG_BITSPERSAMPLE, &info->bitsPerSample); TIFFGetFieldDefaulted(image, TIFFTAG_SAMPLESPERPIXEL, &info->samplesPerPixel); TIFFGetFieldDefaulted(image, TIFFTAG_PLANARCONFIG, &info->planarConfig); /* * If TIFFTAG_PHOTOMETRIC is not present then assign a reasonable default. * The TIFF 5.0 specification doesn't give a default. */ if (!TIFFGetField(image, TIFFTAG_PHOTOMETRIC, &info->photoInterp)) { switch (info->samplesPerPixel) { case 1: info->photoInterp = PHOTOMETRIC_MINISBLACK; break; case 3: case 4: info->photoInterp = PHOTOMETRIC_RGB; break; default: TIFFError(TIFFFileName(image), "Missing needed \"PhotometricInterpretation\" tag"); return (0); } TIFFError(TIFFFileName(image), "No \"PhotometricInterpretation\" tag, assuming %s\n", info->photoInterp == PHOTOMETRIC_RGB ? "RGB" : "min-is-black"); } return info; } #define READ_SCANLINE(sample) \ if ( TIFFReadScanline( image, buf, row, sample ) < 0 ) { \ fprintf(stderr, "tiff: bad data read on line %d\n", row ); \ error = 1; \ break; \ } \ inP = buf; /* Read an image into a data array. The data array is assumed to have been already allocated to the correct size. Note that palette images are implicitly coverted to 24-bit contig direct color images. Thus the data array should be large enough to hold this information. */ void * NXReadTiff(int imageNumber, TIFF *image, NXTiffInfo *info, void *data) { int i; int row, col; int maxval; int size; int line; int error = 0; u_char *inP, *outP; u_char *buf; u_char *raster; NXTiffInfo *newinfo; NXColormap *map; if (data == NULL) return NULL; /* Make sure we're at the right image */ if ((newinfo = NXGetTiffInfo(imageNumber, image)) == NULL) return NULL; if (info) memcpy(info, newinfo, sizeof(NXTiffInfo)); map = NULL; if ( newinfo->photoInterp == PHOTOMETRIC_PALETTE) { map = NXGetColormap(image); if (!map) return NULL; } maxval = ( 1 << newinfo->bitsPerSample ) - 1; line = ceil((float)newinfo->width * newinfo->bitsPerSample / 8.0); size = ceil((float)line * newinfo->height * newinfo->samplesPerPixel ); NX_MALLOC(buf, u_char, TIFFScanlineSize(image)); MCHECK(buf, image); raster = (u_char *)data; outP = raster; switch ( newinfo->photoInterp ) { case PHOTOMETRIC_MINISBLACK: case PHOTOMETRIC_MINISWHITE: if (newinfo->planarConfig == PLANARCONFIG_CONTIG) { for ( row = 0; row < newinfo->height; ++row ) { READ_SCANLINE(0) for ( col = 0; col < line*newinfo->samplesPerPixel; col++) *outP++ = *inP++; } } else { for (i = 0; i < newinfo->samplesPerPixel; i++) for ( row = 0; row < newinfo->height; ++row ) { READ_SCANLINE(i) for ( col = 0; col < line; col++) *outP++ = *inP++; } } break; case PHOTOMETRIC_PALETTE: { for ( row = 0; row < newinfo->height; ++row ) { READ_SCANLINE(0) for ( col = 0; col < newinfo->width; col++) { *outP++ = map->red[*inP] / 256; *outP++ = map->green[*inP] / 256; *outP++ = map->blue[*inP] / 256; inP++; } } free(map->red); free(map->green); free(map->blue); free(map); } break; case PHOTOMETRIC_RGB: if (newinfo->planarConfig == PLANARCONFIG_CONTIG) { for ( row = 0; row < newinfo->height; ++row ) { READ_SCANLINE(0) for ( col = 0; col < newinfo->width; col++) for (i = 0; i < newinfo->samplesPerPixel; i++) *outP++ = *inP++; } } else { for (i = 0; i < newinfo->samplesPerPixel; i++) for ( row = 0; row < newinfo->height; ++row ) { READ_SCANLINE(i) for ( col = 0; col < newinfo->width; col++) *outP++ = *inP++; } } break; default: TIFFError(TIFFFileName(image), "Can't read photometric %d", newinfo->photoInterp); break; } NX_FREE(newinfo); return (error) ? NULL : raster; } int NXWriteTiff(TIFF *image, NXTiffInfo *info, void *data) { return 0; } /*------------------------------------------------------------------------*/ /* * Many programs get TIFF colormaps wrong. They use 8-bit colormaps instead of * 16-bit colormaps. This function is a heuristic to detect and correct this. */ static int CheckAndCorrectColormap(NXColormap *map) { register int i; for (i = 0; i < map->size; i++) if ((map->red[i] > 255)||(map->green[i] > 255)||(map->blue[i] > 255)) return 16; #define CVT(x) (((x) * 255) / ((1L<<16)-1)) for (i = 0; i < map->size; i++) { map->red[i] = CVT(map->red[i]); map->green[i] = CVT(map->green[i]); map->blue[i] = CVT(map->blue[i]); } return 8; } /* Gets the colormap for the image if there is one. Returns a NXColormap if one was found. */ NXColormap * NXGetColormap(TIFF *image) { NXTiffInfo *info; NXColormap *map; /* Re-read the tiff information. We pass -1 as the image number which means just read the current image. */ info = NXGetTiffInfo(-1, image); if (info->photoInterp != PHOTOMETRIC_PALETTE) return NULL; NX_MALLOC(map, NXColormap, 1); map->size = 1 << info->bitsPerSample; if (!TIFFGetField(image, TIFFTAG_COLORMAP, &map->red, &map->green, &map->blue)) { TIFFError(TIFFFileName(image), "Missing required \"Colormap\" tag"); NX_FREE(map); return NULL; } if (CheckAndCorrectColormap(map) == 8) TIFFWarning(TIFFFileName(image), "Assuming 8-bit colormap"); free(info); return map; } #else /* HAVE_LIBTIFF */ TIFF * NXOpenTiffFile(const char *filename, int mode) { return NULL; } TIFF * NXOpenTiffStream(NXStream *stream, int mode) { return NULL; } int NXCloseTiff(TIFF *image) { return 0; } NXTiffInfo * NXGetTiffInfo(int imageNumber, TIFF *image) { return NULL; } void * NXReadTiff(int imageNumber, TIFF *image, NXTiffInfo *info, void *data) { return NULL; } int NXWriteTiff(TIFF *image, NXTiffInfo *info, void *data) { return -1; } NXColormap * NXGetColormap(TIFF *image) { return NULL; } #endif /* not HAVE_LIBTIFF */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.