/*******************************************************************************
* Copyright (c) 2002, 2010 Innoopract Informationssysteme GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Innoopract Informationssysteme GmbH - initial API and implementation
* EclipseSource - ongoing development
******************************************************************************/
package org.eclipse.swt.graphics;
import java.io.*;
import org.eclipse.rwt.RWT;
import org.eclipse.rwt.resources.IResourceManager;
import org.eclipse.swt.*;
import org.eclipse.swt.internal.graphics.ResourceFactory;
/**
* Instances of this class are graphics which have been prepared
* for display on a specific device. That is, they are to display
* on widgets with, for example, <code>Button.setImage()</code>.
*
* <p>If loaded from a file format that supports it, an
* <code>Image</code> may have transparency, meaning that certain
* pixels are specified as being transparent when drawn. Examples
* of file formats that support transparency are GIF and PNG.</p>
*
* <p><strong>Note:</strong> Even though constructors are provided here, it is
* recommended to create images by using one of the <code>getImage</code>
* methods in class <code>Graphics</code>. These factory methods share images
* among all sessions.
* Creating images via constructors carelessly may lead to bad performance
* and/or unnecessary memory consumption.
* </p>
*
* @see org.eclipse.rwt.graphics.Graphics#getImage(String)
* @see org.eclipse.rwt.graphics.Graphics#getImage(String, ClassLoader)
* @see org.eclipse.rwt.graphics.Graphics#getImage(String, java.io.InputStream)
*/
public final class Image extends Resource {
/**
* <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
* public API. It is marked public only so that it can be shared
* within the packages provided by SWT. It is not available on all
* platforms and should never be accessed from application code.
*/
public String resourceName;
private int width;
private int height;
/* This constructor is called by ResourceFactory#createImage() */
private Image( final String resourceName, final int width, final int height )
{
super( null );
this.resourceName = resourceName;
this.width = width;
this.height = height;
}
/**
* Constructs an instance of this class by loading its representation
* from the specified input stream. Throws an error if an error
* occurs while loading the image, or if the result is an image
* of an unsupported type. Application code is still responsible
* for closing the input stream.
* <p>
* This constructor is provided for convenience when loading a single
* image only. If the stream contains multiple images, only the first
* one will be loaded. To load multiple images, use
* <code>ImageLoader.load()</code>.
* </p><p>
* This constructor may be used to load a resource as follows:
* </p>
* <pre>
* static Image loadImage (Display display, Class clazz, String string) {
* InputStream stream = clazz.getResourceAsStream (string);
* if (stream == null) return null;
* Image image = null;
* try {
* image = new Image (display, stream);
* } catch (SWTException ex) {
* } finally {
* try {
* stream.close ();
* } catch (IOException ex) {}
* }
* return image;
* }
* </pre>
*
* <p><strong>Note</strong>, this constructor is provided for convenience when
* single-sourcing code with SWT. For RWT, the recommended way to create images
* is to use one of the <code>Graphics#getImage()</code> methods.
* </p>
*
* @param device the device on which to create the image
* @param stream the input stream to load the image from
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
* <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
* <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data </li>
* <li>ERROR_UNSUPPORTED_DEPTH - if the image stream describes an image with an unsupported depth</li>
* <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
* </ul>
* @exception SWTError <ul>
* <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
* </ul>
* @see org.eclipse.rwt.graphics.Graphics#getImage(String)
* @see org.eclipse.rwt.graphics.Graphics#getImage(String, ClassLoader)
* @see org.eclipse.rwt.graphics.Graphics#getImage(String, java.io.InputStream)
* @since 1.3
*/
public Image( final Device device, final InputStream stream ) {
super( checkDevice( device ) );
if( stream == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
init( stream );
}
/**
* Constructs an instance of this class by loading its representation
* from the file with the specified name. Throws an error if an error
* occurs while loading the image, or if the result is an image
* of an unsupported type.
* <p>
* This constructor is provided for convenience when loading
* a single image only. If the specified file contains
* multiple images, only the first one will be used.
*
* <p><strong>Note</strong>, this constructor is provided for convenience when
* single-sourcing code with SWT. For RWT, the recommended way to create images
* is to use one of the <code>Graphics#getImage()</code> methods.
* </p>
*
* @param device the device on which to create the image
* @param filename the name of the file to load the image from
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
* <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_IO - if an IO error occurs while reading from the file</li>
* <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li>
* <li>ERROR_UNSUPPORTED_DEPTH - if the image file describes an image with an unsupported depth</li>
* <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
* </ul>
* @exception SWTError <ul>
* <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
* </ul>
* @see org.eclipse.rwt.graphics.Graphics#getImage(String)
* @see org.eclipse.rwt.graphics.Graphics#getImage(String, ClassLoader)
* @see org.eclipse.rwt.graphics.Graphics#getImage(String, java.io.InputStream)
* @since 1.3
*/
public Image( final Device device, final String fileName ) {
super( checkDevice( device ) );
if( fileName == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
init( fileName );
}
/**
* Constructs a new instance of this class based on the
* provided image, with an appearance that varies depending
* on the value of the flag. The possible flag values are:
* <dl>
* <dt><b>{@link SWT#IMAGE_COPY}</b></dt>
* <dd>the result is an identical copy of srcImage</dd>
* <dt><b>{@link SWT#IMAGE_DISABLE}</b></dt>
* <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd>
* <dt><b>{@link SWT#IMAGE_GRAY}</b></dt>
* <dd>the result is a copy of srcImage which has a <em>gray scale</em> look</dd>
* </dl>
*
* @param device the device on which to create the image
* @param srcImage the image to use as the source
* @param flag the style, either <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code>
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
* <li>ERROR_NULL_ARGUMENT - if srcImage is null</li>
* <li>ERROR_INVALID_ARGUMENT - if the flag is not one of <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code></li>
* <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon, or is otherwise in an invalid state</li>
* <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the image is not supported</li>
* </ul>
* @exception SWTError <ul>
* <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
* </ul>
* @since 1.3
*/
public Image( final Device device, final Image srcImage, final int flag ) {
super( checkDevice( device ) );
if( srcImage == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( srcImage.isDisposed() ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
switch( flag ) {
case SWT.IMAGE_COPY:
IResourceManager resourceManager = RWT.getResourceManager();
InputStream content
= resourceManager.getRegisteredContent( srcImage.resourceName );
init( content );
break;
default:
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
break;
}
}
/**
* Constructs an instance of this class from the given
* <code>ImageData</code>.
*
* @param device the device on which to create the image
* @param data the image data to create the image from (must not be null)
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
* <li>ERROR_NULL_ARGUMENT - if the image data is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the ImageData is not supported</li>
* </ul>
* </ul>
* @since 1.3
*/
public Image( final Device device, final ImageData imageData ) {
super( checkDevice( device ) );
if( imageData == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
init( imageData );
}
private void init( final String fileName ) {
try {
FileInputStream stream = new FileInputStream( fileName );
try {
init( stream );
} finally {
stream.close();
}
} catch( IOException e ) {
throw new SWTException( SWT.ERROR_IO, e.getMessage() );
}
}
private void init( final InputStream stream ) {
resourceName = "image-" + String.valueOf( hashCode() );
Point size = ResourceFactory.registerImage( resourceName, stream );
if( size == null ) {
throw new SWTException( SWT.ERROR_UNSUPPORTED_FORMAT );
}
width = size.x;
height = size.y;
}
private void init( final ImageData imageData ) {
resourceName = "image-" + String.valueOf( hashCode() );
ImageLoader imageLoader = new ImageLoader();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
imageLoader.data = new ImageData[] { imageData };
imageLoader.save( outputStream, imageData.type );
byte[] bytes = outputStream.toByteArray();
InputStream inputStream = new ByteArrayInputStream( bytes );
Point size = ResourceFactory.registerImage( resourceName, inputStream );
width = size.x;
height = size.y;
}
///////////////////////
// Public Image methods
/**
* Returns the bounds of the receiver. The rectangle will always
* have x and y values of 0, and the width and height of the
* image.
*
* @return a rectangle specifying the image's bounds
*
* @exception SWTException <ul>
* <!-- <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> -->
* <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
* </ul>
*/
public Rectangle getBounds() {
Rectangle result = null;
if( isDisposed() ) {
SWT.error( SWT.ERROR_GRAPHIC_DISPOSED );
}
if( width != -1 && height != -1 ) {
result = new Rectangle( 0, 0, width, height );
} else {
// TODO [rst] check types
SWT.error( SWT.ERROR_INVALID_IMAGE );
}
return result;
}
/**
* Returns an <code>ImageData</code> based on the receiver
* Modifications made to this <code>ImageData</code> will not
* affect the Image.
*
* @return an <code>ImageData</code> containing the image's data and attributes
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
* </ul>
*
* @see ImageData
* @since 1.3
*/
public ImageData getImageData() {
if( isDisposed() ) {
SWT.error( SWT.ERROR_GRAPHIC_DISPOSED );
}
return ResourceFactory.getImageData( this );
}
/**
* Sets the color to which to map the transparent pixel.
* <p>
* There are certain uses of <code>Images</code> that do not support
* transparency (for example, setting an image into a button or label).
* In these cases, it may be desired to simulate transparency by using
* the background color of the widget to paint the transparent pixels
* of the image. This method specifies the color that will be used in
* these cases. For example:
* <pre>
* Button b = new Button();
* image.setBackground(b.getBackground());
* b.setImage(image);
* </pre>
* </p><p>
* The image may be modified by this operation (in effect, the
* transparent regions may be filled with the supplied color). Hence
* this operation is not reversible and it is not legal to call
* this function twice or with a null argument.
* </p><p>
* This method has no effect if the receiver does not have a transparent
* pixel value.
* </p>
*
* @param color the color to use when a transparent pixel is specified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the color is null</li>
* <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
* @since 1.3
*/
public void setBackground( final Color color ) {
if( isDisposed() ) {
SWT.error( SWT.ERROR_GRAPHIC_DISPOSED );
}
if( color == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( color.isDisposed() ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
// do nothing
}
/**
* Returns the color to which to map the transparent pixel, or null if
* the receiver has no transparent pixel.
* <p>
* There are certain uses of Images that do not support transparency
* (for example, setting an image into a button or label). In these cases,
* it may be desired to simulate transparency by using the background
* color of the widget to paint the transparent pixels of the image.
* Use this method to check which color will be used in these cases
* in place of transparency. This value may be set with setBackground().
* <p>
*
* @return the background color of the image, or null if there is no
* transparency in the image
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
* @since 1.3
*/
public Color getBackground() {
if( isDisposed() ) {
SWT.error( SWT.ERROR_GRAPHIC_DISPOSED );
}
// do nothing
return null;
}
///////////
// Disposal
void destroy() {
RWT.getResourceManager().unregister( resourceName );
}
}