Package com.scriptographer.adm

Source Code of com.scriptographer.adm.Image

/*
* Scriptographer
*
* This file is part of Scriptographer, a Scripting Plugin for Adobe Illustrator
* http://scriptographer.org/
*
* Copyright (c) 2002-2010, Juerg Lehni
* http://scratchdisk.com/
*
* All rights reserved. See LICENSE file for details.
*
* File created on 29.12.2004.
*/

package com.scriptographer.adm;

import java.awt.Container;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.ImageProducer;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import com.scriptographer.ai.Raster;
import com.scriptographer.ui.NativeObject;

/**
* @author lehni
*/
public class Image extends NativeObject {
  // an image can wrap its representation as an icon as well...
  private int iconHandle = 0;
 
  private int width;
  private int height;
  private ImageType type;
  // these variables are set from nativeCreate
  private int byteWidth;
  private int bitsPerPixel;
 
  private Drawer drawer;

  public Image(int width, int height, ImageType type) {
    this.width = width;
    this.height = height;
    this.type = type != null ? type : ImageType.RGB;
    handle = nativeCreate(width, height, type.value);
  }
 
  public Object clone() {
    Image copy = new Image(width, height, type);
    copy.nativeSetPixels(handle, byteWidth * height);
    return copy;
  }

  public static Image getImage(Object obj) throws IOException {
    if (obj instanceof Image)
      return (Image) obj;
    else if (obj instanceof String)
      return new Image((String) obj);
    else if (obj instanceof File)
      return new Image((File) obj);
    else if (obj instanceof URL)
      return new Image((URL) obj);
    else
      return null;
  }
 
  public Image(java.awt.Image image) {
    BufferedImage buf;
    if (image instanceof BufferedImage) {
      buf = (BufferedImage) image;
      width = buf.getWidth();
      height = buf.getHeight();
      int imgType = buf.getType();
      switch(imgType) {
        // direct types:
        case BufferedImage.TYPE_INT_RGB:
          type = ImageType.RGB;
          break;
        case BufferedImage.TYPE_INT_ARGB:
        case BufferedImage.TYPE_INT_ARGB_PRE:
          type = ImageType.ARGB;
          break;

        // indirect types, copying is needed:
        case BufferedImage.TYPE_4BYTE_ABGR:
        case BufferedImage.TYPE_4BYTE_ABGR_PRE:
        case BufferedImage.TYPE_BYTE_INDEXED: {
          BufferedImage tmp = new BufferedImage(width, height,
              BufferedImage.TYPE_INT_ARGB);
          tmp.createGraphics().drawImage(buf, null, 0, 0);
          image = tmp;
          type = ImageType.ARGB;
        }
        break;
        default: {
          BufferedImage tmp = new BufferedImage(width, height,
              BufferedImage.TYPE_INT_ARGB);
          tmp.createGraphics().drawImage(buf, null, 0, 0);
          buf = tmp;
          type = ImageType.ARGB;
        }
      }
    } else {
      width = image.getWidth(null);
      height = image.getHeight(null);
      buf = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
      buf.getGraphics().drawImage(image, 0, 0, null);
      type = ImageType.ARGB;
    }
    handle = nativeCreate(width, height, type.value);
    DataBufferInt buffer = (DataBufferInt) buf.getRaster().getDataBuffer();
    int data[] = buffer.getData();
    nativeSetPixels(data, width, height, byteWidth);
  }
 
  public Image(Raster raster) {
    // TODO: handle this case directly, without converting back and from
    // a java BufferedImage, through native code in Raster (the oposite
    // of the Raster(ui.Image image);
    this(raster.getImage());
  }

  // TODO: ImageIO (or sun graphics) on OS X have a bug with the headless mode.
  // some images cannot be used and throw a HeadlessException when used, others
  // work just fine. The workaround is to rely on the toolkit function.
  // The resolution is to use helma's image object and generator mechanism here
  // too:
  public Image(File file) throws IOException {
//    this(checkImage(ImageIO.read(file), file));
    this(checkImage(waitForImage(Toolkit.getDefaultToolkit().createImage(
        file.getPath())), file));
  }

  public Image(ImageProducer producer) throws IOException {
    this(checkImage(waitForImage(Toolkit.getDefaultToolkit().createImage(
        producer)), producer));
  }

  public Image(URL url) throws IOException {
//    this(checkImage(ImageIO.read(url), url));
    this(checkImage(waitForImage(Toolkit.getDefaultToolkit().createImage(
        url)), url));
  }

  public Image(String str) throws IOException {
    this(getURL(str));
  }
 
  public Image(InputStream in) throws IOException {
//    this(checkImage(ImageIO.read(in), in));
    this(checkImage(waitForImage(Toolkit.getDefaultToolkit().createImage(
        getBytes(in))), in));
  }

