PSDParser extends AbstractParser { public void parse( InputStream stream, ContentHandler handler, Metadata metadata, ParseContext context) throws IOException, SAXException, TikaException { byte[] signature = new byte[4]; IOUtils.readFully(stream, signature); if (signature[0] == (byte) '8' && signature[1] == (byte) 'B' && signature[2] == (byte) 'P' && signature[3] == (byte) 'S') { } else { throw new TikaException("PSD/PSB magic signature invalid"); } int version = EndianUtils.readUShortBE(stream); if (version == 1 || version == 2) { } else { throw new TikaException("Invalid PSD/PSB version " + version); } IOUtils.readFully(stream, new byte[6]); int numChannels = EndianUtils.readUShortBE(stream); int height = EndianUtils.readIntBE(stream); int width = EndianUtils.readIntBE(stream); metadata.set(TIFF.IMAGE_LENGTH, height); metadata.set(TIFF.IMAGE_WIDTH, width); int depth = EndianUtils.readUShortBE(stream); metadata.set(TIFF.BITS_PER_SAMPLE, Integer.toString(depth)); int colorMode = EndianUtils.readUShortBE(stream); if (colorMode < Photoshop._COLOR_MODE_CHOICES_INDEXED.length) { metadata.set(Photoshop.COLOR_MODE, Photoshop._COLOR_MODE_CHOICES_INDEXED[colorMode]); } long colorModeSectionSize = EndianUtils.readIntBE(stream); IOUtils.skipFully(stream, colorModeSectionSize); long imageResourcesSectionSize = EndianUtils.readIntBE(stream); long read = 0; int blocks = 0; while (read < imageResourcesSectionSize && blocks < MAX_BLOCKS) { ResourceBlock rb = new ResourceBlock(stream); if (rb.totalLength <= 0) { } read += rb.totalLength; if (rb.id == ResourceBlock.ID_CAPTION) { metadata.add(TikaCoreProperties.DESCRIPTION, rb.getDataAsString()); } else if (rb.id == ResourceBlock.ID_EXIF_1) { } else if (rb.id == ResourceBlock.ID_EXIF_3) { } else if (rb.id == ResourceBlock.ID_XMP) { JempboxExtractor ex = new JempboxExtractor(metadata); ex.parse(new ByteArrayInputStream(rb.data)); } blocks++; } XHTMLContentHandler xhtml = new XHTMLContentHandler(handler, metadata); xhtml.startDocument(); xhtml.endDocument(); }  Set<MediaType> getSupportedTypes(ParseContext context); void parse(
            InputStream stream, ContentHandler handler,
            Metadata metadata, ParseContext context);  }
@Test public void testPSD() throws Exception { Metadata metadata = new Metadata(); metadata.set(Metadata.CONTENT_TYPE, "image/x-psd"); try (InputStream stream = getClass().getResourceAsStream("/test-documents/testPSD.psd")) { parser.parse(stream, new DefaultHandler(), metadata, new ParseContext()); } assertEquals("537", metadata.get(Metadata.IMAGE_WIDTH)); assertEquals("51", metadata.get(Metadata.IMAGE_LENGTH)); assertEquals("8", metadata.get(Metadata.BITS_PER_SAMPLE)); }
@Test public void testOddPSD() throws Exception { Metadata metadata = new Metadata(); metadata.set(Metadata.CONTENT_TYPE, "image/x-psd"); try (InputStream stream = getClass().getResourceAsStream("/test-documents/testPSD2.psd")) { parser.parse(stream, new DefaultHandler(), metadata, new ParseContext()); } assertEquals("69", metadata.get(Metadata.IMAGE_WIDTH)); assertEquals("70", metadata.get(Metadata.IMAGE_LENGTH)); assertEquals("8", metadata.get(Metadata.BITS_PER_SAMPLE)); }