/* This file is part of SGI Format, a File Format plugin for Adobe Photoshop Copyright (C) 2003-9 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 */ /* The SGI Image File Format, Version 1.00: http://astronomy.swin.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html */ //#include #include #include #include "sgiformat.h" struct sgi_header hdr; unsigned char *indata,*rowdata; unsigned long rb; long tabsize,*offsets,*counts; void expandrow(unsigned char *optr,unsigned char *iptr,long n){ unsigned pixel; long count; for( ; n > 0 ; n -= count ){ pixel = *iptr++; if( (count = pixel & 0x7f) ){ if(count > n){ dbg("row overflowed!"); count = n; } if(pixel & RLE_COPY_FLAG){ memcpy(optr,iptr,count); iptr += count; }else memset(optr,*iptr++,count); }else break; /* zero count ends row */ optr += count; } } void expandrow2(unsigned short *optr,unsigned short *iptr,long n){ unsigned pixel; long count; for( ; n > 0 ; n -= count ){ pixel = ((unsigned char*)iptr)[1]; ++iptr; if( (count = pixel & 0x7f) ){ if(count > n){ dbg("row overflowed!"); count = n; } if(pixel & RLE_COPY_FLAG){ while(count--) *optr++ = *iptr++; }else{ while(count--) *optr++ = *iptr; ++iptr; } }else break; } } OSErr checkpoint(FormatRecordPtr pb,unsigned i){ if(!(i % CHUNK_ROWS)){ if(pb->abortProc()){ return userCanceledErr; }else pb->progressProc((pb->loPlane+1)*(long)hdr.ysize-i,hdr.zsize*(long)hdr.ysize); } return noErr; } OSErr readchannel(FormatRecordPtr pb){ OSErr e = noErr; unsigned i; FILECOUNT count; long *p; unsigned char *row; //DPRINTF("reading channel %d",pb->loPlane); pb->hiPlane = pb->loPlane; SETRECT(pb->theRect,0,0,hdr.xsize,hdr.ysize); pb->data = indata; if(hdr.storage == SGI_VERBATIM){ /* uncompressed image: read next channel's scan lines bottom-to-top */ for( i = hdr.ysize ; i-- ; ){ count = rb; row = indata+rb*i; if( (e = FSREAD(F,&count,row)) || (e = checkpoint(pb,i)) ) break; else if(hdr.bpc == 2 && platform_is_LittleEndian()) swapbytes(row,hdr.xsize); } }else if(hdr.storage == SGI_RLE){ if( !(e = SETFPOS(F,fsFromStart,SGI_HEADER_SIZE+pb->loPlane*tabsize)) ){ for( i = hdr.ysize,p = offsets ; i-- ; ) if( (e = read4B(F,p++)) ){ dbg("error reading offsets"); break; } //if(i == -1) dbg("done reading offsets"); }//else dbg("error setting position(1)"); if( !e && !(e = SETFPOS(F,fsFromStart,SGI_HEADER_SIZE+(hdr.zsize+pb->loPlane)*tabsize)) ){ for( i = hdr.ysize,p = counts ; i-- ; ) if( (e = read4B(F,p++)) ){ dbg("error reading counts"); break; } //if(i == -1) dbg("done reading counts"); }//else dbg("error setting position(2)"); if(!e){ for( i = hdr.ysize,row = indata ; i-- ; row += rb ){ if( (e = checkpoint(pb,i)) ) break; // DPRINTF("i=%d counts[i]=%d offsets[i]=%d",i,counts[i],offsets[i]); count = counts[i]; if(count > 2*rb) count = 2*rb; // don't overflow buffer if( SETFPOS(F,fsFromStart,offsets[i]) || FSREAD(F,&count,rowdata) ){ dbg("error setting pos or reading row"); memset(row,0,rb); //break; }else{ // DPRINTF("expanding row %d",i); if(hdr.bpc == 1) expandrow(row,rowdata,hdr.xsize); else{ expandrow2((unsigned short*)row,(unsigned short*)rowdata,hdr.xsize); if(platform_is_LittleEndian()) swapbytes(row,hdr.xsize); } } } //dbg("done reading rows"); } }else e = formatCannotRead; return e; } OSErr read_prepare(FormatRecordPtr pb){ if( is_sgi(F, &hdr) ){ rb = hdr.xsize*hdr.bpc; tabsize = hdr.ysize*4L; pb->maxData = hdr.ysize*rb + (16L<<10); /* size of one channel, plus some slop */ if(hdr.storage == SGI_RLE) pb->maxData += 2*tabsize + 2*rb; /* offsets table, counts table, one RLE row data */ return noErr; }else return formatCannotRead; } OSErr read_start(FormatRecordPtr pb){ OSErr e = noErr; int i; /*DPRINTF("SGI header:\nstorage=%d bpc=%d dimension=%d\n\ xsize=%d ysize=%d zsize=%d pixmin=%d pixmax=%d imagename=\"%s\" colormap=%d", hdr.storage,hdr.bpc,hdr.dimension,hdr.xsize,hdr.ysize,hdr.zsize, hdr.pixmin,hdr.pixmax,hdr.imagename,hdr.colormap);*/ switch(hdr.colormap){ default: //case SGI_COLORMAP: //dbg("bad colormap value"); //return formatCannotRead; case SGI_NORMAL: switch(hdr.bpc){ case 1: pb->imageMode = hdr.zsize < 3 ? plugInModeGrayScale : plugInModeRGBColor; break; case 2: pb->imageMode = hdr.zsize < 3 ? plugInModeGray16 : plugInModeRGB48; break; default: return formatCannotRead; } break; case SGI_DITHERED: for(i = 0x100; i--; ){ pb->redLUT[i] = ((i & 7) * 255)/7; pb->greenLUT[i] = (((i >> 3) & 7) * 255)/7; pb->blueLUT[i] = ((i >> 6) * 255)/3; } pb->imageMode = plugInModeIndexedColor; break; /*case SGI_SCREEN: pb->imageMode = plugInModeGrayScale; break;*/ } pb->depth = 8*hdr.bpc; pb->planes = hdr.zsize; pb->imageHRes = pb->imageVRes = 72L<<16; pb->imageSize.h = hdr.xsize; pb->imageSize.v = hdr.ysize; pb->colBytes = hdr.bpc; pb->rowBytes = rb; pb->loPlane = pb->hiPlane = 0; if(hdr.storage == SGI_RLE){ if( !(offsets = malloc(tabsize)) || !(counts = malloc(tabsize)) || !(rowdata = malloc(2*rb)) ) e = memFullErr; } if(!e) e = (indata = malloc(hdr.ysize*rb)) ? readchannel(pb) : memFullErr; return e; } OSErr read_continue(FormatRecordPtr pb){ OSErr e = noErr; if(++pb->loPlane < hdr.zsize) e = readchannel(pb); else pb->data = NULL; return e; } OSErr read_finish(FormatRecordPtr pb){ if(hdr.storage == SGI_RLE){ free(offsets); free(counts); free(rowdata); } free(indata); return noErr; }