/* This file is part of TIFFlib Format, a File Format plugin for Adobe Photoshop Copyright (C) 2005-7 Toby Thain, toby@telegraphics.com.au This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #ifdef macintosh #include #else #include #endif #include "tifflibplugin.h" unsigned char *indata = NULL, *tempdata = NULL; TIFF *tif = NULL; uint16 *cmap[3] = {NULL,NULL,NULL}, samplesperpixel, bitspersample; uint32 imgw, imgh, tilew, tileh, bufsize, rowsperstrip, curleft, curtop; int invert = 0; void unpack(unsigned char *dst,unsigned char *src,unsigned cols,unsigned rows); OSErr readtile(FormatRecordPtr pb); OSErr readstrip(FormatRecordPtr pb); void unpack(unsigned char *dst,unsigned char *src,unsigned cols,unsigned rows){ unsigned i, j, shift, mask = (1<>shift) & mask; if(!shift){ // ran out of bits shift = 8; ++p; } } // skip partial byte at end of row if(shift < 8) ++p; } } OSErr readtile(FormatRecordPtr pb){ ttile_t t; // check if we've finished a plane if(curtop >= imgh){ // if planar data, keep going if more planes to read if( (pb->hiPlane == pb->loPlane) && pb->loPlane < (samplesperpixel-1) ){ pb->hiPlane = ++pb->loPlane; curleft = curtop = 0; }else{ // for interleaved data, stop after all tiles read pb->data = NULL; return noErr; } } t = TIFFComputeTile(tif,curleft,curtop,0,pb->loPlane); //{char s[0x100]; sprintf(s,"curleft=%lu curtop=%lu loPlane=%d tile=%lu",curleft,curtop,pb->loPlane,t);dbg(s);} // get file data if(TIFFReadEncodedTile(tif,t,indata,bufsize) == -1) return formatCannotRead; // tell Photoshop about it SETRECT(pb->theRect, curleft, curtop, curleft+tilew, curtop+tileh); if(pb->theRect.right > imgw){ pb->theRect.right = imgw; curleft = 0; curtop += tileh; }else curleft += tilew; if(pb->theRect.bottom > imgh) pb->theRect.bottom = imgh; if(bitspersample > 1 && bitspersample < 8){ unpack(tempdata, indata, tilew, tileh); pb->data = tempdata; }else pb->data = indata; return noErr; } OSErr readstrip(FormatRecordPtr pb){ tstrip_t strip; // check if we've finished a plane if(curtop == imgh){ // if planar data, keep going if more planes to read if( (pb->hiPlane == pb->loPlane) && pb->loPlane < (samplesperpixel-1) ){ pb->hiPlane = ++pb->loPlane; curtop = 0; }else{ // for interleaved data, stop after all strips read pb->data = NULL; return noErr; } } strip = TIFFComputeStrip(tif, curtop, pb->loPlane); //{char s[0x100]; sprintf(s,"curleft=%lu curtop=%lu loPlane=%d strip=%lu",curleft,curtop,pb->loPlane,strip);dbg(s);} if(TIFFReadEncodedStrip(tif, strip, indata, bufsize) == -1) return formatCannotRead; SETRECT(pb->theRect, 0, curtop, imgw, curtop+rowsperstrip); curtop += rowsperstrip; if(curtop > imgh) pb->theRect.bottom = curtop = imgh; if(bitspersample>1 && bitspersample<8){ unpack(tempdata, indata, imgw, 1); pb->data = tempdata; }else pb->data = indata; return noErr; } OSErr read_start(FormatRecordPtr pb){ OSErr e = noErr; uint16 pmetric, resunit, inks, pconfig; int palvalid = 0, i, n, w, deep; float xres, yres; struct revertinfo rev; //char s[0x200]; if( (tif = TIFFFdOpen(pb->dataFork, "", "r")) && TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imgw) && TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imgh) && TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample) && TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &pmetric) && TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel) ) { // grab compression type in case we re-save the image later if(TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &rev.comptype)) putrevertinfo(pb, &rev); pb->imageSize.h = imgw; pb->imageSize.v = imgh; pb->planes = samplesperpixel; deep = bitspersample > 8; pb->depth = bitspersample==1 ? 1 : (8 << deep); // determine image mode if(pmetric==PHOTOMETRIC_MINISWHITE || pmetric==PHOTOMETRIC_MINISBLACK){ if(bitspersample==1){ if(samplesperpixel>1) e = formatCannotRead; // Photoshop only supports 1-channel bitmaps else{ pb->imageMode = plugInModeBitmap; invert = pmetric != PHOTOMETRIC_MINISWHITE; } }else{ pb->imageMode = deep ? plugInModeGray16 : plugInModeGrayScale; invert = pmetric != PHOTOMETRIC_MINISBLACK; } } else if(pmetric==PHOTOMETRIC_PALETTE){ // convert Indexed plus extra channels ->RGB? // handle palette n = sizeof(uint16)<imageMode = plugInModeIndexedColor; for(i = 0, n = 1<redLUT[i] = cmap[0][i] >> 8; pb->greenLUT[i] = cmap[1][i] >> 8; pb->blueLUT[i] = cmap[2][i] >> 8; } for(; i < 0x100; ++i) pb->redLUT[i] = pb->greenLUT[i] = pb->blueLUT[i] = 0; }else e = formatCannotRead; } else if(pmetric==PHOTOMETRIC_RGB){ pb->imageMode = deep ? plugInModeRGB48 : plugInModeRGBColor; } else if( pmetric==PHOTOMETRIC_SEPARATED && TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inks) && inks==INKSET_CMYK ) { pb->imageMode = deep ? plugInModeCMYK64 : plugInModeCMYKColor; invert = 1; } else{ // catchall pb->imageMode = deep ? plugInModeDeepMultichannel : plugInModeMultichannel; } // handle resolution info if( (TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit) && resunit != RESUNIT_NONE) && TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) && TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) ) { pb->imageHRes = rint(resunit==RESUNIT_CENTIMETER ? xres*65536.*2.54 : xres*65536.); pb->imageVRes = rint(resunit==RESUNIT_CENTIMETER ? yres*65536.*2.54 : yres*65536.); }else pb->imageHRes = pb->imageVRes = 72L<<16; // read interleaved? w = TIFFIsTiled(tif) && TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tilew) ? tilew : imgw; if( samplesperpixel==1 || (TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &pconfig) && pconfig==PLANARCONFIG_SEPARATE) ) { // always read one plane at a time pb->colBytes = 1<rowBytes = bitspersample==1 ? (w+7)/8 : w*pb->colBytes; pb->loPlane = pb->hiPlane = 0; }else{ // all planes interleaved pb->planeBytes = 1<colBytes = samplesperpixel*pb->planeBytes; pb->rowBytes = w*pb->colBytes; pb->loPlane = 0; pb->hiPlane = samplesperpixel-1; } // strips or tiles? if(TIFFIsTiled(tif)){ if(TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tilew) && TIFFGetField(tif, TIFFTAG_TILELENGTH, &tileh)) { indata = malloc((bufsize = TIFFTileSize(tif))+4); if(bitspersample!=1 && bitspersample<8) tempdata = malloc(pb->colBytes*samplesperpixel*tilew*tileh); curleft = curtop = 0; readtile(pb); }else e = formatCannotRead; }else{ if(TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip)){ indata = malloc((bufsize = TIFFStripSize(tif))+4); if(bitspersample>1 && bitspersample<8) tempdata = malloc(pb->colBytes*samplesperpixel*imgw); curtop = 0; readstrip(pb); }else e = formatCannotRead; } if(!e && invert) invertbuf(pb->data, bufsize); }else e = formatCannotRead; if(e){ if(cmap[0]) free(cmap[0]); if(cmap[1]) free(cmap[1]); if(cmap[2]) free(cmap[2]); } /*sprintf(s,"read_start: err=%d imageMode=%d imageSize=%d,%d depth=%d planes=%d data=%p\n" "theRect=%d,%d,%d,%d loPlane=%d hiPlane=%d colBytes=%d rowBytes=%ld planeBytes=%ld", e,pb->imageMode,pb->imageSize.h,pb->imageSize.v,pb->depth,pb->planes,pb->data, pb->theRect.left,pb->theRect.top,pb->theRect.right,pb->theRect.bottom, pb->loPlane,pb->hiPlane,pb->colBytes,pb->rowBytes,pb->planeBytes); dbg(s);*/ return e; } OSErr read_continue(FormatRecordPtr pb){ OSErr e = TIFFIsTiled(tif) ? readtile(pb) : readstrip(pb); if(!e && invert) invertbuf(indata, bufsize); return e; } OSErr read_finish(FormatRecordPtr pb){ if(cmap[0]) free(cmap[0]); if(cmap[1]) free(cmap[1]); if(cmap[2]) free(cmap[2]); free(indata); if(tempdata) free(tempdata); TIFFClose(tif); return noErr; }