Decodes a PhotoShop (.psd) file into one or more frames : Psd « 2D Graphics GUI « Java

Home
Java
1.2D Graphics GUI
2.2D Graphics GUI1
3.3D
4.Advanced Graphics
5.Ant
6.Apache Common
7.Chart
8.Class
9.Collections Data Structure
10.Data Type
11.Database SQL JDBC
12.Design Pattern
13.Development Class
14.EJB3
15.Email
16.Event
17.File Input Output
18.Game
19.Generics
20.GWT
21.Hibernate
22.I18N
23.J2EE
24.J2ME
25.JDK 6
26.JNDI LDAP
27.JPA
28.JSP
29.JSTL
30.Language Basics
31.Network Protocol
32.PDF RTF
33.Reflection
34.Regular Expressions
35.Scripting
36.Security
37.Servlets
38.Spring
39.Swing Components
40.Swing JFC
41.SWT JFace Eclipse
42.Threads
43.Tiny Application
44.Velocity
45.Web Services SOA
46.XML
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
SCJP
Java » 2D Graphics GUI » PsdScreenshots 
Decodes a PhotoShop (.psd) file into one or more frames

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

/**
 * Class PSDReader - Decodes a PhotoShop (.psd) file into one or more frames.
 * Supports uncompressed or RLE-compressed RGB files only. Each layer may be
 * retrieved as a full frame BufferedImage, or as a smaller image with an offset
 * if the layer does not occupy the full frame size. Transparency in the
 * original psd file is preserved in the returned BufferedImage's. Does not
 * support additional features in PS versions higher than 3.0. Example: <br>
 
 * <pre>
 * PSDReader r = new PSDReader();
 * r.read(&quot;sample.psd&quot;);
 * int n = r.getFrameCount();
 * for (int i = 0; i &lt; n; i++) {
 *   BufferedImage image = r.getLayer(i);
 *   Point offset = r.getLayerOffset(i);
 *   // do something with image
 * }
 * </pre>
 
 * No copyright asserted on the source code of this class. May be used for any
 * purpose. Please forward any corrections to kweiner@fmsware.com.
 
 @author Kevin Weiner, FM Software.
 @version 1.1 January 2004 [bug fix; add RLE support]
 
 */
public class PSDReader {

  /**
   * File read status: No errors.
   */
  public static final int STATUS_OK = 0;

  /**
   * File read status: Error decoding file (may be partially decoded)
   */
  public static final int STATUS_FORMAT_ERROR = 1;

  /**
   * File read status: Unable to open source.
   */
  public static final int STATUS_OPEN_ERROR = 2;

  /**
   * File read status: Unsupported format
   */
  public static final int STATUS_UNSUPPORTED = 3;

  public static int ImageType = BufferedImage.TYPE_INT_ARGB;

  protected BufferedInputStream input;

  protected int frameCount;

  protected BufferedImage[] frames;

  protected int status = 0;

  protected int nChan;

  protected int width;

  protected int height;

  protected int nLayers;

  protected int miscLen;

  protected boolean hasLayers;

  protected LayerInfo[] layers;

  protected short[] lineLengths;

  protected int lineIndex;

  protected boolean rleEncoded;

  protected class LayerInfo {
    int x, y, w, h;

    int nChan;

    int[] chanID;

    int alpha;
  }

  /**
   * Gets the number of layers read from file.
   
   @return frame count
   */
  public int getFrameCount() {
    return frameCount;
  }

