Java tutorial
/* * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ package javax.media.j3d; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.util.logging.Level; /** * This class defines a 2D image component. This is used for texture * images, background images and raster components of Shape3D nodes. * Prior to Java 3D 1.2, only BufferedImage objects could be used as the * input to an ImageComponent2D object. As of Java 3D 1.2, an * ImageComponent2D accepts any RenderedImage object (BufferedImage is * an implementation of the RenderedImage interface). The methods * that set/get a BufferedImage object are left in for compatibility. * The new methods that set/get a RenderedImage are a superset of the * old methods. In particular, the two set methods in the following * example are equivalent: * * <p> * <ul> * <code> * BufferedImage bi;<br> * RenderedImage ri = bi;<br> * ImageComponent2D ic;<br> * <p> * // Set the image to the specified BufferedImage<br> * ic.set(bi);<br> * <p> * // Set the image to the specified RenderedImage<br> * ic.set(ri);<br> * </code> * </ul> * * <p> * As of Java 3D 1.5, an ImageComponent2D accepts an NioImageBuffer object * as an alternative to a RenderedImage. */ public class ImageComponent2D extends ImageComponent { // non-public, no parameter constructor ImageComponent2D() { } /** * Constructs a 2D image component object using the specified * format, width, and height. Default values are used for * all other parameters. The default values are as follows: * <ul> * image : null<br> * imageClass : ImageClass.BUFFERED_IMAGE<br> * </ul> * * @param format the image component format, one of: FORMAT_RGB, * FORMAT_RGBA, etc. * @param width the number of columns of pixels in this image component * object * @param height the number of rows of pixels in this image component * object * @exception IllegalArgumentException if format is invalid, or if * width or height are not positive. */ public ImageComponent2D(int format, int width, int height) { if (MasterControl.isDevLoggable(Level.FINER)) { MasterControl.getDevLogger().finer("ImageComponent - using default of byCopy"); } ((ImageComponent2DRetained) this.retained).processParams(format, width, height, 1); } /** * Constructs a 2D image component object using the specified format * and BufferedImage. A copy of the BufferedImage is made. * The image class is set to ImageClass.BUFFERED_IMAGE. * Default values are used for all other parameters. * * @param format the image component format, one of: FORMAT_RGB, * FORMAT_RGBA, etc. * @param image the BufferedImage used to create this 2D image component. * @exception IllegalArgumentException if format is invalid, or if * the width or height of the image are not positive. */ public ImageComponent2D(int format, BufferedImage image) { if (MasterControl.isDevLoggable(Level.FINER)) { MasterControl.getDevLogger().finer("ImageComponent - using default of byCopy"); } ((ImageComponent2DRetained) this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); ((ImageComponent2DRetained) this.retained).set(image); } /** * Constructs a 2D image component object using the specified format * and RenderedImage. A copy of the RenderedImage is made. * The image class is set to ImageClass.BUFFERED_IMAGE. * Default values are used for all other parameters. * * @param format the image component format, one of: FORMAT_RGB, * FORMAT_RGBA, etc. * @param image the RenderedImage used to create this 2D image component * @exception IllegalArgumentException if format is invalid, or if * the width or height of the image are not positive. * * @since Java 3D 1.2 */ public ImageComponent2D(int format, RenderedImage image) { if (MasterControl.isDevLoggable(Level.FINER)) { MasterControl.getDevLogger().finer("ImageComponent - using default of byCopy"); } ((ImageComponent2DRetained) this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); ((ImageComponent2DRetained) this.retained).set(image); } /** * Constructs a 2D image component object using the specified * format, width, height, byReference flag, and yUp flag. * Default values are used for all other parameters. * * @param format the image component format, one of: FORMAT_RGB, * FORMAT_RGBA, etc. * @param width the number of columns of pixels in this image component * object * @param height the number of rows of pixels in this image component * object * @param byReference a flag that indicates whether the data is copied * into this image component object or is accessed by reference. * @param yUp a flag that indicates the y-orientation of this image * component. If yUp is set to true, the origin of the image is * the lower left; otherwise, the origin of the image is the upper * left. * @exception IllegalArgumentException if format is invalid, or if * width or height are not positive. * * @since Java 3D 1.2 */ public ImageComponent2D(int format, int width, int height, boolean byReference, boolean yUp) { if (MasterControl.isDevLoggable(Level.INFO)) { if (byReference && !yUp) { MasterControl.getDevLogger().info("ImageComponent - yUp should " + "be set when using byReference, " + "otherwise an extra copy of the image will be created"); } } ((ImageComponentRetained) this.retained).setByReference(byReference); ((ImageComponentRetained) this.retained).setYUp(yUp); ((ImageComponent2DRetained) this.retained).processParams(format, width, height, 1); } /** * Constructs a 2D image component object using the specified format, * BufferedImage, byReference flag, and yUp flag. * The image class is set to ImageClass.BUFFERED_IMAGE. * * @param format the image component format, one of: FORMAT_RGB, * FORMAT_RGBA, etc. * @param image the BufferedImage used to create this 2D image component * @param byReference a flag that indicates whether the data is copied * into this image component object or is accessed by reference * @param yUp a flag that indicates the y-orientation of this image * component. If yUp is set to true, the origin of the image is * the lower left; otherwise, the origin of the image is the upper * left. * @exception IllegalArgumentException if format is invalid, or if * the width or height of the image are not positive. * * @since Java 3D 1.2 */ public ImageComponent2D(int format, BufferedImage image, boolean byReference, boolean yUp) { if (MasterControl.isDevLoggable(Level.INFO)) { if (byReference && !yUp) { MasterControl.getDevLogger().info("ImageComponent - yUp should " + "be set when using byReference, " + "otherwise an extra copy of the image will be created"); } } ((ImageComponentRetained) this.retained).setByReference(byReference); ((ImageComponentRetained) this.retained).setYUp(yUp); ((ImageComponent2DRetained) this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); ((ImageComponent2DRetained) this.retained).set(image); } /** * Constructs a 2D image component object using the specified format, * RenderedImage, byReference flag, and yUp flag. * The image class is set to ImageClass.RENDERED_IMAGE if the byReferece * flag is true and the specified RenderedImage is <i>not</i> an instance * of BufferedImage. In all other cases, the image class is set to * ImageClass.BUFFERED_IMAGE. * * @param format the image component format, one of: FORMAT_RGB, * FORMAT_RGBA, etc. * @param image the RenderedImage used to create this 2D image component * @param byReference a flag that indicates whether the data is copied * into this image component object or is accessed by reference. * @param yUp a flag that indicates the y-orientation of this image * component. If yUp is set to true, the origin of the image is * the lower left; otherwise, the origin of the image is the upper * left. * @exception IllegalArgumentException if format is invalid, or if * the width or height of the image are not positive. * * @since Java 3D 1.2 */ public ImageComponent2D(int format, RenderedImage image, boolean byReference, boolean yUp) { if (MasterControl.isDevLoggable(Level.INFO)) { if (byReference && !yUp) MasterControl.getDevLogger().info("ImageComponent - yUp should " + "be set when using byReference, " + "otherwise an extra copy of the image will be created"); } ((ImageComponentRetained) this.retained).setByReference(byReference); ((ImageComponentRetained) this.retained).setYUp(yUp); ((ImageComponent2DRetained) this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); ((ImageComponent2DRetained) this.retained).set(image); } /** * Constructs a 2D image component object using the specified format, * NioImageBuffer, byReference flag, and yUp flag. * The image class is set to ImageClass.NIO_IMAGE_BUFFER. * * @param format the image component format, one of: FORMAT_RGB, * FORMAT_RGBA, etc. * @param image the NioImageBuffer used to create this 2D image component * @param byReference a flag that indicates whether the data is copied * into this image component object or is accessed by reference. * @param yUp a flag that indicates the y-orientation of this image * component. If yUp is set to true, the origin of the image is * the lower left; otherwise, the origin of the image is the upper * left. * * @exception IllegalArgumentException if format is invalid, or if * the width or height of the image are not positive. * * @exception IllegalArgumentException if the byReference flag is false. * * @exception IllegalArgumentException if the yUp flag is false. * * @exception IllegalArgumentException if the number of components in format * does not match the number of components in image. * * @since Java 3D 1.5 */ public ImageComponent2D(int format, NioImageBuffer image, boolean byReference, boolean yUp) { ((ImageComponentRetained) this.retained).setByReference(byReference); ((ImageComponentRetained) this.retained).setYUp(yUp); ((ImageComponent2DRetained) this.retained).processParams(format, image.getWidth(), image.getHeight(), 1); ((ImageComponent2DRetained) this.retained).set(image); } /** * Sets this image component to the specified BufferedImage * object. * If the data access mode is not by-reference, then the * BufferedImage data is copied into this object. If * the data access mode is by-reference, then a reference to the * BufferedImage is saved, but the data is not necessarily * copied. * <p> * The image class is set to ImageClass.BUFFERED_IMAGE. * * @param image BufferedImage object containing the image. * Its size must be the same as the current size of this * ImageComponent2D object. * * @exception CapabilityNotSetException if appropriate capability is * not set and this object is part of live or compiled scene graph * * @exception IllegalArgumentException if the width and height of the * specified image is not equal to the width and height of this * ImageComponent object. */ public void set(BufferedImage image) { if (isLiveOrCompiled()) { if (!this.getCapability(ALLOW_IMAGE_WRITE)) throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D1")); } ((ImageComponent2DRetained) this.retained).set(image); } /** * Sets this image component to the specified RenderedImage * object. If the data access mode is not by-reference, the * RenderedImage data is copied into this object. If * the data access mode is by-reference, a reference to the * RenderedImage is saved, but the data is not necessarily * copied. * <p> * The image class is set to ImageClass.RENDERED_IMAGE if the the * data access mode is by-reference and the specified * RenderedImage is <i>not</i> an instance of BufferedImage. In all * other cases, the image class is set to ImageClass.BUFFERED_IMAGE. * * @param image RenderedImage object containing the image. * Its size must be the same as the current size of this * ImageComponent2D object. * * @exception CapabilityNotSetException if appropriate capability is * not set and this object is part of live or compiled scene graph * * @exception IllegalArgumentException if the width and height of the * specified image is not equal to the width and height of this * ImageComponent object. * * @since Java 3D 1.2 */ public void set(RenderedImage image) { if (isLiveOrCompiled()) { if (!this.getCapability(ALLOW_IMAGE_WRITE)) throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D1")); } ((ImageComponent2DRetained) this.retained).set(image); } /** * Sets this image component to the specified NioImageBuffer * object. If the data access mode is not by-reference, the * NioImageBuffer data is copied into this object. If * the data access mode is by-reference, a reference to the * NioImageBuffer is saved, but the data is not necessarily * copied. * <p> * The image class is set to ImageClass.NIO_IMAGE_BUFFER. * * @param image NioImageBuffer object containing the image. * Its size must be the same as the current size of this * ImageComponent2D object. * * @exception CapabilityNotSetException if appropriate capability is * not set and this object is part of live or compiled scene graph * * @exception IllegalStateException if this ImageComponent object * is <i>not</i> yUp. * * @exception IllegalArgumentException if the width and height of the * specified image is not equal to the width and height of this * ImageComponent object. * * @exception IllegalArgumentException if the number of components in format * does not match the number of components in image. * * @since Java 3D 1.5 */ public void set(NioImageBuffer image) { if (isLiveOrCompiled()) { if (!this.getCapability(ALLOW_IMAGE_WRITE)) { throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D1")); } } ((ImageComponent2DRetained) this.retained).set(image); } /** * Retrieves the image from this ImageComponent2D object. If the * data access mode is not by-reference, a copy of the image * is made. If the data access mode is by-reference, the * reference is returned. * * @return either a new BufferedImage object created from the data * in this image component, or the BufferedImage object referenced * by this image component. * * @exception CapabilityNotSetException if appropriate capability is * not set and this object is part of live or compiled scene graph * * @exception IllegalStateException if the image class is not * ImageClass.BUFFERED_IMAGE. */ public BufferedImage getImage() { if (isLiveOrCompiled()) { if (!this.getCapability(ImageComponent.ALLOW_IMAGE_READ)) throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D0")); } RenderedImage img = ((ImageComponent2DRetained) this.retained).getImage(); if ((img != null) && !(img instanceof BufferedImage)) { throw new IllegalStateException(J3dI18N.getString("ImageComponent2D5")); } return (BufferedImage) img; } /** * Retrieves the image from this ImageComponent2D object. If the * data access mode is not by-reference, a copy of the image * is made. If the data access mode is by-reference, the * reference is returned. * * @return either a new RenderedImage object created from the data * in this image component, or the RenderedImage object referenced * by this image component. * * @exception CapabilityNotSetException if appropriate capability is * not set and this object is part of live or compiled scene graph * * @exception IllegalStateException if the image class is not one of: * ImageClass.BUFFERED_IMAGE or ImageClass.RENDERED_IMAGE. * * @since Java 3D 1.2 */ public RenderedImage getRenderedImage() { if (isLiveOrCompiled()) if (!this.getCapability(ImageComponent.ALLOW_IMAGE_READ)) throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D0")); return ((ImageComponent2DRetained) this.retained).getImage(); } /** * Retrieves the image from this ImageComponent2D object. If the * data access mode is not by-reference, a copy of the image * is made. If the data access mode is by-reference, the * reference is returned. * * @return either a new NioImageBuffer object created from the data * in this image component, or the NioImageBuffer object referenced * by this image component. * * @exception CapabilityNotSetException if appropriate capability is * not set and this object is part of live or compiled scene graph * * @exception IllegalStateException if the image class is not * ImageClass.NIO_IMAGE_BUFFER. * * @since Java 3D 1.5 */ public NioImageBuffer getNioImage() { if (isLiveOrCompiled()) { if (!this.getCapability(ImageComponent.ALLOW_IMAGE_READ)) { throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D0")); } } return ((ImageComponent2DRetained) this.retained).getNioImage(); } /** * Modifies a contiguous subregion of the image component. * Block of data of dimension (width * height) * starting at the offset (srcX, srcY) of the specified * RenderedImage object will be copied into the image component * starting at the offset (dstX, dstY) of the ImageComponent2D object. * The specified RenderedImage object must be of the same format as * the current RenderedImage object in this image component. * This method can only be used if the data access mode is * by-copy. If it is by-reference, see updateData(). * * @param image RenderedImage object containing the subimage. * @param width width of the subregion. * @param height height of the subregion. * @param srcX starting X offset of the subregion in the * specified image. * @param srcY starting Y offset of the subregion in the * specified image. * @param dstX starting X offset of the subregion in the image * component of this object. * @param dstY starting Y offset of the subregion in the image * component of this object. * * @exception CapabilityNotSetException if appropriate capability is * not set and this object is part of live or compiled scene graph * * @exception IllegalStateException if the data access mode is * <code>BY_REFERENCE</code>. * * @exception IllegalArgumentException if <code>width</code> or * <code>height</code> of * the subregion exceeds the dimension of the image of this object. * * @exception IllegalArgumentException if <code>dstX</code> < 0, or * (<code>dstX</code> + <code>width</code>) > width of this object, or * <code>dstY</code> < 0, or * (<code>dstY</code> + <code>height</code>) > height of this object. * * @exception IllegalArgumentException if <code>srcX</code> < 0, or * (<code>srcX</code> + <code>width</code>) > width of the RenderedImage * object containing the subimage, or * <code>srcY</code> < 0, or * (<code>srcY</code> + <code>height</code>) > height of the * RenderedImage object containing the subimage. * * @exception IllegalArgumentException if the specified RenderedImage * is not compatible with the existing RenderedImage. * * @exception IllegalStateException if the image class is not one of: * ImageClass.BUFFERED_IMAGE or ImageClass.RENDERED_IMAGE. * * @since Java 3D 1.3 */ public void setSubImage(RenderedImage image, int width, int height, int srcX, int srcY, int dstX, int dstY) { if (isLiveOrCompiled() && !this.getCapability(ALLOW_IMAGE_WRITE)) { throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D1")); } if (((ImageComponent2DRetained) this.retained).isByReference()) { throw new IllegalStateException(J3dI18N.getString("ImageComponent2D4")); } int w = ((ImageComponent2DRetained) this.retained).getWidth(); int h = ((ImageComponent2DRetained) this.retained).getHeight(); // Fix to issue 492 if ((srcX < 0) || (srcY < 0) || ((srcX + width) > image.getWidth()) || ((srcY + height) > image.getHeight()) || (dstX < 0) || (dstY < 0) || ((dstX + width) > w) || ((dstY + height) > h)) { throw new IllegalArgumentException(J3dI18N.getString("ImageComponent2D3")); } ((ImageComponent2DRetained) this.retained).setSubImage(image, width, height, srcX, srcY, dstX, dstY); } /** * Updates image data that is accessed by reference. * This method calls the updateData method of the specified * ImageComponent2D.Updater object to synchronize updates to the * image data that is referenced by this ImageComponent2D object. * Applications that wish to modify such data must perform all * updates via this method. * <p> * The data to be modified has to be within the boundary of the * subregion * specified by the offset (x, y) and the dimension (width*height). * It is illegal to modify data outside this boundary. * If any referenced data is modified outisde the updateData * method, or any data outside the specified boundary is modified, * the results are undefined. * <p> * @param updater object whose updateData callback method will be * called to update the data referenced by this ImageComponent2D object. * @param x starting X offset of the subregion. * @param y starting Y offset of the subregion. * @param width width of the subregion. * @param height height of the subregion. * * @exception CapabilityNotSetException if the appropriate capability * is not set, and this object is part of a live or compiled scene graph * @exception IllegalStateException if the data access mode is * <code>BY_COPY</code>. * @exception IllegalArgumentException if <code>width</code> or * <code>height</code> of * the subregion exceeds the dimension of the image of this object. * @exception IllegalArgumentException if <code>x</code> < 0, or * (<code>x</code> + <code>width</code>) > width of this object, or * <code>y</code> < 0, or * (<code>y</code> + <code>height</code>) > height of this object. * * @since Java 3D 1.3 */ public void updateData(Updater updater, int x, int y, int width, int height) { if (isLiveOrCompiled() && !this.getCapability(ALLOW_IMAGE_WRITE)) { throw new CapabilityNotSetException(J3dI18N.getString("ImageComponent2D1")); } if (!((ImageComponent2DRetained) this.retained).isByReference()) { throw new IllegalStateException(J3dI18N.getString("ImageComponent2D2")); } int w = ((ImageComponent2DRetained) this.retained).getWidth(); int h = ((ImageComponent2DRetained) this.retained).getHeight(); if ((x < 0) || (y < 0) || ((x + width) > w) || ((y + height) > h)) { throw new IllegalArgumentException(J3dI18N.getString("ImageComponent2D3")); } ((ImageComponent2DRetained) this.retained).updateData(updater, x, y, width, height); } /** * Creates a retained mode ImageComponent2DRetained object that this * ImageComponent2D component object will point to. */ @Override void createRetained() { this.retained = new ImageComponent2DRetained(); this.retained.setSource(this); } /** * @deprecated replaced with cloneNodeComponent(boolean forceDuplicate) */ @Override public NodeComponent cloneNodeComponent() { ImageComponent2DRetained rt = (ImageComponent2DRetained) retained; ImageComponent2D img = new ImageComponent2D(rt.getFormat(), rt.width, rt.height, rt.byReference, rt.yUp); img.duplicateNodeComponent(this); return img; } /** * Copies all node information from <code>originalNodeComponent</code> * into the current node. This method is called from the * <code>duplicateNode</code> method. This routine does * the actual duplication of all "local data" (any data defined in * this object). * * @param originalNodeComponent the original node to duplicate * @param forceDuplicate when set to <code>true</code>, causes the * <code>duplicateOnCloneTree</code> flag to be ignored. When * <code>false</code>, the value of each node's * <code>duplicateOnCloneTree</code> variable determines whether * NodeComponent data is duplicated or copied. * * @see Node#cloneTree * @see NodeComponent#setDuplicateOnCloneTree */ @Override void duplicateAttributes(NodeComponent originalNodeComponent, boolean forceDuplicate) { super.duplicateAttributes(originalNodeComponent, forceDuplicate); ImageComponent.ImageClass imageClass = ((ImageComponentRetained) originalNodeComponent.retained) .getImageClass(); if (imageClass == ImageComponent.ImageClass.NIO_IMAGE_BUFFER) { NioImageBuffer nioImg = ((ImageComponent2DRetained) originalNodeComponent.retained).getNioImage(); if (nioImg != null) { ((ImageComponent2DRetained) retained).set(nioImg); } } else { RenderedImage img = ((ImageComponent2DRetained) originalNodeComponent.retained).getImage(); if (img != null) { ((ImageComponent2DRetained) retained).set(img); } } } /** * The ImageComponent2D.Updater interface is used in updating image data * that is accessed by reference from a live or compiled ImageComponent * object. Applications that wish to modify such data must define a * class that implements this interface. An instance of that class is * then passed to the <code>updateData</code> method of the * ImageComponent object to be modified. * * @since Java 3D 1.3 */ public static interface Updater { /** * Updates image data that is accessed by reference. * This method is called by the updateData method of an * ImageComponent object to effect * safe updates to image data that * is referenced by that object. Applications that wish to modify * such data must implement this method and perform all updates * within it. * <br> * NOTE: Applications should <i>not</i> call this method directly. * * @param imageComponent the ImageComponent object being updated. * @param x starting X offset of the subregion. * @param y starting Y offset of the subregion. * @param width width of the subregion. * @param height height of the subregion. * * @see ImageComponent2D#updateData */ public void updateData(ImageComponent2D imageComponent, int x, int y, int width, int height); } }