/* This file is part of PSPFormat, a File Format plugin for Adobe Photoshop Copyright (C) 2003-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 */ /* PSP File Format Specification is Copyright (C) 2000 Jasc Software, Inc. See http://www.jasc.com/specs/psp.asp */ //#include #include #include #include "pspformat.h" #include "str.h" #include "misc.h" #include "ui.h" #include "PIProperties.h" int layercnt, channelcnt, transcnt, alphacnt, thisplane, imageplanes, firstalpha, chosenlayer; unsigned char *indata = NULL; PSP_image_attr_chunk gia; PSP_layer_info_chunk *layers = NULL; PSP_channel_info_chunk channels[MAX_CHANNELS]; PSP_alpha_channel_info_chunk *alphainfo = NULL; PSP_channel_info_chunk *psplanes[MAX_CHANNELS]; static OSErr readplane(FormatRecordPtr pb, int plane, PSP_layer_info_chunk *li){ OSErr e = noErr; unsigned long *lp, pspdatasize; PSP_channel_info_chunk *ci = psplanes[plane]; PSP_alpha_channel_info_chunk *aci; unsigned char *p, *q, *inrow, *outrow, *outptr, *tempbuf; int i, j, psprb, rasterw, rasterh; if(plane < firstalpha){ /* it's an image plane, or layer transparency */ SETRECT(pb->theRect, li->saved_rect.left, li->saved_rect.top, li->saved_rect.right, li->saved_rect.bottom); }else{ /* alpha channel */ aci = alphainfo + (plane - firstalpha); SETRECT(pb->theRect, aci->saved_rect.left, aci->saved_rect.top, aci->saved_rect.right, aci->saved_rect.bottom); } pb->loPlane = pb->hiPlane = plane; rasterw = pb->theRect.right - pb->theRect.left; rasterh = pb->theRect.bottom - pb->theRect.top; if( ci && ci->bitmap_type == PSP_DIB_IMAGE && gia.bit_depth < 8 ){ // assume rows are padded to multiple of 4 bytes psprb = PAD4((long)gia.bit_depth * rasterw); pb->rowBytes = PAD4((long)pb->depth * rasterw); }else // no row padding; whole bytes only psprb = pb->rowBytes = rasterw; pb->planeBytes = (long)pb->rowBytes * rasterh; pspdatasize = (long)psprb * rasterh; if(!indata) indata = malloc(pb->planeBytes); if( (pb->data = indata) ){ DPRINTF("\nreadplane: raster=(%d,%d) PSP rowBytes=%d dataSize=%ld\n" " theRect=(%d,%d,%d,%d) loPlane=%d hiPlane=%d\n" " colBytes=%d rowBytes=%ld planeBytes=%ld data=%#x", rasterw,rasterh,psprb,pspdatasize, pb->theRect.left,pb->theRect.top,pb->theRect.right,pb->theRect.bottom, pb->loPlane,pb->hiPlane,pb->colBytes,pb->rowBytes,pb->planeBytes,pb->data); if(ci){ if(gia.bit_depth == 4){ // for 4 bits/pixel data, we need a separate buffer to hold the input, // while we expand it to 8 bits/pixel in the output buffer. if( !(tempbuf = malloc(pspdatasize)) ) return memFullErr; outptr = tempbuf; }else outptr = indata; /* seek to channel data, read it, decompress it into a buffer (outptr) */ if( !psp_channel((FILEREF)pb->dataFork, &gia, ci, outptr, pspdatasize) ){ switch(gia.bit_depth){ /* now postprocess if necessary */ case 1: /* for bitmap mode, invert data */ for(i = pb->planeBytes/sizeof(long), lp = (unsigned long*)indata; i--;) *lp++ ^= ~0UL; break; case 4: /* expand 4 bit pixels to Photoshop 8-bit Indexed pixels */ for(j = 0, outrow = indata, inrow = tempbuf; j < rasterh; ++j, inrow += psprb, outrow += pb->rowBytes){ for(i = (rasterw+1)/2, q = outrow, p = inrow; i--;){ *q++ = *p >> 4; *q++ = *p & 15; ++p; } } free(tempbuf); break; } }else INFO("readplane: psp_channel() returned error!"); }else{ DPRINTF("readplane: psplanes[plane]==NULL! returning zero data"); memset(indata, 0, pb->planeBytes); } }else{ DPRINTF("readplane: can't get memory (%d bytes)",pb->planeBytes); e = memFullErr; } /* { char fn[0x100]; FILE *f; //myp2cstrcpy(fn, pb->fileSpec->name); sprintf(fn, "pspformat-out-%d-r%d-c%d-b%ld.raw", plane, rasterh, rasterw, pb->rowBytes); f = fopen(fn, "w"); fwrite(pb->data, pb->planeBytes, 1, f); fclose(f); long i, j, k = rasterw > 36 ? 36 : rasterw; unsigned char *p = pb->data; for(j = 0; j < rasterh; ++j){ for(i = 0; i < k; ++i) printf("%02x", p[i]); p += pb->rowBytes; if(k < rasterw) puts("..."); else putchar('\n'); } } */ return e; } OSErr headerok(FILEREF r, PSP_file_header *ph){ OSErr e; if( !(e = psp_read_file_header(r, ph)) ) e = strcmp(ph->signature, PSP_SIGNATURE) ? formatCannotRead : noErr; return e; } OSErr read_start(FormatRecordPtr pb, intptr_t *data){ OSErr e = formatCannotRead; PSP_file_header h; static double resunit[] = {1., 1., 2.54}; // PSP_METRIC_UNDEFINED,PSP_METRIC_INCH,PSP_METRIC_CM int a, i, idx; RGBQUAD *pal = 0; PSP_palette_info_chunk pi; PSP_channel_info_chunk *ci; struct revertinfo rev; /* Initialise globals; needed on 68K! */ layers = NULL; alphainfo = NULL; indata = NULL; if( !(e = headerok((FILEREF)pb->dataFork, &h)) ){ rev.savevers = h.major_version; //dprintf("\nPSP file header, version=%d,%d",h.major_version,h.minor_version); // Process all the blocks of the file. This will set the counters // for layers, channels, transparency masks, and alpha channels: for( layercnt = channelcnt = transcnt = alphacnt = 0 ; !(e = psp_block((FILEREF)pb->dataFork,&h,&gia,&layers,channels,&alphainfo,&pi,&pal)) ; ) ; /* note, a "cannot read" return is deliberately ignored if we found some layers. * this is to facilitate recovery of corrupt files. */ if( e == noErr || e == eofErr || (e==formatCannotRead && layercnt>0) ){ rev.savecomp = gia.comp_type; putrevertinfo(pb, &rev); //dprintf("counted %d image layers",layercnt); if(layercnt){ chosenlayer = 0; if( layercnt==1 || layerdlg() ){ // initialise channel positions, so we can later see which ones // were correctly found (datapos != 0) for(i = MAX_CHANNELS; i--;){ channels[i].datapos = 0; psplanes[i] = NULL; } if( !(e = psp_layer((FILEREF)pb->dataFork,&h,&gia,layers+chosenlayer,channels,&alphainfo,&pi,&pal)) ){ imageplanes = 1; pb->depth = 8; switch(gia.bit_depth){ case 1: /* FIXME: we should check palette is strictly black and white first */ pb->imageMode = plugInModeBitmap; pb->depth = 1; break; case 4: case 8: pb->imageMode = gia.greyscale_flag ? plugInModeGrayScale : plugInModeIndexedColor; break; case 24: pb->imageMode = plugInModeRGBColor; imageplanes = 3; break; default: DPRINTF("weird bit depth: %d",gia.bit_depth); goto err; } /* determine mapping from PSP channels to Photoshop planes: image planes come first (1 or 3), then layer transparency (if available), then alpha channels */ firstalpha = imageplanes + (transcnt > 0); pb->planes = firstalpha + alphacnt; DPRINTF("channelcnt=%d imageplanes=%d transcnt=%d alphacnt=%d planes=%d", channelcnt,imageplanes,transcnt,alphacnt,pb->planes); for(i = 0, a = firstalpha, ci = channels; i < channelcnt; ++i, ++ci){ if(ci->datapos) switch(ci->bitmap_type){ case PSP_DIB_IMAGE: idx = ci->channel_type == PSP_CHANNEL_COMPOSITE ? 0 : ci->channel_type-1; DPRINTF("PSP_DIB_IMAGE @ %6ld index = %d",ci->datapos,idx); psplanes[idx] = ci; break; case PSP_DIB_TRANS_MASK: DPRINTF("PSP_DIB_TRANS_MASK @ %6ld index = %d (transparencyPlane)",ci->datapos,imageplanes); psplanes[imageplanes] = ci; if(pb->transparencyPlane) pb->transparencyPlane = imageplanes; break; case PSP_DIB_ALPHA_MASK: DPRINTF("PSP_DIB_ALPHA_MASK @ %6ld index = %d",ci->datapos,a); psplanes[a++] = ci; break; } else DPRINTF("*** bad channel %d skipped!",i); } /* set Photoshop colour palette */ if(pal){ if(pb->imageMode == plugInModeIndexedColor){ if(pi.entry_count > 256) pi.entry_count = 256; for( i = 0 ; i < pi.entry_count ; ++i ){ pb->redLUT[i] = pal[i].rgbRed; pb->greenLUT[i] = pal[i].rgbGreen; pb->blueLUT[i] = pal[i].rgbBlue; } /* black out extra entries */ for( ; i < 256 ; ++i ) pb->redLUT[i] = pb->greenLUT[i] = pb->blueLUT[i] = 0; pb->lutCount = pi.entry_count; // PS 5.5 or later } free(pal); } pb->imageHRes = pb->imageVRes = gia.resolution*65536.*resunit[gia.res_metric]; pb->imageSize.h = gia.image_width; pb->imageSize.v = gia.image_height; pb->colBytes = 1; DPRINTF("read_start: imageMode=%d imageSize=(%d,%d) depth=%d planes=%d res=%gdpi", pb->imageMode,pb->imageSize.h,pb->imageSize.v, pb->depth,pb->planes,gia.resolution*resunit[gia.res_metric]); thisplane = 0; e = readplane(pb, thisplane++, layers+chosenlayer); }else dbg("psp_layer FAIL"); }else e = userCanceledErr; }else{ alert("Cannot open that PSP file; it contains no raster (image) layers."); e = userCanceledErr; } }else dbg("read_start: unexpected error from psp_block()"); } err: return e; } OSErr read_continue(FormatRecordPtr pb, intptr_t *data){ OSErr e = noErr; if(pb->abortProc()) e = userCanceledErr; else{ // pb->progressProc(ypixel+currow,ypixel*2); if(thisplane < pb->planes) e = readplane(pb, thisplane++, layers+chosenlayer); else pb->data = NULL; //SETRECT(pb->theRect,0,0,0,0); } return e; } OSErr read_finish(FormatRecordPtr pb, intptr_t *data){ if(layers) free(layers); if(alphainfo) free(alphainfo); if(indata) free(indata); return noErr; }