  protected void setInput(InputStream stream) {
    // open input stream
    init();
    if (stream == null) {
      status = STATUS_OPEN_ERROR;
    else {
      if (stream instanceof BufferedInputStream)
        input = (BufferedInputStreamstream;
      else
        input = new BufferedInputStream(stream);
    }
  }

  protected void setInput(String name) {
    // open input file
    init();
    try {
      name = name.trim();
      if (name.startsWith("file:")) {
        name = name.substring(5);
        while (name.startsWith("/"))
          name = name.substring(1);
      }
      if (name.indexOf("://"0) {
        URL url = new URL(name);
        input = new BufferedInputStream(url.openStream());
      else {
        input = new BufferedInputStream(new FileInputStream(name));
      }
    catch (IOException e) {
      status = STATUS_OPEN_ERROR;
    }
  }

  /**
   * Gets display duration for specified frame. Always returns 0.
   
   */
  public int getDelay(int forFrame) {
    return 0;
  }

  /**
   * Gets the image contents of frame n. Note that this expands the image to the
   * full frame size (if the layer was smaller) and any subsequent use of
   * getLayer() will return the full image.
   
   @return BufferedImage representation of frame, or null if n is invalid.
   */
  public BufferedImage getFrame(int n) {
    BufferedImage im = null;
    if ((n >= 0&& (n < nLayers)) {
      im = frames[n];
      LayerInfo info = layers[n];
      if ((info.w != width|| (info.h != height)) {
        BufferedImage temp = new BufferedImage(width, height, ImageType);
        Graphics2D gc = temp.createGraphics();
        gc.drawImage(im, info.x, info.y, null);
        gc.dispose();
        im = temp;
        frames[n= im;
      }
    }
    return im;
  }

  /**
   * Gets maximum image size. Individual layers may be smaller.
   
   @return maximum image dimensions
   */
  public Dimension getFrameSize() {
    return new Dimension(width, height);
  }

  /**
   * Gets the first (or only) image read.
   
   @return BufferedImage containing first frame, or null if none.
   */
  public BufferedImage getImage() {
    return getFrame(0);
  }

  /**
   * Gets the image contents of layer n. May be smaller than full frame size -
   * use getFrameOffset() to obtain position of subimage within main image area.
   
   @return BufferedImage representation of layer, or null if n is invalid.
   */
  public BufferedImage getLayer(int n) {
    BufferedImage im = null;
    if ((n >= 0&& (n < nLayers)) {
      im = frames[n];
    }
    return im;
  }

  /**
   * Gets the subimage offset of layer n if it is smaller than the full frame
   * size.
   
   @return Point indicating offset from upper left corner of frame.
   */
  public Point getLayerOffset(int n) {
    Point p = null;
    if ((n >= 0&& (n < nLayers)) {
      int x = layers[n].x;
      int y = layers[n].y;
      p = new Point(x, y);
    }
    if (p == null) {
      p = new Point(00);
    }
    return p;
  }

  /**
   * Reads PhotoShop layers from stream.
   
   @param InputStream
   *          in PhotoShop format.
   @return read status code (0 = no errors)
   */
  public int read(InputStream stream) {
    setInput(stream);
    process();
    return status;
  }

  /**
   * Reads PhotoShop file from specified source (file or URL string)
   
   @param name
   *          String containing source
   @return read status code (0 = no errors)
   */
  public int read(String name) {
    setInput(name);
    process();
    return status;
  }

  /**
   * Closes input stream and discards contents of all frames.
   
   */
  public void reset() {
    init();
  }

  protected void close() {
    if (input != null) {
      try {
        input.close();
      catch (Exception e) {
      }
      input = null;
    }
  }

  protected boolean err() {
    return status != STATUS_OK;
  }

  protected byte[] fillBytes(int size, int value) {
    // create byte array filled with given value
    byte[] b = new byte[size];
    if (value != 0) {
      byte v = (bytevalue;
      for (int i = 0; i < size; i++) {
        b[i= v;
      }
    }
    return b;
  }

  protected void init() {
    close();
    frameCount = 0;
    frames = null;
    layers = null;
    hasLayers = true;
    status = STATUS_OK;
  }

  protected void makeDummyLayer() {
    // creat dummy layer for non-layered image
    rleEncoded = readShort() == 1;
    hasLayers = false;
    nLayers = 1;
    layers = new LayerInfo[1];
    LayerInfo layer = new LayerInfo();
    layers[0= layer;
    layer.h = height;
    layer.w = width;
    int nc = Math.min(nChan, 4);
    if (rleEncoded) {
      // get list of rle encoded line lengths for all channels
      readLineLengths(height * nc);
    }
    layer.nChan = nc;
    layer.chanID = new int[nc];
    for (int i = 0; i < nc; i++) {
      int id = i;
      if (i == 3)
        id = -1;
      layer.chanID[i= id;
    }
  }

  protected void readLineLengths(int nLines) {
    // read list of rle encoded line lengths
    lineLengths = new short[nLines];
    for (int i = 0; i < nLines; i++) {
      lineLengths[i= readShort();
    }
    lineIndex = 0;
  }

  protected BufferedImage makeImage(int w, int h, byte[] r, byte[] g, byte[] b, byte[] a) {
    // create image from given plane data
    BufferedImage im = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    int[] data = ((DataBufferIntim.getRaster().getDataBuffer()).getData();
    int n = w * h;
    int j = 0;
    while (j < n) {
      try {
        int ac = a[j0xff;
        int rc = r[j0xff;
        int gc = g[j0xff;
        int bc = b[j0xff;
        data[j(((((ac << 8| rc<< 8| gc<< 8| bc;
      catch (Exception e) {
      }
      j++;
    }
    return im;
  }

  protected void process() {
    // decode PSD file
    if (err())
      return;
    readHeader();
    if (err())
      return;
    readLayerInfo();
    if (err())
      return;
    if (nLayers == 0) {
      makeDummyLayer();
      if (err())
        return;
    }
    readLayers();
  }

  protected int readByte() {
    // read single byte from input
    int curByte = 0;
    try {
      curByte = input.read();
    catch (IOException e) {
      status = STATUS_FORMAT_ERROR;
    }
    return curByte;
  }

  protected int readBytes(byte[] bytes, int n) {
    // read multiple bytes from input
    if (bytes == null)
      return 0;
    int r = 0;
    try {
      r = input.read(bytes, 0, n);
    catch (IOException e) {
      status = STATUS_FORMAT_ERROR;
    }
    if (r < n) {
      status = STATUS_FORMAT_ERROR;
    }
    return r;
  }

  protected void readHeader() {
    // read PSD header info
    String sig = readString(4);
    int ver = readShort();
    skipBytes(6);
    nChan = readShort();
    height = readInt();
    width = readInt();
    int depth = readShort();
    int mode = readShort();
    int cmLen = readInt();
    skipBytes(cmLen);
    int imResLen = readInt();
    skipBytes(imResLen);

    // require 8-bit RGB data
    if ((!sig.equals("8BPS")) || (ver != 1)) {
      status = STATUS_FORMAT_ERROR;
    else if ((depth != 8|| (mode != 3)) {
      status = STATUS_UNSUPPORTED;
    }
  }

  protected int readInt() {
    // read big-endian 32-bit integer
    return (((((readByte() << 8| readByte()) << 8| readByte()) << 8| readByte();
  }

  protected void readLayerInfo() {
    // read layer header info
    miscLen = readInt();
    if (miscLen == 0) {
      return// no layers, only base image
    }
    int layerInfoLen = readInt();
    nLayers = readShort();
    if (nLayers > 0) {
      layers = new LayerInfo[nLayers];
    }
    for (int i = 0; i < nLayers; i++) {
      LayerInfo info = new LayerInfo();
      layers[i= info;
      info.y = readInt();
      info.x = readInt();
      info.h = readInt() - info.y;
      info.w = readInt() - info.x;
      info.nChan = readShort();
      info.chanID = new int[info.nChan];
      for (int j = 0; j < info.nChan; j++) {
        int id = readShort();
        int size = readInt();
        info.chanID[j= id;
      }
      String s = readString(4);
      if (!s.equals("8BIM")) {
        status = STATUS_FORMAT_ERROR;
        return;
      }
      skipBytes(4)// blend mode
      info.alpha = readByte();
      int clipping = readByte();
      int flags = readByte();
      readByte()// filler
      int extraSize = readInt();
      skipBytes(extraSize);
    }
  }

  protected void readLayers() {
    // read and convert each layer to BufferedImage
    frameCount = nLayers;
    frames = new BufferedImage[nLayers];
    for (int i = 0; i < nLayers; i++) {
      LayerInfo info = layers[i];
      byte[] r = null, g = null, b = null, a = null;
      for (int j = 0; j < info.nChan; j++) {
        int id = info.chanID[j];
        switch (id) {
        case 0:
          r = readPlane(info.w, info.h);
          break;
        case 1:
          g = readPlane(info.w, info.h);
          break;
        case 2:
          b = readPlane(info.w, info.h);
          break;
        case -1:
          a = readPlane(info.w, info.h);
          break;
        default:
          readPlane(info.w, info.h);
        }
        if (err())
          break;
      }
      if (err())
        break;
      int n = info.w * info.h;
      if (r == null)
        r = fillBytes(n, 0);
      if (g == null)
        g = fillBytes(n, 0);
      if (b == null)
        b = fillBytes(n, 0);
      if (a == null)
        a = fillBytes(n, 255);

      BufferedImage im = makeImage(info.w, info.h, r, g, b, a);
      frames[i= im;
    }
    lineLengths = null;
    if ((miscLen > 0&& !err()) {
      int n = readInt()// global layer mask info len
      skipBytes(n);
    }
  }

  protected byte[] readPlane(int w, int h) {
    // read a single color plane
    byte[] b = null;
    int size = w * h;
    if (hasLayers) {
      // get RLE compression info for channel
      rleEncoded = readShort() == 1;
      if (rleEncoded) {
        // list of encoded line lengths
        readLineLengths(h);
      }
    }

    if (rleEncoded) {
      b = readPlaneCompressed(w, h);
    else {
      b = new byte[size];
      readBytes(b, size);
    }

    return b;

  }

  protected byte[] readPlaneCompressed(int w, int h) {
    byte[] b = new byte[w * h];
    byte[] s = new byte[w * 2];
    int pos = 0;
    for (int i = 0; i < h; i++) {
      if (lineIndex >= lineLengths.length) {
        status = STATUS_FORMAT_ERROR;
        return null;
      }
      int len = lineLengths[lineIndex++];
      readBytes(s, len);
      decodeRLE(s, 0, len, b, pos);
      pos += w;
    }
    return b;
  }

  protected void decodeRLE(byte[] src, int sindex, int slen, byte[] dst, int dindex) {
    try {
      int max = sindex + slen;
      while (sindex < max) {
        byte b = src[sindex++];
        int n = (intb;
        if (n < 0) {
          // dup next byte 1-n times
          n = - n;
          b = src[sindex++];
          for (int i = 0; i < n; i++) {
            dst[dindex++= b;
          }
        else {
          // copy next n+1 bytes
          n = n + 1;
          System.arraycopy(src, sindex, dst, dindex, n);
          dindex += n;
          sindex += n;
        }
      }
    catch (Exception e) {
      status = STATUS_FORMAT_ERROR;
    }
  }

  protected short readShort() {
    // read big-endian 16-bit integer
    return (short) ((readByte() << 8| readByte());
  }

  protected String readString(int len) {
    // read string of specified length
    String s = "";
    for (int i = 0; i < len; i++) {
      s = s + (charreadByte();
    }
    return s;
  }

  protected void skipBytes(int n) {
    // skip over n input bytes
    for (int i = 0; i < n; i++) {
      readByte();
    }
  }
}

           
       
Related examples in the same category
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.