#include "StdAfx.h" // #define STRICT #include "diblib.h" #include #include // MAX_ constants #include #include /*-------------------------------------------------------------------- READ TIFF Load the TIFF data from the file into memory. Return a pointer to a valid DIB (or NULL for errors). Uses the TIFFRGBA interface to libtiff.lib to convert most file formats to a useable form. We just keep the 32 bit form of the data to display, rather than optimizing for the display. Main entry points: int ChkTIFF ( LPCTSTR lpszPath ) PVOID ReadTIFF ( LPCTSTR lpszPath ) RETURN A valid DIB pointer for success; NULL for failure. --------------------------------------------------------------------*/ #include "TiffLib/tiff.h" #include "TiffLib/tiffio.h" #include #include // piggyback some data on top of the RGBA Image struct TIFFDibImage { TIFFRGBAImage tif; int dibinstalled; }; HANDLE LoadTIFFinDIB(LPCTSTR lpFileName); HANDLE TIFFRGBA2DIB(TIFFDibImage *dib, uint32_t *raster); static void MyWarningHandler(const char *module, const char *fmt, va_list ap) { // ignore all warnings (unused tags, etc) return; } static void MyErrorHandler(const char *module, const char *fmt, va_list ap) { return; } // Turn off the error and warning handlers to check if a valid file. // Necessary because of the way that the Doc loads images and restart files. int ChkTIFF(LPCTSTR lpszPath) { int rtn = 0; TIFFErrorHandler eh; TIFFErrorHandler wh; eh = TIFFSetErrorHandler(NULL); wh = TIFFSetWarningHandler(NULL); TIFF *tif = TIFFOpen(lpszPath, "r"); if (tif) { rtn = 1; TIFFClose(tif); } TIFFSetErrorHandler(eh); TIFFSetWarningHandler(wh); return rtn; } void DibInstallHack(TIFFDibImage *img); PVOID ReadTIFF(LPCTSTR lpszPath) { void *pDIB = 0; TIFFErrorHandler wh; wh = TIFFSetWarningHandler(MyWarningHandler); if (ChkTIFF(lpszPath)) { TIFF *tif = TIFFOpen(lpszPath, "r"); if (tif) { char emsg[1024]; if (TIFFRGBAImageOK(tif, emsg)) { TIFFDibImage img; char emsg[1024]; if (TIFFRGBAImageBegin(&img.tif, tif, -1, emsg)) { size_t npixels; uint32_t *raster; DibInstallHack(&img); npixels = img.tif.width * img.tif.height; raster = (uint32_t *)_TIFFmalloc(npixels * sizeof(uint32_t)); if (raster != NULL) { if (TIFFRGBAImageGet(&img.tif, raster, img.tif.width, img.tif.height)) { pDIB = TIFFRGBA2DIB(&img, raster); } } _TIFFfree(raster); } TIFFRGBAImageEnd(&img.tif); } else { TRACE("Unable to open image(%s): %s\n", lpszPath, emsg); } TIFFClose(tif); } } TIFFSetWarningHandler(wh); return pDIB; } HANDLE TIFFRGBA2DIB(TIFFDibImage *dib, uint32_t *raster) { void *pDIB = 0; TIFFRGBAImage *img = &dib->tif; uint32_t imageLength; uint32_t imageWidth; uint16_t BitsPerSample; uint16_t SamplePerPixel; uint32_t RowsPerStrip; uint16_t PhotometricInterpretation; BITMAPINFOHEADER bi; int dwDIBSize; TIFFGetField(img->tif, TIFFTAG_IMAGEWIDTH, &imageWidth); TIFFGetField(img->tif, TIFFTAG_IMAGELENGTH, &imageLength); TIFFGetField(img->tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetField(img->tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(img->tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel); TIFFGetField(img->tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); if (BitsPerSample == 1 && SamplePerPixel == 1 && dib->dibinstalled) { // bilevel bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = imageWidth; bi.biHeight = imageLength; bi.biPlanes = 1; // always bi.biBitCount = 1; bi.biCompression = BI_RGB; bi.biSizeImage = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; // must be zero for RGB compression (none) bi.biClrImportant = 0; // always // Get the size of the DIB dwDIBSize = GetDIBSize(&bi); // Allocate for the BITMAPINFO structure and the color table. pDIB = GlobalAllocPtr(GHND, dwDIBSize); if (pDIB == 0) { return (NULL); } // Copy the header info *((BITMAPINFOHEADER *)pDIB) = bi; // Get a pointer to the color table RGBQUAD *pRgbq = (RGBQUAD *)((LPSTR)pDIB + sizeof(BITMAPINFOHEADER)); pRgbq[0].rgbRed = 0; pRgbq[0].rgbBlue = 0; pRgbq[0].rgbGreen = 0; pRgbq[0].rgbReserved = 0; pRgbq[1].rgbRed = 255; pRgbq[1].rgbBlue = 255; pRgbq[1].rgbGreen = 255; pRgbq[1].rgbReserved = 255; // Pointers to the bits // PVOID pbiBits = (LPSTR)pRgbq + bi.biClrUsed * sizeof(RGBQUAD); // // In the BITMAPINFOHEADER documentation, it appears that // there should be no color table for 32 bit images, but // experience shows that the image is off by 3 words if it // is not included. So here it is. PVOID pbiBits = GetDIBImagePtr( (BITMAPINFOHEADER *)pDIB); //(LPSTR)pRgbq + 3 * sizeof(RGBQUAD); int sizeWords = bi.biSizeImage / 4; RGBQUAD *rgbDib = (RGBQUAD *)pbiBits; long *rgbTif = (long *)raster; _TIFFmemcpy(pbiBits, raster, bi.biSizeImage); } // For now just always default to the RGB 32 bit form. // save as 32 bit // for simplicity else if (true /*BitsPerSample == 8 && SamplePerPixel == 3*/) { // 24 bit color bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = imageWidth; bi.biHeight = imageLength; bi.biPlanes = 1; // always bi.biBitCount = 32; bi.biCompression = BI_RGB; bi.biSizeImage = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; // must be zero for RGB compression (none) bi.biClrImportant = 0; // always // Get the size of the DIB dwDIBSize = GetDIBSize(&bi); // Allocate for the BITMAPINFO structure and the color table. pDIB = GlobalAllocPtr(GHND, dwDIBSize); if (pDIB == 0) { return (NULL); } // Copy the header info *((BITMAPINFOHEADER *)pDIB) = bi; // Get a pointer to the color table RGBQUAD *pRgbq = (RGBQUAD *)((LPSTR)pDIB + sizeof(BITMAPINFOHEADER)); // Pointers to the bits // PVOID pbiBits = (LPSTR)pRgbq + bi.biClrUsed * sizeof(RGBQUAD); // // In the BITMAPINFOHEADER documentation, it appears that // there should be no color table for 32 bit images, but // experience shows that the image is off by 3 words if it // is not included. So here it is. PVOID pbiBits = (LPSTR)pRgbq + 3 * sizeof(RGBQUAD); int sizeWords = bi.biSizeImage / 4; RGBQUAD *rgbDib = (RGBQUAD *)pbiBits; long *rgbTif = (long *)raster; // Swap the byte order while copying for (int i = 0; i < sizeWords; ++i) { rgbDib[i].rgbRed = TIFFGetR(rgbTif[i]); rgbDib[i].rgbBlue = TIFFGetB(rgbTif[i]); rgbDib[i].rgbGreen = TIFFGetG(rgbTif[i]); rgbDib[i].rgbReserved = 0; } } return pDIB; } /////////////////////////////////////////////////////////////// // // Hacked from tif_getimage.c in libtiff in v3.5.7 // // typedef unsigned char u_char; #define DECLAREContigPutFunc(name) \ static void name(TIFFRGBAImage *img, uint32_t *cp, uint32_t x, uint32_t y, \ uint32_t w, uint32_t h, int32_t fromskew, int32_t toskew, \ u_char *pp) #define DECLARESepPutFunc(name) \ static void name(TIFFRGBAImage *img, uint32_t *cp, uint32_t x, uint32_t y, \ uint32_t w, uint32_t h, int32_t fromskew, int32_t toskew, \ u_char *r, u_char *g, u_char *b, u_char *a) DECLAREContigPutFunc(putContig1bitTile); static int getStripContig1Bit(TIFFRGBAImage *img, uint32_t *uraster, uint32_t w, uint32_t h); // typdef struct TIFFDibImage { // TIFFRGBAImage tif; // dibinstalled; // } TIFFDibImage ; void DibInstallHack(TIFFDibImage *dib) { TIFFRGBAImage *img = &dib->tif; dib->dibinstalled = false; switch (img->photometric) { case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: switch (img->bitspersample) { case 1: img->put.contig = putContig1bitTile; img->get = getStripContig1Bit; dib->dibinstalled = true; break; } break; } } /* * 1-bit packed samples => 1-bit * * Override to just copy the data */ DECLAREContigPutFunc(putContig1bitTile) { int samplesperpixel = img->samplesperpixel; (void)y; fromskew *= samplesperpixel; int wb = WIDTHBYTES(w); u_char *ucp = (u_char *)cp; /* Convert 'w' to bytes from pixels (rounded up) */ w = (w + 7) / 8; while (h-- > 0) { _TIFFmemcpy(ucp, pp, w); /* for (x = wb; x-- > 0;) { *cp++ = rgbi(Map[pp[0]], Map[pp[1]], Map[pp[2]]); pp += samplesperpixel; } */ ucp += (wb + toskew); pp += (w + fromskew); } } /* * Hacked from the tif_getimage.c file. */ static uint32_t setorientation(TIFFRGBAImage *img, uint32_t h) { TIFF *tif = img->tif; uint32_t y; switch (img->orientation) { case ORIENTATION_BOTRIGHT: case ORIENTATION_RIGHTBOT: /* XXX */ case ORIENTATION_LEFTBOT: /* XXX */ TIFFWarning(TIFFFileName(tif), "using bottom-left orientation"); img->orientation = ORIENTATION_BOTLEFT; /* fall through... */ case ORIENTATION_BOTLEFT: y = 0; break; case ORIENTATION_TOPRIGHT: case ORIENTATION_RIGHTTOP: /* XXX */ case ORIENTATION_LEFTTOP: /* XXX */ default: TIFFWarning(TIFFFileName(tif), "using top-left orientation"); img->orientation = ORIENTATION_TOPLEFT; /* fall through... */ case ORIENTATION_TOPLEFT: y = h - 1; break; } return (y); } /* * Get a strip-organized image that has * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 * * Hacked from the tif_getimage.c file. * * This is set up to allow us to just copy the data to the raster * for 1-bit bitmaps */ static int getStripContig1Bit(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, uint32_t h) { TIFF *tif = img->tif; tileContigRoutine put = img->put.contig; uint16_t orientation; uint32_t row, y, nrow, rowstoread; uint32_t pos; u_char *buf; uint32_t rowsperstrip; uint32_t imagewidth = img->width; tsize_t scanline; int32_t fromskew, toskew; tstrip_t strip; tsize_t stripsize; u_char *braster = (u_char *)raster; // byte wide raster uint32_t wb = WIDTHBYTES(w); int ret = 1; buf = (u_char *)_TIFFmalloc(TIFFStripSize(tif)); if (buf == 0) { TIFFErrorExtR(tif, TIFFFileName(tif), "No space for strip buffer"); return (0); } y = setorientation(img, h); orientation = img->orientation; toskew = -(int32_t)(orientation == ORIENTATION_TOPLEFT ? wb + wb : wb - wb); TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0) / 8; for (row = 0; row < h; row += nrow) { rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; nrow = (row + rowstoread > h ? h - row : rowstoread); strip = TIFFComputeStrip(tif, row + img->row_offset, 0); stripsize = ((row + img->row_offset) % rowsperstrip + nrow) * scanline; if (TIFFReadEncodedStrip(tif, strip, buf, stripsize) < 0 && img->stoponerr) { ret = 0; break; } pos = ((row + img->row_offset) % rowsperstrip) * scanline; (*put)(img, (uint32_t *)(braster + y * wb), 0, y, w, nrow, fromskew, toskew, buf + pos); y += (orientation == ORIENTATION_TOPLEFT ? -(int32_t)nrow : (int32_t)nrow); } _TIFFfree(buf); return (ret); }