  private static java.awt.Image checkImage(java.awt.Image image, Object srcObj)
      throws IOException {
    if (image == null)
      throw new IOException("The specified image could not be read: "
          + srcObj);
    return image;
  }

  public static java.awt.Image waitForImage(java.awt.Image image) {
    MediaTracker mediaTracker = new MediaTracker(new Container());
    mediaTracker.addImage(image, 0);
    try {
      mediaTracker.waitForID(0);
      if (image.getWidth(null) == -1 || image.getHeight(null) == -1)
        image = null;
    } catch (InterruptedException e) {
      image = null;
    }
    return image;
  }
 
  private static byte[] getBytes(InputStream in) throws IOException {
    if (in == null)
      throw new IOException("InputStream is null");
    byte bytes[] = new byte[in.available()];
    in.read(bytes);
    return bytes;
  }

  private static URL getURL(String str) throws IOException {
    // the string could either be an url or a local filename, let's try
    // both:
    URL url = null;
    try {
      url = new URL(str);
    } catch (MalformedURLException e) {
      // try the local file now:
      // url = new URL("file://" + str);
      url = new File(str).toURI().toURL();
    }
    return url;
  }

  public int getCompatibleType() {
    switch(type) {
    case ARGB:
    case ASCREEN:
      return BufferedImage.TYPE_INT_ARGB;
    default:
      return BufferedImage.TYPE_INT_RGB;
    }
  }

  /**
   * fetches the pixels from the image and creates a BufferedImage from it
   */
  public BufferedImage getImage() {
    BufferedImage img =
        new BufferedImage(width, height, getCompatibleType());
    DataBufferInt buffer = (DataBufferInt) img.getRaster().getDataBuffer();
    int data[] = buffer.getData();
    nativeGetPixels(data, width, height, byteWidth);
    return img;
  }
 
  public void setImage(BufferedImage image) {
    int imgType = getCompatibleType();
    if (image.getType() != imgType || image.getWidth() != width ||
        image.getHeight() != height) {
      BufferedImage tmp = new BufferedImage(width, height, imgType);
      tmp.createGraphics().drawImage(image, 0, 0, null);
      image = tmp;
    }
    DataBufferInt buffer =
        (DataBufferInt) image.getRaster().getDataBuffer();
    int data[] = buffer.getData();
    nativeSetPixels(data, width, height, byteWidth);
  }
 
  public int getWidth() {
    return width;
  }
 
  public int getHeight() {
    return height;
  }

  public Size getSize() {
    return new Size(width, height);
  }
 
  public int getByteWidth() {
    return byteWidth;
  }
 
  public int getBitsPerPixel() {
    return bitsPerPixel;
  }
 
  public int getIconHandle() {
    if (iconHandle == 0)
      iconHandle = nativeCreateIcon();
    return iconHandle;
  }
 
  /*
   * This is pretty stupid: ADM seems to take care of destruction of attached
   * pictures itself (for list entries and dialog items). Therefore one
   * image cannot be attached to more than on item or entry, otherwise it
   * would be deleted several times. so in order to create an image to attach
   * it somewhere, a new instance of the image needs to be created everytime,
   * and an icon needs to be created as well. We don't have to take care of
   * the disposal, as the item or entry seems to do so.
   *
   * TODO: workaround: handle images in the DrawProc, adjust entryTextRects
   * accordingly and don't use the native setImage methods at all... some more
   * work with the Tracker would be needed in order to emulate rollover
   * behavior. But it may be worth geting around the memory consumption of
   * this dirty hack here...
   */
  public int createIconHandle() {
    Image img = ((Image) clone());
    int handle = img.nativeCreateIcon();
    // clear the handle so that nothing happens in finalize or destroy!
    img.handle = 0;
    img.iconHandle = 0;
    return handle;
  }
 
  public Drawer getDrawer() {
    if (drawer == null)
      drawer = new Drawer(nativeBeginDrawer(), this, false);
    return drawer;
  }
 
  public void dispose() {
    if (handle != 0) {
      if (drawer != null) {
        drawer.dispose();
        drawer = null;
      }
      nativeDestroy(handle, iconHandle);
      handle = 0;
      iconHandle = 0;
    }
  }
 
  public void finalize() {
    dispose();
  }
 
  /**
   * called by Drawer.dispose
   */
  protected void endDrawer() {
    if (drawer != null) {
      nativeEndDrawer();
      drawer = null;
    }
  }

  private native int nativeCreate(int width, int height, int type);

  private native void nativeDestroy(int handle, int iconHandle);

  private native void nativeSetPixels(int[] data, int width, int height,
      int byteWidth);

  private native void nativeGetPixels(int[] data, int width, int height,
      int byteWidth);

  private native void nativeSetPixels(int handle, int numBytes);

  private native int nativeCreateIcon();

  private native int nativeBeginDrawer();

  private native void nativeEndDrawer();
}
TOP

Related Classes of com.scriptographer.adm.Image

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.