jdk/src/share/classes/java/awt/image/renderable/RenderableImageOp.java
changeset 539 7952521a4ad3
child 715 f16baef3a20e
equal deleted inserted replaced
538:d95bc71a5732 539:7952521a4ad3
       
     1 /*
       
     2  * Portions Copyright 1998-2000 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 /* ********************************************************************
       
    27  **********************************************************************
       
    28  **********************************************************************
       
    29  *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
       
    30  *** As  an unpublished  work pursuant to Title 17 of the United    ***
       
    31  *** States Code.  All rights reserved.                             ***
       
    32  **********************************************************************
       
    33  **********************************************************************
       
    34  **********************************************************************/
       
    35 
       
    36 package java.awt.image.renderable;
       
    37 import java.awt.geom.AffineTransform;
       
    38 import java.awt.geom.Rectangle2D;
       
    39 import java.awt.image.RenderedImage;
       
    40 import java.awt.RenderingHints;
       
    41 import java.util.Hashtable;
       
    42 import java.util.Vector;
       
    43 
       
    44 /**
       
    45  * This class handles the renderable aspects of an operation with help
       
    46  * from its associated instance of a ContextualRenderedImageFactory.
       
    47  */
       
    48 public class RenderableImageOp implements RenderableImage {
       
    49 
       
    50     /** A ParameterBlock containing source and parameters. */
       
    51     ParameterBlock paramBlock;
       
    52 
       
    53     /** The associated ContextualRenderedImageFactory. */
       
    54     ContextualRenderedImageFactory myCRIF;
       
    55 
       
    56     /** The bounding box of the results of this RenderableImageOp. */
       
    57     Rectangle2D boundingBox;
       
    58 
       
    59 
       
    60     /**
       
    61      * Constructs a RenderedImageOp given a
       
    62      * ContextualRenderedImageFactory object, and
       
    63      * a ParameterBlock containing RenderableImage sources and other
       
    64      * parameters.  Any RenderedImage sources referenced by the
       
    65      * ParameterBlock will be ignored.
       
    66      *
       
    67      * @param CRIF a ContextualRenderedImageFactory object
       
    68      * @param paramBlock a ParameterBlock containing this operation's source
       
    69      *        images and other parameters necessary for the operation
       
    70      *        to run.
       
    71      */
       
    72     public RenderableImageOp(ContextualRenderedImageFactory CRIF,
       
    73                              ParameterBlock paramBlock) {
       
    74         this.myCRIF = CRIF;
       
    75         this.paramBlock = (ParameterBlock) paramBlock.clone();
       
    76     }
       
    77 
       
    78     /**
       
    79      * Returns a vector of RenderableImages that are the sources of
       
    80      * image data for this RenderableImage. Note that this method may
       
    81      * return an empty vector, to indicate that the image has no sources,
       
    82      * or null, to indicate that no information is available.
       
    83      *
       
    84      * @return a (possibly empty) Vector of RenderableImages, or null.
       
    85      */
       
    86     public Vector<RenderableImage> getSources() {
       
    87         return getRenderableSources();
       
    88     }
       
    89 
       
    90     private Vector getRenderableSources() {
       
    91         Vector sources = null;
       
    92 
       
    93         if (paramBlock.getNumSources() > 0) {
       
    94             sources = new Vector();
       
    95             int i = 0;
       
    96             while (i < paramBlock.getNumSources()) {
       
    97                 Object o = paramBlock.getSource(i);
       
    98                 if (o instanceof RenderableImage) {
       
    99                     sources.add((RenderableImage)o);
       
   100                     i++;
       
   101                 } else {
       
   102                     break;
       
   103                 }
       
   104             }
       
   105         }
       
   106         return sources;
       
   107     }
       
   108 
       
   109     /**
       
   110      * Gets a property from the property set of this image.
       
   111      * If the property name is not recognized, java.awt.Image.UndefinedProperty
       
   112      * will be returned.
       
   113      *
       
   114      * @param name the name of the property to get, as a String.
       
   115      * @return a reference to the property Object, or the value
       
   116      *         java.awt.Image.UndefinedProperty.
       
   117      */
       
   118     public Object getProperty(String name) {
       
   119         return myCRIF.getProperty(paramBlock, name);
       
   120     }
       
   121 
       
   122     /**
       
   123      * Return a list of names recognized by getProperty.
       
   124      * @return a list of property names.
       
   125      */
       
   126     public String[] getPropertyNames() {
       
   127         return myCRIF.getPropertyNames();
       
   128     }
       
   129 
       
   130     /**
       
   131      * Returns true if successive renderings (that is, calls to
       
   132      * createRendering() or createScaledRendering()) with the same arguments
       
   133      * may produce different results.  This method may be used to
       
   134      * determine whether an existing rendering may be cached and
       
   135      * reused.  The CRIF's isDynamic method will be called.
       
   136      * @return <code>true</code> if successive renderings with the
       
   137      *         same arguments might produce different results;
       
   138      *         <code>false</code> otherwise.
       
   139      */
       
   140     public boolean isDynamic() {
       
   141         return myCRIF.isDynamic();
       
   142     }
       
   143 
       
   144     /**
       
   145      * Gets the width in user coordinate space.  By convention, the
       
   146      * usual width of a RenderableImage is equal to the image's aspect
       
   147      * ratio (width divided by height).
       
   148      *
       
   149      * @return the width of the image in user coordinates.
       
   150      */
       
   151     public float getWidth() {
       
   152         if (boundingBox == null) {
       
   153             boundingBox = myCRIF.getBounds2D(paramBlock);
       
   154         }
       
   155         return (float)boundingBox.getWidth();
       
   156     }
       
   157 
       
   158     /**
       
   159      * Gets the height in user coordinate space.  By convention, the
       
   160      * usual height of a RenderedImage is equal to 1.0F.
       
   161      *
       
   162      * @return the height of the image in user coordinates.
       
   163      */
       
   164     public float getHeight() {
       
   165         if (boundingBox == null) {
       
   166             boundingBox = myCRIF.getBounds2D(paramBlock);
       
   167         }
       
   168         return (float)boundingBox.getHeight();
       
   169     }
       
   170 
       
   171     /**
       
   172      * Gets the minimum X coordinate of the rendering-independent image data.
       
   173      */
       
   174     public float getMinX() {
       
   175         if (boundingBox == null) {
       
   176             boundingBox = myCRIF.getBounds2D(paramBlock);
       
   177         }
       
   178         return (float)boundingBox.getMinX();
       
   179     }
       
   180 
       
   181     /**
       
   182      * Gets the minimum Y coordinate of the rendering-independent image data.
       
   183      */
       
   184     public float getMinY() {
       
   185         if (boundingBox == null) {
       
   186             boundingBox = myCRIF.getBounds2D(paramBlock);
       
   187         }
       
   188         return (float)boundingBox.getMinY();
       
   189     }
       
   190 
       
   191     /**
       
   192      * Change the current ParameterBlock of the operation, allowing
       
   193      * editing of image rendering chains.  The effects of such a
       
   194      * change will be visible when a new rendering is created from
       
   195      * this RenderableImageOp or any dependent RenderableImageOp.
       
   196      *
       
   197      * @param paramBlock the new ParameterBlock.
       
   198      * @return the old ParameterBlock.
       
   199      * @see #getParameterBlock
       
   200      */
       
   201     public ParameterBlock setParameterBlock(ParameterBlock paramBlock) {
       
   202         ParameterBlock oldParamBlock = this.paramBlock;
       
   203         this.paramBlock = (ParameterBlock)paramBlock.clone();
       
   204         return oldParamBlock;
       
   205     }
       
   206 
       
   207     /**
       
   208      * Returns a reference to the current parameter block.
       
   209      * @return the <code>ParameterBlock</code> of this
       
   210      *         <code>RenderableImageOp</code>.
       
   211      * @see #setParameterBlock(ParameterBlock)
       
   212      */
       
   213     public ParameterBlock getParameterBlock() {
       
   214         return paramBlock;
       
   215     }
       
   216 
       
   217     /**
       
   218      * Creates a RenderedImage instance of this image with width w, and
       
   219      * height h in pixels.  The RenderContext is built automatically
       
   220      * with an appropriate usr2dev transform and an area of interest
       
   221      * of the full image.  All the rendering hints come from hints
       
   222      * passed in.
       
   223      *
       
   224      * <p> If w == 0, it will be taken to equal
       
   225      * Math.round(h*(getWidth()/getHeight())).
       
   226      * Similarly, if h == 0, it will be taken to equal
       
   227      * Math.round(w*(getHeight()/getWidth())).  One of
       
   228      * w or h must be non-zero or else an IllegalArgumentException
       
   229      * will be thrown.
       
   230      *
       
   231      * <p> The created RenderedImage may have a property identified
       
   232      * by the String HINTS_OBSERVED to indicate which RenderingHints
       
   233      * were used to create the image.  In addition any RenderedImages
       
   234      * that are obtained via the getSources() method on the created
       
   235      * RenderedImage may have such a property.
       
   236      *
       
   237      * @param w the width of rendered image in pixels, or 0.
       
   238      * @param h the height of rendered image in pixels, or 0.
       
   239      * @param hints a RenderingHints object containg hints.
       
   240      * @return a RenderedImage containing the rendered data.
       
   241      */
       
   242     public RenderedImage createScaledRendering(int w, int h,
       
   243                                                RenderingHints hints) {
       
   244         // DSR -- code to try to get a unit scale
       
   245         double sx = (double)w/getWidth();
       
   246         double sy = (double)h/getHeight();
       
   247         if (Math.abs(sx/sy - 1.0) < 0.01) {
       
   248             sx = sy;
       
   249         }
       
   250         AffineTransform usr2dev = AffineTransform.getScaleInstance(sx, sy);
       
   251         RenderContext newRC = new RenderContext(usr2dev, hints);
       
   252         return createRendering(newRC);
       
   253     }
       
   254 
       
   255     /**
       
   256      * Gets a RenderedImage instance of this image with a default
       
   257      * width and height in pixels.  The RenderContext is built
       
   258      * automatically with an appropriate usr2dev transform and an area
       
   259      * of interest of the full image.  All the rendering hints come
       
   260      * from hints passed in.  Implementors of this interface must be
       
   261      * sure that there is a defined default width and height.
       
   262      *
       
   263      * @return a RenderedImage containing the rendered data.
       
   264      */
       
   265     public RenderedImage createDefaultRendering() {
       
   266         AffineTransform usr2dev = new AffineTransform(); // Identity
       
   267         RenderContext newRC = new RenderContext(usr2dev);
       
   268         return createRendering(newRC);
       
   269     }
       
   270 
       
   271     /**
       
   272      * Creates a RenderedImage which represents this
       
   273      * RenderableImageOp (including its Renderable sources) rendered
       
   274      * according to the given RenderContext.
       
   275      *
       
   276      * <p> This method supports chaining of either Renderable or
       
   277      * RenderedImage operations.  If sources in
       
   278      * the ParameterBlock used to construct the RenderableImageOp are
       
   279      * RenderableImages, then a three step process is followed:
       
   280      *
       
   281      * <ol>
       
   282      * <li> mapRenderContext() is called on the associated CRIF for
       
   283      * each RenderableImage source;
       
   284      * <li> createRendering() is called on each of the RenderableImage sources
       
   285      * using the backwards-mapped RenderContexts obtained in step 1,
       
   286      * resulting in a rendering of each source;
       
   287      * <li> ContextualRenderedImageFactory.create() is called
       
   288      * with a new ParameterBlock containing the parameters of
       
   289      * the RenderableImageOp and the RenderedImages that were created by the
       
   290      * createRendering() calls.
       
   291      * </ol>
       
   292      *
       
   293      * <p> If the elements of the source Vector of
       
   294      * the ParameterBlock used to construct the RenderableImageOp are
       
   295      * instances of RenderedImage, then the CRIF.create() method is
       
   296      * called immediately using the original ParameterBlock.
       
   297      * This provides a basis case for the recursion.
       
   298      *
       
   299      * <p> The created RenderedImage may have a property identified
       
   300      * by the String HINTS_OBSERVED to indicate which RenderingHints
       
   301      * (from the RenderContext) were used to create the image.
       
   302      * In addition any RenderedImages
       
   303      * that are obtained via the getSources() method on the created
       
   304      * RenderedImage may have such a property.
       
   305      *
       
   306      * @param renderContext The RenderContext to use to perform the rendering.
       
   307      * @return a RenderedImage containing the desired output image.
       
   308      */
       
   309     public RenderedImage createRendering(RenderContext renderContext) {
       
   310         RenderedImage image = null;
       
   311         RenderContext rcOut = null;
       
   312 
       
   313         // Clone the original ParameterBlock; if the ParameterBlock
       
   314         // contains RenderableImage sources, they will be replaced by
       
   315         // RenderedImages.
       
   316         ParameterBlock renderedParamBlock = (ParameterBlock)paramBlock.clone();
       
   317         Vector sources = getRenderableSources();
       
   318 
       
   319         try {
       
   320             // This assumes that if there is no renderable source, that there
       
   321             // is a rendered source in paramBlock
       
   322 
       
   323             if (sources != null) {
       
   324                 Vector renderedSources = new Vector();
       
   325                 for (int i = 0; i < sources.size(); i++) {
       
   326                     rcOut = myCRIF.mapRenderContext(i, renderContext,
       
   327                                                     paramBlock, this);
       
   328                     RenderedImage rdrdImage =
       
   329                        ((RenderableImage)sources.elementAt(i)).createRendering(rcOut);
       
   330                     if (rdrdImage == null) {
       
   331                         return null;
       
   332                     }
       
   333 
       
   334                     // Add this rendered image to the ParameterBlock's
       
   335                     // list of RenderedImages.
       
   336                     renderedSources.addElement(rdrdImage);
       
   337                 }
       
   338 
       
   339                 if (renderedSources.size() > 0) {
       
   340                     renderedParamBlock.setSources(renderedSources);
       
   341                 }
       
   342             }
       
   343 
       
   344             return myCRIF.create(renderContext, renderedParamBlock);
       
   345         } catch (ArrayIndexOutOfBoundsException e) {
       
   346             // This should never happen
       
   347             return null;
       
   348         }
       
   349     }
       
   350 }