/* This file is part of DITABIS, a File Format plugin for Adobe Photoshop Copyright (C) 2003-6 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 #include #include #include "ditabis.h" #include "str.h" #include "misc.h" #include "bufio.h" #include "PIProperties.h" enum{ MAXLINE = 0x200, OUTBYTEPERPIXEL = 2, MEM_SLOP = 16L<<10, // allow some spare memory, just in case }; /* DITABIS header fields */ long header = 2048,ypixel,xpixel,byteperpixel,magnification; char *magstr = ""; double xresolution,yresolution,scalefactor; unsigned char *indata,*outdata; long currow,chunksize,inrowbytes,outrowbytes,chunkrows; /* Tags that must be present: CREATED = Time and Date String HEADER = Length of header, typically 2048 YPIXEL = Number of pixel in Y typ. 3000..3500 pixel XPIXEL = Number of pixel in X typ. 3000..3200 pixel BYTE PER PIXEL = Data depth in byte, 2,3 or 4 XRESOLUTION = Resolution X in µm YRESOLUTION = Resolution Y in µm, exact value in parentheses THUMB-NAIL-ZOOM = Zoom factor for preview, typ. 10 Additional tags: MAGNIFICATION: gives the magnification in the microscope. OFFSET: gives the value that represents zero dose OFFSET CORRECTION: Indicator wether Offset Correction was used GAIN: Gain setting of the instrument LASER: Laser setting of the instrument PARAMS: Settings file used for this scan FORMAT: Format file used for this scan CHANNEL: Data channel used for this file MICRON-MARK Position, length and text of micron mark overlay COMMENT: is always the last tag and has no equal sign after. It is followed by the comment string that may contain CR/LF characters and is terminated by a null character. */ struct node_t *firstnode = 0; int headertext,commenttext,headerlines,commentlines; double getres(char *v); double getres(char *v){ char *p,*q; double val; for( p = v ; *p && *p != '(' ; ++p ) ; // p points to NUL, or opening parenthesis if(*p){ ++p; for( q = p ; *q && *q != ')' ; ++q ) ; *q = 0; val = strtod(p,NULL); }else // no parenthesis; use integer value val = atol(v); return val; } unsigned long pixelvalue(unsigned char *p); unsigned long pixelvalue(unsigned char *p){ unsigned long val = 0; switch(byteperpixel){ case 4: val |= (unsigned long)p[3] << 24; case 3: val |= (unsigned long)p[2] << 16; case 2: val |= (unsigned long)p[1] << 8; case 1: val |= (unsigned long)p[0]; } return val; } void readheader(FILEREF r,Boolean keepmetadata){ char linebuf[MAXLINE],*p,*q; int c,line,lineptr; Boolean incomment = false; struct node_t *node,**nextnode = &firstnode; long bytes; headertext = commenttext = headerlines = commentlines = 0; ypixel = xpixel = byteperpixel = 0; magnification = 1; xresolution = yresolution = 0.; for( line=lineptr=bytes=0 ; bytes
next = 0; node->length = lineptr; node->iscomment = incomment; if( (node->text = malloc(lineptr+1)) ){ memcpy(node->text,linebuf,lineptr+1); *nextnode = node; nextnode = &node->next; incomment ? ++commentlines,commenttext+=lineptr : ++headerlines,headertext+=lineptr; }else free(node); } if(!incomment){ // look for "=" for( p = linebuf ; *p && *p != '=' ; ++p ) ; // p either points to NUL (end of line) or "=" character if(*p){ // look for value for( q = p+1 ; *q && *q == ' ' ; ++q ) ; if(*q){ // strip trailing spaces from key string while(*--p == ' ') ; p[1] = 0; // terminate it if(!strcmp(linebuf,"HEADER")) header = atol(q); else if(!strcmp(linebuf,"YPIXEL")) xpixel = atol(q); // deliberately transposed x-y else if(!strcmp(linebuf,"XPIXEL")) ypixel = atol(q); // deliberately transposed x-y else if(!strcmp(linebuf,"BYTE PER PIXEL")) byteperpixel = atol(q); else if(!strcmp(linebuf,"XRESOLUTION")) yresolution = getres(q); // deliberately transposed x-y else if(!strcmp(linebuf,"YRESOLUTION")) xresolution = getres(q); // deliberately transposed x-y else if(!strcmp(linebuf,"MAGNIFICATION")){ magnification = atol(q); if(keepmetadata) magstr = my_strdup(q); } }//else no value found! }else{ // no "=" found // strip trailing spaces from key string while(*--p == ' ') ; p[1] = 0; if(!strcmp(linebuf,"COMMENT")) incomment = true; } } ++line; lineptr = 0; }else{ if(lineptr < MAXLINE-1) linebuf[lineptr++] = c; } } } // if(c == EOF) syntaxalert("end of file"); } OSErr getchunk(FormatRecordPtr pb,int toprow,int nrows); OSErr getchunk(FormatRecordPtr pb,int toprow,int nrows){ OSErr e; long count; unsigned char *p; unsigned short *q; pb->theRect.left = 0; pb->theRect.right = xpixel; pb->theRect.top = toprow; pb->theRect.bottom = toprow+nrows; pb->loPlane = pb->hiPlane = 0; pb->colBytes = OUTBYTEPERPIXEL; /* Spacing between columns */ pb->rowBytes = outrowbytes; /* Spacing between rows */ count = nrows*inrowbytes; if( !(e = FSRead((FILEREF)pb->dataFork,&count,indata)) ){ pb->data = outdata; // file data is LittleEndian and may be deeper than 2 bytes ber pixel for( p=indata,count=xpixel*nrows,q=(unsigned short*)outdata ; count-- ; p += byteperpixel ) *q++ = pixelvalue(p)*scalefactor; } return e; } OSErr findmax(FormatRecordPtr pb); OSErr findmax(FormatRecordPtr pb){ OSErr e; long count; unsigned long val,max = 0; int j,k; unsigned char *p; if(!(e = SetFPos((FILEREF)pb->dataFork,fsFromStart,header))) for( j = ypixel ; j ; j -= k ){ if(pb->abortProc()) return userCanceledErr; else{ pb->progressProc(ypixel-j,ypixel*2); k = lesser(chunkrows,j); count = k*inrowbytes; if( (e = FSRead((FILEREF)pb->dataFork,&count,indata)) ) return e; else for( p=indata,count=xpixel*k ; count-- ; p += byteperpixel ){ val = pixelvalue(p); if(val > max) max = val; } } } scalefactor = max ? 65535./max : 1.; // {char s[0x100];sprintf(s,"got max %ld scalefactor=%g",max,scalefactor);dbg(s);} return noErr; } OSErr read_start(FormatRecordPtr pb,long *data){ OSErr e; long mem; extern long bytesinbuf,bufptr; bytesinbuf = bufptr = 0; readheader((FILEREF)pb->dataFork,true); if( xpixel && ypixel && byteperpixel ){ pb->imageMode = plugInModeGray16; pb->planes = 1; pb->imageSize.h = xpixel; /* Size of image */ pb->imageSize.v = ypixel; pb->depth = 16; /* Bits per sample */ pb->imageHRes = xresolution ? (25400L<<16)/xresolution + .5 : 72L<<16; /* Pixels per inch */ pb->imageVRes = yresolution ? (25400L<<16)/yresolution + .5 : 72L<<16; // if(pb->canTranspose) pb->needTranspose = true; inrowbytes = xpixel*byteperpixel; outrowbytes = xpixel*OUTBYTEPERPIXEL; mem = pb->maxData - MEM_SLOP; chunkrows = lesser(mem / (inrowbytes+outrowbytes),ypixel); if(!chunkrows) // sanity check chunkrows = 1; // we are likely to run out of memory though /* sprintf(s,"xpixel=%ld ypixel=%ld byteperpixel=%ld rowbytes=%ld chunkrows=%ld maxData=%ld xres=%g yres=%g", xpixel,ypixel,byteperpixel,rowbytes,chunkrows,pb->maxData,xresolution,yresolution); dbg(s); */ if( (indata = malloc(chunkrows*inrowbytes)) ){ if( (outdata = malloc(chunkrows*outrowbytes)) ){ if( !(e = findmax(pb)) && !(e = SetFPos((FILEREF)pb->dataFork,fsFromStart,header)) ) e = getchunk(pb,currow = 0,chunkrows); if(e) free(outdata); }else e = memFullErr; if(e) free(indata); }else e = memFullErr; }else e = formatCannotRead; return e; } OSErr read_continue(FormatRecordPtr pb,long *data){ OSErr e = noErr; int rowsleft; currow += chunkrows; rowsleft = ypixel - currow; if(pb->abortProc()) e = userCanceledErr; else{ pb->progressProc(ypixel+currow,ypixel*2); if(rowsleft > 0) e = getchunk(pb,currow,lesser(chunkrows,rowsleft)); else pb->data = 0; //SETRECT(&pb->theRect,0,0,0,0); } return e; } OSErr read_finish(FormatRecordPtr pb,long *data){ Handle h; if( pb->propertyProcs && (h = build_metadata(pb)) ) pb->propertyProcs->setPropertyProc(kPhotoshopSignature,propCaption,0, 0,h); free(indata); free(outdata); return noErr; }