struct dictentry *findbykey(psd_file_t f, int level, struct dictentry *parent, char *key, int len, int resetpos) { struct dictentry *d; for(d = parent; d->key; ++d) if(KEYMATCH(key, d->key)){ char *tagname = d->tag + (d->tag[0] == '-'); //fprintf(stderr, "matched tag %s\n", d->tag); if(d->func) entertag(f, level, len, parent, d, resetpos); else{ // there is no function to parse this block. // because tag is empty in this case, we only need to consider // parent's one-line-ness. if(xml){ if(parent->tag[0] == '-') fprintf(xml, " <%s /> <!-- not parsed --> ", tagname); else fprintf(xml, "%s<%s /> <!-- not parsed -->\n", tabs(level), tagname); } } return d; } return NULL; }
void layerblendmode(psd_file_t f, int level, int len, struct blend_mode_info *bm){ struct dictentry *d; const char *indent = tabs(level); if(xml && KEYMATCH(bm->sig, "8BIM")){ fprintf(xml, "%s<BLENDMODE OPACITY='%g' CLIPPING='%d'>\n", indent, bm->opacity/2.55, bm->clipping); findbykey(f, level+1, bmdict, bm->key, len, 1); if(bm->flags & 1) fprintf(xml, "%s\t<TRANSPARENCYPROTECTED />\n", indent); if(bm->flags & 2) fprintf(xml, "%s\t<HIDDEN />\n", indent); if((bm->flags & (8|16)) == (8|16)) // both bits set fprintf(xml, "%s\t<PIXELDATAIRRELEVANT />\n", indent); fprintf(xml, "%s</BLENDMODE>\n", indent); } if(!xml){ d = findbykey(f, level+1, bmdict, bm->key, len, 1); VERBOSE(" blending mode: sig='%c%c%c%c' key='%c%c%c%c'(%s) opacity=%d(%d%%) clipping=%d(%s)\n\ flags=%#x(transp_prot%s visible%s bit4valid%s pixel_data_irrelevant%s)\n", bm->sig[0],bm->sig[1],bm->sig[2],bm->sig[3], bm->key[0],bm->key[1],bm->key[2],bm->key[3], d ? d->desc : "???", bm->opacity, (bm->opacity*100+127)/255, bm->clipping, bm->clipping ? "non-base" : "base", bm->flags, BITSTR(bm->flags&1), BITSTR(bm->flags&2), BITSTR(bm->flags&8), BITSTR(bm->flags&16) ); }
unsigned scan(unsigned char *addr, size_t len, int psd_version, struct layer_info *li) { unsigned char *p = addr, *q; size_t i; int j, k; unsigned n = 0, ps_ptr_bytes = 2 << psd_version; struct dictentry *de; for(i = 0; i < len;) { if(KEYMATCH((char*)p+i, "8BIM")){ i += 4; // found possible layer signature // check next 4 bytes for a known blend mode for(de = bmdict; de->key; ++de) if(!memcmp(de->key, (char*)p+i, 4)){ // found a possible layer blendmode signature // try to guess number of channels for(j = 1; j < 64; ++j){ q = p + i - 4 - j*(ps_ptr_bytes + 2) - 2; if(peek2B(q) == j){ long t = peek4B(q-16), l = peek4B(q-12), b = peek4B(q-8), r = peek4B(q-4); // sanity check bounding box if(b >= t && r >= l){ // sanity check channel ids for(k = 0; k < j; ++k){ int chid = peek2B(q + 2 + k*(ps_ptr_bytes + 2)); if(chid < -2 || chid >= j) break; // smells bad, give up } if(k == j){ // channel ids were ok. could still be a valid guess... ++n; if(li){ li->filepos = q - p - 16; ++li; } else VERBOSE("scavenge @ %8td : key: %c%c%c%c could be %d channel layer: t = %ld, l = %ld, b = %ld, r = %ld\n", q - p - 16, de->key[0], de->key[1], de->key[2], de->key[3], j, t, l, b, r); break; } } } } break; } }else ++i; } return n; }
int is_resource(unsigned char *addr, size_t len, size_t offset) { int namelen; long size; if(KEYMATCH(addr + offset, "8BIM")){ offset += 4; // type offset += 2; // id namelen = addr[offset]; offset += PAD2(1+namelen); size = peek4B(addr+offset); offset += 4; offset += PAD2(size); // skip resource block data return offset; // should be offset of next resource } return 0; }
int dopsd(psd_file_t f, char *psdpath, struct psd_header *h){ int result = 0; // file header fread(h->sig, 1, 4, f); h->version = get2Bu(f); get4B(f); get2B(f); // reserved[6]; h->channels = get2Bu(f); h->rows = get4B(f); h->cols = get4B(f); h->depth = get2Bu(f); h->mode = get2Bu(f); if(!feof(f) && KEYMATCH(h->sig, "8BPS")){ if(h->version == 1 #ifdef PSBSUPPORT || h->version == 2 #endif ){ openfiles(psdpath, h); if(listfile) fprintf(listfile, "-- PSD file: %s\n", psdpath); if(xml){ fputs("<PSD FILE='", xml); fputsxml(psdpath, xml); fprintf(xml, "' VERSION='%u' CHANNELS='%u' ROWS='%u' COLUMNS='%u' DEPTH='%u' MODE='%u'", h->version, h->channels, h->rows, h->cols, h->depth, h->mode); if(h->mode >= 0 && h->mode < 16) fprintf(xml, " MODENAME='%s'", mode_names[h->mode]); fputs(">\n", xml); } UNQUIET(" PS%c (version %u), %u channels, %u rows x %u cols, %u bit %s\n", h->version == 1 ? 'D' : 'B', h->version, h->channels, h->rows, h->cols, h->depth, h->mode >= 0 && h->mode < 16 ? mode_names[h->mode] : "???"); if(h->channels <= 0 || h->channels > 64 || h->rows <= 0 || h->cols <= 0 || h->depth <= 0 || h->depth > 32 || h->mode < 0) { alwayswarn("### something isn't right about that header, giving up now.\n"); } else{ h->colormodepos = ftello(f); if(h->mode == ModeDuotone) duotone_data(f, 1); else skipblock(f, "color mode data"); h->resourcepos = ftello(f); if(rsrc || resdump) doimageresources(f); else skipblock(f, "image resources"); dolayermaskinfo(f, h); h->layerdatapos = ftello(f); VERBOSE("## layer data begins @ " LL_L("%lld","%ld") "\n", h->layerdatapos); result = 1; } }else alwayswarn("# \"%s\": version %d not supported\n", psdpath, h->version); }else alwayswarn("# \"%s\": couldn't read header, or is not a PSD/PSB\n", psdpath); if(!result) alwayswarn("# Try --scavenge (and related options) to see if any layer data can be found.\n"); return result; }