Source Code Cross Referenced for OpImage.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » javax » media » jai » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » Java Advanced Imaging » javax.media.jai 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: OpImage.java,v $
0003:         *
0004:         * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * Use is subject to license terms.
0007:         *
0008:         * $Revision: 1.1 $
0009:         * $Date: 2005/02/11 04:57:12 $
0010:         * $State: Exp $
0011:         */
0012:        package javax.media.jai;
0013:
0014:        import com.sun.media.jai.util.ImageUtil;
0015:        import com.sun.media.jai.util.JDKWorkarounds;
0016:        import java.awt.Dimension;
0017:        import java.awt.Point;
0018:        import java.awt.Rectangle;
0019:        import java.awt.geom.Point2D;
0020:        import java.awt.image.ColorModel; // 3-22-00 used in deprecated methods only
0021:        import java.awt.image.IndexColorModel; // 3-22-00 used in deprecated mthds only
0022:        import java.awt.image.Raster;
0023:        import java.awt.image.RenderedImage;
0024:        import java.awt.image.SampleModel; // 3-22-00 used in deprecated methods only
0025:        import java.awt.image.WritableRaster;
0026:        import java.util.ArrayList;
0027:        import java.util.Iterator;
0028:        import java.util.Map;
0029:        import java.util.Set;
0030:        import java.util.Vector;
0031:        import javax.media.jai.util.CaselessStringKey;
0032:
0033:        /**
0034:         * This is the base class for all image operations.  It provides a home
0035:         * for information and functionalities common to all the op-image classes,
0036:         * and implements various utility methods that may be useful to a specific
0037:         * operation.  Image operations may be divided into different categories
0038:         * based on their characteristics.  A subclass, extending
0039:         * <code>OpImage</code>, represents a category and implements methods
0040:         * unique and common to those operations.  Each individual operator
0041:         * should extend the subclass that represents the specific
0042:         * category that operator belongs to.
0043:         *
0044:         * <p> The layout variables of an <code>OpImage</code> are inherited from the
0045:         * <code>PlanarImage</code> superclass.  The layout should be set when the
0046:         * <code>OpImage</code> is constructed.  Each subclass must set
0047:         * the appropriate layout variables and supply them via the
0048:         * <code>ImageLayout</code> argument at construction time.  This class
0049:         * simply modifies these settings as described in the <code>OpImage</code>
0050:         * constructor comments before forwarding the layout to the
0051:         * <code>PlanarImage</code> constructor.  If a subclass needs to modify
0052:         * any of the layout settings subsequent to invoking its superclass
0053:         * constructors it should use the <code>setImageLayout()</code> method
0054:         * defined in <code>PlanarImage</code> in preference to setting the
0055:         * layout variables directly.
0056:         *
0057:         * <p> A <code>RenderedImage</code>'s pixel data type and number of bands
0058:         * are defined by its <code>SampleModel</code>, while the
0059:         * <code>ColorModel</code> translates the pixel data into color/alpha
0060:         * components in the specific <code>ColorSpace</code> that is associated
0061:         * with the <code>ColorModel</code>.
0062:         *
0063:         * <p> By default, the operators provided by Java Advanced Imaging (JAI)
0064:         * operate on the image's pixel data only.  That is, the computations
0065:         * are performed on the data described by the image's
0066:         * <code>SampleModel</code>.  No color translation is performed prior
0067:         * to the actual computation by the operator, regardless of the type of
0068:         * the <code>ColorModel</code> an image has.  If a user intends to have
0069:         * an operation performed on the color data, he must perform the
0070:         * color translation explicitly prior to invoking the operation.
0071:         *
0072:         * <p> There are those operators that specifically deal with the
0073:         * color/alpha data of an image.  Such an operator must state its
0074:         * behavior in its <code>OperationDescriptor</code> explicitly and
0075:         * explain its intended usage of the image's color/alpha component data.
0076:         * In such cases, the image's <code>ColorModel</code> as well as the
0077:         * associated <code>ColorSpace</code> should be considered.
0078:         *
0079:         * <p> However there are certain operations, the results of which are
0080:         * incorrect when the source has colormapped imagery, i.e. the source
0081:         * has an <code>IndexColorModel</code>, and the computations are
0082:         * performed on the image's non color transformed pixel data. In JAI,
0083:         * such operations are those that are implemented as subclasses of
0084:         * {@link AreaOpImage}, {@link GeometricOpImage}, and the "format" 
0085:         * operation. These operations set the 
0086:         * {@link JAI#KEY_REPLACE_INDEX_COLOR_MODEL} <code>RenderingHint</code>
0087:         * to true, thus ensuring that the operations are performed correctly 
0088:         * on the colormapped imagery, not treating the indices into the color
0089:         * map as pixel data. 
0090:         *
0091:         * <p> The tile cache and scheduler are handled by this class.  JAI
0092:         * provides a default implementation for <code>TileCache</code> and
0093:         * <code>TileScheduler</code>.  However, they may be overriden by
0094:         * each application.  An <code>OpImage</code> may share a common cache
0095:         * with other <code>OpImage</code>s, or it may have a private cache of
0096:         * its own.  To override an existing cache, use the
0097:         * <code>setTileCache</code> method; an input argument of <code>null</code>
0098:         * indicates that this image should not have a tile cache.
0099:         *
0100:         * <p> The <code>getTile</code> method may be used to request a tile
0101:         * of the image.  The default implementation of this method in this
0102:         * class first checks whether the requested tile is in the tile cache,
0103:         * and if not, uses the default <code>TileScheduler</code> to schedule
0104:         * the tile for computation.  Once the tile has been computed, it is
0105:         * added to the cache and returned as a <code>Raster</code>.
0106:         *
0107:         * <p> The JAI tile scheduler assumes that when a request is made to
0108:         * schedule a tile for computation via the <code>scheduleTile</code>
0109:         * method, that tile is not currently in the cache.  To avoid a cycle,
0110:         * it calls <code>OpImage.computeTile</code> for the actual tile
0111:         * computation.
0112:         *
0113:         * <p> The default implementation of the <code>computeTile</code> method 
0114:         * in this class first creates a new <code>Raster</code> to represent
0115:         * the requested tile, then calls one of the two <code>computeRect</code>
0116:         * methods to compute the actual pixel values and store the result in
0117:         * the <code>DataBuffer</code> of the <code>Raster</code>.
0118:         *
0119:         * <p> Two variants of the <code>computeRect</code> method exist.
0120:         *
0121:         * <p> The first (with input arguments <code>Raster[]</code>,
0122:         * <code>WritableRaster</code>, and <code>Rectangle</code>) is used when
0123:         * the <code>OpImage</code> is constructed with the
0124:         * <code>cobbleSources</code> argument set to <code>true</code>.
0125:         * This indicates that the source data must be cobbled into a single
0126:         * <code>Raster</code> and that all the necessary source data are provided
0127:         * in order to compute the rectangular region of the destination image.
0128:         * The source <code>Raster</code> array contains one entry for each
0129:         * source image.
0130:         *
0131:         * <p> The second (with input arguments <code>PlanarImage[]</code>,
0132:         * <code>WritableRaster</code>, and <code>Rectangle</code>) is used when
0133:         * the <code>OpImage</code> is constructed with the
0134:         * <code>cobbleSources</code> argument set to <code>false</code>.
0135:         * This indicates that the source data are not cobbled into a single
0136:         * <code>Raster</code>; instead an array of <code>PlanarImage</code>s,
0137:         * one for each source, supply the source data and each image is
0138:         * responsible for performing its own data accesses.  This variant is
0139:         * generally useful if iterators are to be used for the underlying
0140:         * implementation of accessing the image data.
0141:         *
0142:         * <p> The two <code>computeRect</code> methods are not abstract because
0143:         * normally only one needs to be implemented by the subclass depending on
0144:         * the <code>cobbleSources</code> value.  The default implementation of
0145:         * these two methods in this class throws a <code>RuntimeException</code>.
0146:         *
0147:         * <p> Every operator who follows the above default implementation must
0148:         * supply an overridden version of at least one of the
0149:         * <code>computeRect</code> method variants, and specify which one is
0150:         * to be called via the <code>cobbleSources</code> argument of the
0151:         * constructor, or an exception will be thrown at run time.
0152:         *
0153:         * <p> If a subclass overrides <code>getTile</code> not to call
0154:         * <code>computeTile</code>, does not use the JAI implementation of
0155:         * <code>TileScheduler</code>, overrides <code>computeTile</code> not to
0156:         * call <code>computeRect</code>, or does not follow the above default
0157:         * implementation in any way, then it may need to handle issues such as
0158:         * tile caching, multi-threading, and etc. by itself and may not need to
0159:         * override some of the methods described above.  In some cases, some of
0160:         * the methods or variables are even irrelevant.  However, subclasses
0161:         * should be careful when not following the default path for computing
0162:         * a tile.  Most importantly, when a subclass overrides
0163:         * <code>getTile</code>, it should also override <code>computeTile</code>.
0164:         *
0165:         * <p> To request multiple tiles at a time, it is preferable to
0166:         * call the <code>getTiles</code> method with a complete list of the
0167:         * requested tiles' indices, than to call <code>getTile</code> once
0168:         * per tile.  The implementation of <code>getTiles</code> in this class
0169:         * is optimized using multi-threading so that multiple tiles are
0170:         * computed simultaneously.
0171:         *
0172:         * @see PlanarImage
0173:         * @see AreaOpImage
0174:         * @see GeometricOpImage
0175:         * @see PointOpImage
0176:         * @see StatisticsOpImage
0177:         * @see SourcelessOpImage
0178:         *
0179:         */
0180:        public abstract class OpImage extends PlanarImage {
0181:
0182:            /**
0183:             * A constant indicating that an operation is likely to
0184:             * spend its time mainly performing computation.
0185:             */
0186:            public static final int OP_COMPUTE_BOUND = 1;
0187:
0188:            /**
0189:             * A constant indicating that an operation is likely to
0190:             * spend its time mainly performing local I/O.
0191:             */
0192:            public static final int OP_IO_BOUND = 2;
0193:
0194:            /**
0195:             * A constant indicating that an operation is likely to
0196:             * spend its time mainly performing network I/O.
0197:             */
0198:            public static final int OP_NETWORK_BOUND = 3;
0199:
0200:            /**
0201:             * A constant equal to what would be returned by
0202:             * <code>ImageLayout.getValidMask()</code> if all fields were set.
0203:             */
0204:            private static final int LAYOUT_MASK_ALL = ImageLayout.MIN_X_MASK
0205:                    | ImageLayout.MIN_Y_MASK | ImageLayout.WIDTH_MASK
0206:                    | ImageLayout.HEIGHT_MASK
0207:                    | ImageLayout.TILE_GRID_X_OFFSET_MASK
0208:                    | ImageLayout.TILE_GRID_Y_OFFSET_MASK
0209:                    | ImageLayout.TILE_WIDTH_MASK
0210:                    | ImageLayout.TILE_HEIGHT_MASK
0211:                    | ImageLayout.SAMPLE_MODEL_MASK
0212:                    | ImageLayout.COLOR_MODEL_MASK;
0213:
0214:            /**
0215:             * The cache object used to cache this image's tiles.  It may refer
0216:             * to a common cache shared by many <code>OpImage</code>s or a private
0217:             * cache for this image only.  If it is <code>null</code>, it
0218:             * indicates that this image does not have a tile cache.
0219:             */
0220:            protected transient TileCache cache;
0221:
0222:            /**
0223:             * Metric used to produce an ordered list of tiles.  This determines
0224:             * which tiles are removed from the cache first if a memory control
0225:             * operation is required.
0226:             *
0227:             * @since JAI 1.1
0228:             */
0229:            protected Object tileCacheMetric;
0230:
0231:            /**
0232:             * The scheduler to be used to schedule tile computation.
0233:             */
0234:            private transient TileScheduler scheduler = JAI
0235:                    .getDefaultInstance().getTileScheduler();
0236:
0237:            /**
0238:             * Variable indicating whether the TileScheduler is the Sun implementation.
0239:             */
0240:            private boolean isSunTileScheduler = false;
0241:
0242:            /**
0243:             * Indicates which one of the two <code>computeRect</code> variants
0244:             * should be called by the <code>computeTile</code> method.  If it
0245:             * is <code>true</code>, <code>computeRect</code> expects
0246:             * contiguous sources.
0247:             */
0248:            protected boolean cobbleSources;
0249:
0250:            /**
0251:             * Whether dispose() has been invoked.
0252:             */
0253:            private boolean isDisposed = false;
0254:
0255:            /**
0256:             * Flag indicating that tile recycling is enabled for tiles which
0257:             * may be referenced outside the API.
0258:             */
0259:            private boolean isCachedTileRecyclingEnabled = false;
0260:
0261:            /**
0262:             * A <code>TileRecycler</code> for use in <code>createTile()</code>.
0263:             * May be <code>null</code>. This field is set by the configuration
0264:             * map passed to {@link #OpImage(Vector,ImageLayout,Map,boolean}.
0265:             *
0266:             * @since JAI 1.1.2
0267:             */
0268:            protected TileRecycler tileRecycler;
0269:
0270:            /** The default RasterAccessor format tags. */
0271:            // XXX This variable should be removed if we stop using RasterAccessor.
0272:            private RasterFormatTag[] formatTags = null;
0273:
0274:            /**
0275:             * Creates a new <code>ImageLayout</code> or forwards the argument
0276:             * layout with or without modifications.
0277:             *
0278:             * <p> If the <code>layout</code> parameter is non-<code>null</code>
0279:             * and all its fields are set then it is cloned and returned.
0280:             *
0281:             * <p> If the <code>layout</code> parameter is non-<code>null</code>
0282:             * but some of its fields are not set and there is at least one source
0283:             * available, then all fields of the layout which are not set are
0284:             * copied from the corresponding attributes of the first source except
0285:             * possibly the <code>ColorModel</code>.  The <code>ColorModel</code>
0286:             * is copied if and only if the destination <code>SampleModel</code> is
0287:             * non-<code>null</code> and the <code>ColorModel</code> and
0288:             * <code>SampleModel</code> are compatible.
0289:             *
0290:             * The image's tile dimensions will be set by the first applicable 
0291:             * means in the following priority-ordered list. Note that each tile
0292:             * dimension, the <code>tileWidth</code> and the
0293:             * <code>tileHeight</code>, is considered independently :
0294:             * <ol>
0295:             * <li>Tile dimension set in the <code>ImageLayout</code> (either by
0296:             * the user or the operator itself);</li>
0297:             * <li>Tile dimension of source, if source is non-<code>null</code>.
0298:             * The tile dimension will be clamped to the minimum of that of the
0299:             * source tile dimension and the image's corresponding dimension;</li>
0300:             * <li>Non-<code>null</code> default tile size returned by 
0301:             * <code>JAI.getDefaultTileSize()</code>, if the corresponding
0302:             * image dimension is at least double the default tile size;</li>
0303:             * <li>The dimensions of the image itself;</li>
0304:             * </ol>
0305:             *
0306:             * <p> If the <code>layout</code> parameter is <code>null</code> and
0307:             * there is at least one source available, a new layout is created from
0308:             * the first source and returned directly.
0309:             */
0310:            private static ImageLayout layoutHelper(ImageLayout layout,
0311:                    Vector sources, Map config) {
0312:                // Initialize to a reference to the layout passed in.
0313:                ImageLayout il = layout;
0314:
0315:                // Check the source Vector elements for nulls.
0316:                if (sources != null) {
0317:                    checkSourceVector(sources, true);
0318:                }
0319:
0320:                // Check the class of the first source to avoid an exception here; a
0321:                // class cast exception will be thrown by the PlanarImage constructor.
0322:                RenderedImage im = sources != null && sources.size() > 0
0323:                        && sources.firstElement() instanceof  RenderedImage ? (RenderedImage) sources
0324:                        .firstElement()
0325:                        : null;
0326:
0327:                // Update some or all of the layout if a source is available.
0328:                if (im != null) {
0329:                    // Create a new layout with the source as fallback.
0330:                    // The ColorModel field is intentionally NOT set.
0331:                    if (layout == null) {
0332:                        // Copy entirety of source image layout.
0333:                        il = layout = new ImageLayout(im);
0334:
0335:                        // Invalidate the ColorModel setting.
0336:                        il.unsetValid(ImageLayout.COLOR_MODEL_MASK);
0337:                    } else {
0338:                        // Set all fields except ColorModel.
0339:                        il = new ImageLayout(layout.getMinX(im), layout
0340:                                .getMinY(im), layout.getWidth(im), layout
0341:                                .getHeight(im), layout.getTileGridXOffset(im),
0342:                                layout.getTileGridYOffset(im), layout
0343:                                        .getTileWidth(im), layout
0344:                                        .getTileHeight(im), layout
0345:                                        .getSampleModel(im), null);
0346:                    }
0347:
0348:                    // At this point "layout" and "il" are non-null with "layout"
0349:                    // representing the ImageLayout originally passed in.  "il" does
0350:                    // not yet have its ColorModel field set.
0351:
0352:                    // Set the ColorModel.
0353:                    if (layout.isValid(ImageLayout.COLOR_MODEL_MASK)
0354:                            && layout.getColorModel(null) == null) {
0355:                        // User wants to force a null ColorModel.
0356:                        il.setColorModel(null);
0357:
0358:                    } else if (il.getSampleModel(null) != null) {
0359:
0360:                        // Target SampleModel is available.
0361:
0362:                        // Get SampleModel from "il"; guaranteed to be non-null.
0363:                        SampleModel sm = il.getSampleModel(null);
0364:
0365:                        // Get ColorModel from "layout".
0366:                        ColorModel cmLayout = layout.getColorModel(null);
0367:
0368:                        // First attempt to set the ColorModel to that specified
0369:                        // in the original layout, if any.
0370:                        if (cmLayout != null) {
0371:                            // ColorModel is set in original layout.
0372:                            if (JDKWorkarounds.areCompatibleDataModels(sm,
0373:                                    cmLayout)) {
0374:                                // ColorModel is compatible with target SampleModel.
0375:                                il.setColorModel(cmLayout);
0376:
0377:                            } else if (layout.getSampleModel(null) == null) {
0378:                                // SampleModel not set in original layout so
0379:                                // ColorModel must be incompatible with source
0380:                                // SampleModel: create a compatible SampleModel.
0381:
0382:                                // Set the ColorModel to that desired.
0383:                                il.setColorModel(cmLayout);
0384:
0385:                                // Derive a new SampleModel from the desired ColorModel
0386:                                SampleModel derivedSM = cmLayout
0387:                                        .createCompatibleSampleModel(il
0388:                                                .getTileWidth(null), il
0389:                                                .getTileHeight(null));
0390:
0391:                                // Set the SampleModel to that derived from the CM.
0392:                                il.setSampleModel(derivedSM);
0393:
0394:                            }
0395:                        }
0396:
0397:                        // If ColorModel not set from ImageLayout, attempt to set
0398:                        // using a ColorModelFactory and if that fails, attempt to
0399:                        // use the ColorModel of the source.
0400:                        if (!il.isValid(ImageLayout.COLOR_MODEL_MASK)
0401:                                && !setColorModelFromFactory(sm, sources,
0402:                                        config, il)) {
0403:                            // Get ColorModel from "im", i.e., the source.
0404:                            ColorModel cmSource = im.getColorModel();
0405:                            if (cmSource != null
0406:                                    && JDKWorkarounds.areCompatibleDataModels(
0407:                                            sm, cmSource)) {
0408:                                // Set to source ColorModel.
0409:                                if (cmSource != null
0410:                                        && cmSource instanceof  IndexColorModel
0411:                                        && config != null
0412:                                        && config
0413:                                                .containsKey(JAI.KEY_REPLACE_INDEX_COLOR_MODEL)
0414:                                        && ((Boolean) config
0415:                                                .get(JAI.KEY_REPLACE_INDEX_COLOR_MODEL))
0416:                                                .booleanValue()) {
0417:
0418:                                    ColorModel newCM = PlanarImage
0419:                                            .getDefaultColorModel(sm
0420:                                                    .getDataType(), cmSource
0421:                                                    .getNumComponents());
0422:
0423:                                    SampleModel newSM;
0424:                                    if (newCM != null) {
0425:                                        newSM = newCM
0426:                                                .createCompatibleSampleModel(il
0427:                                                        .getTileWidth(null), il
0428:                                                        .getTileHeight(null));
0429:                                    } else {
0430:                                        newSM = RasterFactory
0431:                                                .createPixelInterleavedSampleModel(
0432:                                                        sm.getDataType(),
0433:                                                        il.getTileWidth(null),
0434:                                                        il.getTileHeight(null),
0435:                                                        cmSource
0436:                                                                .getNumComponents());
0437:                                    }
0438:
0439:                                    il.setSampleModel(newSM);
0440:                                    if (newCM != null)
0441:                                        il.setColorModel(newCM);
0442:                                } else {
0443:                                    il.setColorModel(cmSource);
0444:                                }
0445:                            }
0446:                        }
0447:                    } else if (il.getSampleModel(null) == null) { // null SampleModel
0448:                        // Set to whatever is available.
0449:                        il.setColorModel(layout.getColorModel(im));
0450:                    }
0451:                    // end of block if(im != null)
0452:                } else if (il != null) {
0453:                    // Can only get here if im == null && layout != null.
0454:                    // Make sure that il is a clone of layout.
0455:                    il = (ImageLayout) layout.clone();
0456:
0457:                    // If the ColorModel is set but the SampleModel is not,
0458:                    // derive a SampleModel from the ColorModel.
0459:                    if (il.getColorModel(null) != null
0460:                            && il.getSampleModel(null) == null) {
0461:                        // Set SampleModel dimensions.
0462:                        int smWidth = il.getTileWidth(null);
0463:                        if (smWidth == 0) {
0464:                            smWidth = 512;
0465:                        }
0466:                        int smHeight = il.getTileHeight(null);
0467:                        if (smHeight == 0) {
0468:                            smHeight = 512;
0469:                        }
0470:
0471:                        // Derive a new SampleModel from the desired ColorModel
0472:                        SampleModel derivedSM = il.getColorModel(null)
0473:                                .createCompatibleSampleModel(smWidth, smHeight);
0474:
0475:                        // Set the SampleModel to that derived from the CM.
0476:                        il.setSampleModel(derivedSM);
0477:                    }
0478:                } // end of block if(il != null)
0479:
0480:                // If no ColorModel is set, then first attempt to set a ColorModel
0481:                // using the ColorModelFactory; otherwise set a default ColorModel
0482:                // if either the configuration mapping is null, it does not contain
0483:                // a mapping of the key KEY_DEFAULT_COLOR_MODEL_ENABLED, or this key
0484:                // is mapped to Boolean.TRUE.
0485:                if (il != null
0486:                        && !il.isValid(ImageLayout.COLOR_MODEL_MASK)
0487:                        && il.getSampleModel(null) != null
0488:                        && !setColorModelFromFactory(il.getSampleModel(null),
0489:                                sources, config, il)) {
0490:
0491:                    ColorModel cm = null;
0492:                    SampleModel srcSM = il.getSampleModel(null);
0493:
0494:                    // If it is not a byte image, then probably all the above did not
0495:                    // manage to set a ColorModel and ImageUtil.getCompatibleColorModel
0496:                    // will be used to get the ColorModel. However we want to ensure
0497:                    // that the destination ColorModel is expanded if the ColorModel
0498:                    // of the source is an IndexColorModel and we've been asked to
0499:                    // do IndexColorModel expansion
0500:                    if (im != null
0501:                            && im.getColorModel() != null
0502:                            && im.getColorModel() instanceof  IndexColorModel
0503:                            && config != null
0504:                            && config
0505:                                    .containsKey(JAI.KEY_REPLACE_INDEX_COLOR_MODEL)
0506:                            && ((Boolean) config
0507:                                    .get(JAI.KEY_REPLACE_INDEX_COLOR_MODEL))
0508:                                    .booleanValue()) {
0509:
0510:                        IndexColorModel icm = (IndexColorModel) im
0511:                                .getColorModel();
0512:
0513:                        // We need to change the ColorModel to a non IndexColorModel
0514:                        // so that operations such as geometric can take place
0515:                        // correctly. If the ColorModel is changed the SampleModel
0516:                        // needs to be changed too, so that they are compatible
0517:                        cm = PlanarImage.getDefaultColorModel(srcSM
0518:                                .getDataType(), icm.getNumComponents());
0519:
0520:                        SampleModel newSM;
0521:                        if (cm != null) {
0522:                            newSM = cm.createCompatibleSampleModel(srcSM
0523:                                    .getWidth(), srcSM.getHeight());
0524:                        } else {
0525:                            newSM = RasterFactory
0526:                                    .createPixelInterleavedSampleModel(srcSM
0527:                                            .getDataType(), srcSM.getWidth(),
0528:                                            srcSM.getHeight(), icm
0529:                                                    .getNumComponents());
0530:                        }
0531:
0532:                        il.setSampleModel(newSM);
0533:
0534:                    } else {
0535:
0536:                        cm = ImageUtil.getCompatibleColorModel(il
0537:                                .getSampleModel(null), config);
0538:                    }
0539:
0540:                    // Set ColorModel only if method succeeded.
0541:                    if (cm != null)
0542:                        il.setColorModel(cm);
0543:                }
0544:
0545:                // If the tile dimensions were not set in "layout" and are either
0546:                // not set in "il" or would yield an untiled image then reset them to
0547:                // the global tile size default if each image dimension is at least
0548:                // double the respective default tile dimension.
0549:                if (layout != null
0550:                        && il != null
0551:                        && !layout.isValid(ImageLayout.TILE_WIDTH_MASK
0552:                                | ImageLayout.TILE_HEIGHT_MASK)) {
0553:                    Dimension defaultTileSize = JAI.getDefaultTileSize();
0554:                    if (defaultTileSize != null) {
0555:                        if (!layout.isValid(ImageLayout.TILE_WIDTH_MASK)) {
0556:                            if (il.getTileWidth(null) <= 0) {
0557:                                il.setTileWidth(defaultTileSize.width);
0558:                            } else {
0559:                                // Calculate number of tiles along X.
0560:                                int numX = XToTileX(il.getMinX(null)
0561:                                        + il.getWidth(null) - 1, il
0562:                                        .getTileGridXOffset(null), il
0563:                                        .getTileWidth(null))
0564:                                        - XToTileX(il.getMinX(null), il
0565:                                                .getTileGridXOffset(null), il
0566:                                                .getTileWidth(null)) + 1;
0567:
0568:                                // Reset if single-tiled and image is big enough in X.
0569:                                if (numX <= 1
0570:                                        && il.getWidth(null) >= 2 * defaultTileSize.width) {
0571:                                    il.setTileWidth(defaultTileSize.width);
0572:                                }
0573:                            }
0574:                        }
0575:
0576:                        if (!layout.isValid(ImageLayout.TILE_HEIGHT_MASK)) {
0577:                            if (il.getTileHeight(null) <= 0) {
0578:                                il.setTileHeight(defaultTileSize.height);
0579:                            } else {
0580:                                // Calculate number of tiles along Y.
0581:                                int numY = YToTileY(il.getMinY(null)
0582:                                        + il.getHeight(null) - 1, il
0583:                                        .getTileGridYOffset(null), il
0584:                                        .getTileHeight(null))
0585:                                        - YToTileY(il.getMinY(null), il
0586:                                                .getTileGridYOffset(null), il
0587:                                                .getTileHeight(null)) + 1;
0588:
0589:                                // Reset if single-tiled and image is big enough in Y.
0590:                                if (numY <= 1
0591:                                        && il.getHeight(null) >= 2 * defaultTileSize.height) {
0592:                                    il.setTileHeight(defaultTileSize.height);
0593:                                }
0594:                            }
0595:                        }
0596:                    }
0597:                }
0598:
0599:                // Independently clamp each tile dimension to the respective image
0600:                // dimension, if the tile dimensions are not set in any supplied
0601:                // ImageLayout, and the tile and image dimensions are both set in
0602:                // the ImageLayout to be returned.
0603:
0604:                // Tile width
0605:                if ((layout == null || !layout
0606:                        .isValid(ImageLayout.TILE_WIDTH_MASK))
0607:                        && il.isValid(ImageLayout.TILE_WIDTH_MASK
0608:                                | ImageLayout.WIDTH_MASK)
0609:                        && il.getTileWidth(null) > il.getWidth(null)) {
0610:                    il.setTileWidth(il.getWidth(null));
0611:                }
0612:
0613:                // Tile height
0614:                if ((layout == null || !layout
0615:                        .isValid(ImageLayout.TILE_HEIGHT_MASK))
0616:                        && il.isValid(ImageLayout.TILE_HEIGHT_MASK
0617:                                | ImageLayout.HEIGHT_MASK)
0618:                        && il.getTileHeight(null) > il.getHeight(null)) {
0619:                    il.setTileHeight(il.getHeight(null));
0620:                }
0621:
0622:                return il;
0623:            }
0624:
0625:            /**
0626:             * Set the <code>ColorModel</code> in <code>layout</code> if
0627:             * <code>config</code> is non-<code>null</code> and contains a mapping
0628:             * for <code>JAI.KEY_COLOR_MODEL_FACTORY</code>.  If the
0629:             * <code>ColorModelFactory</code> returns a non-<code>null</code>
0630:             * <code>ColorModel</code> which is compatible with
0631:             * <code>sampleModel</code> it is used to set the <code>ColorModel</code>
0632:             * in <code>layout</code>.
0633:             *
0634:             * @param sampleModel The <code>SampleModel</code> to which the
0635:             *        <code>ColorModel</code> to be created must correspond;
0636:             *        may <b>not</b> be <code>null</code>.
0637:             * @param sources A <code>List</code> of <code>RenderedImage</code>s;
0638:             *        may be <code>null</code>.
0639:             * @param config A configuration mapping; may be
0640:             *        <code>null</code>.
0641:             * @param layout The image layout; will be updated with the
0642:             *        <code>ColorModel</code>created by the
0643:             *        <code>ColorModelFactory</code>
0644:             *
0645:             * @return Whether the <code>ColorModel</code> in <code>layout</code>
0646:             *         has been set.
0647:             * @exception IllegalArgumentException if <code>sampleModel</code>
0648:             *            is <code>null</code>.
0649:             */
0650:            private static boolean setColorModelFromFactory(
0651:                    SampleModel sampleModel, Vector sources, Map config,
0652:                    ImageLayout layout) {
0653:                boolean isColorModelSet = false;
0654:
0655:                if (config != null
0656:                        && config.containsKey(JAI.KEY_COLOR_MODEL_FACTORY)) {
0657:                    ColorModelFactory cmf = (ColorModelFactory) config
0658:                            .get(JAI.KEY_COLOR_MODEL_FACTORY);
0659:                    ColorModel cm = cmf.createColorModel(sampleModel, sources,
0660:                            config);
0661:                    if (cm != null
0662:                            && JDKWorkarounds.areCompatibleDataModels(
0663:                                    sampleModel, cm)) {
0664:                        layout.setColorModel(cm);
0665:                        isColorModelSet = true;
0666:                    }
0667:                }
0668:
0669:                return isColorModelSet;
0670:            }
0671:
0672:            // XXX Note: ColorModel.isCompatibleRaster() is mentioned below but it
0673:            // should be ColorModel.isCompatibleSampleModel(). This has a bug
0674:            // however (4326636) which is worked around within JAI. The other method
0675:            // is mentioned as it does NOT have a bug.
0676:            /**
0677:             * Constructor.
0678:             *
0679:             * <p> The image's layout is encapsulated in the <code>layout</code>
0680:             * argument.  The variables of the image layout which are not set in
0681:             * the <code>layout</code> parameter are copied from the first source
0682:             * if sources are available.  In the case of the <code>ColorModel</code>,
0683:             * the copy is performed if and only if the <code>ColorModel</code> is
0684:             * compatible with the destination <code>SampleModel</code> and is not
0685:             * set by another higher priority mechanism as described presently.</p>
0686:             *
0687:             * <p> Assuming that there is at least one source, the image's
0688:             * <code>ColorModel</code> will be set by the first applicable means
0689:             * in the following priority-ordered list:
0690:             * <ol>
0691:             * <li><code>null</code> <code>ColorModel</code> from
0692:             * <code>ImageLayout</code>;</li>
0693:             * <li>Non-<code>null</code> <code>ColorModel</code> from
0694:             * <code>ImageLayout</code> if compatible with
0695:             * <code>SampleModel</code> in <code>ImageLayout</code> or if
0696:             * <code>SampleModel</code> in <code>ImageLayout</code> is
0697:             * <code>null</code>;</li>
0698:             * <li>Value returned by <code>ColorModelFactory</code> set via the
0699:             * <code>JAI.KEY_COLOR_MODEL_FACTORY</code> configuration variable if
0700:             * compatible with <code>SampleModel</code>;</li>
0701:             * <li>An instance of a non-<code>IndexColorModel</code> (or
0702:             * <code>null</code> if no compatible non-<code>IndexColorModel</code> 
0703:             * could be generated), if the source has an <code>IndexColorModel</code> 
0704:             * and <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code>
0705:             * is <code>Boolean.TRUE</code>;</li>
0706:             * <li><code>ColorModel</code> of first source if compatible with
0707:             * <code>SampleModel</code>;</li>
0708:             * <li>Value returned by default method specified by the
0709:             * <code>JAI.KEY_DEFAULT_COLOR_MODEL_METHOD</code> configuration variable
0710:             * if <code>JAI.KEY_DEFAULT_COLOR_MODEL_ENABLED</code> is
0711:             * <code>Boolean.TRUE</code>.</li>
0712:             * </ol>
0713:             * If it is not possible to set the <code>ColorModel</code> by any of
0714:             * these means it will remain <code>null</code>.</p>
0715:             *
0716:             * The image's tile dimensions will be set by the first applicable 
0717:             * means in the following priority-ordered list. Note that each tile
0718:             * dimension, the <code>tileWidth</code> and the
0719:             * <code>tileHeight</code>, is considered independently :
0720:             * <ol>
0721:             * <li>Tile dimension set in the <code>ImageLayout</code> (either by
0722:             * the user or the operator itself);</li>
0723:             * <li>Tile dimension of source, if source is non-<code>null</code>.
0724:             * The tile dimension will be clamped to the minimum of that of the
0725:             * source tile dimension and the image's corresponding dimension;</li>
0726:             * <li>Non-<code>null</code> default tile size returned by 
0727:             * <code>JAI.getDefaultTileSize()</code>, if the corresponding
0728:             * image dimension is at least double the default tile size;</li>
0729:             * <li>The dimensions of the image itself;</li>
0730:             * </ol>
0731:             *
0732:             * <p> The <code>sources</code> contains a list of immediate sources
0733:             * of this image.  Elements in the list may not be <code>null</code>.
0734:             * If this image has no sources this argument should be <code>null</code>.
0735:             * This parameter is forwarded unmodified to the <code>PlanarImage</code>
0736:             * constructor.
0737:             *
0738:             * <p> The <code>configuration</code> contains a mapping of configuration
0739:             * variables and image properties.  Entries which have keys of type
0740:             * <code>RenderingHints.Key</code> are taken to be configuration variables.
0741:             * Entries with a key which is either a <code>String</code> or a
0742:             * <code>CaselessStringKey</code> are interpreted as image properties.
0743:             * This parameter is forwarded unmodified to the <code>PlanarImage</code>
0744:             * constructor.
0745:             *
0746:             * <p> This image class recognizes the configuration variables referenced
0747:             * by the following keys:
0748:             *
0749:             * <ul>
0750:             * <li> <code>JAI.KEY_TILE_CACHE</code>: specifies the
0751:             * <code>TileCache</code> in which to store the image tiles;
0752:             * if this key is not supplied no tile caching will be performed.
0753:             * <li> <code>JAI.KEY_TILE_CACHE_METRIC</code>: establishes an
0754:             * ordering of tiles stored in the tile cache.  This ordering
0755:             * is used to determine which tiles will be removed first, if
0756:             * a condition causes tiles to be removed from the cache.
0757:             * <li> <code>JAI.KEY_TILE_SCHEDULER</code>: specifies the
0758:             * <code>TileScheduler</code> to use to schedule tile computation;
0759:             * if this key is not supplied the default scheduler will be used.
0760:             * <li> <code>JAI.KEY_COLOR_MODEL_FACTORY</code>: specifies a
0761:             * <code>ColorModelFactory</code> to be used to generate the
0762:             * <code>ColorModel</code> of the image.  If such a callback is
0763:             * provided it will be invoked if and only if either no
0764:             * <code>ImageLayout</code> hint is given, or an <code>ImageLayout</code>
0765:             * hint is given but contains a non-<code>null</code>
0766:             * <code>ColorModel</code> which is incompatible with the image
0767:             * <code>SampleModel</code>.  In other words, such a callback provides
0768:             * the second priority mechanism for setting the <code>ColorModel</code>
0769:             * of the image.</li>
0770:             * <li> <code>JAI.KEY_DEFAULT_COLOR_MODEL_ENABLED</code>: specifies whether
0771:             * a default <code>ColorModel</code> will be derived
0772:             * if none is specified and one cannot be inherited from the first source;
0773:             * if this key is not supplied a default <code>ColorModel</code> will be
0774:             * computed if necessary.
0775:             * <li> <code>JAI.KEY_DEFAULT_COLOR_MODEL_METHOD</code>: specifies the
0776:             * method to be used to compute the default <code>ColorModel</code>;
0777:             * if this key is not supplied and a default <code>ColorModel</code> is
0778:             * required, <code>PlanarImage.createColorModel()</code> will be used to
0779:             * compute it.
0780:             * <li> <code>JAI.KEY_TILE_FACTORY</code>: specifies a
0781:             * {@link TileFactory} to be used to generate the tiles of the
0782:             * image via {@link TileFactory#createTile(SampleModel,Point)}.  If
0783:             * no such configuration variable is given, a new <code>Raster</code>
0784:             * will be created for each image tile.  This behavior may be
0785:             * overridden by subclasses which have alternate means of saving
0786:             * memory, for example as in the case of point operations which
0787:             * may overwrite a source image not referenced by user code. Note
0788:             * that the corresponding instance variable is actually set by
0789:             * the superclass constructor.</li>
0790:             * <li> <code>JAI.KEY_TILE_RECYCLER</code>: specifies a
0791:             * {@link TileRecycler} to be used to recycle the tiles of the
0792:             * image when the <code>dispose()</code> method is invoked.  If
0793:             * such a configuration variable is set, the image has a
0794:             * non-<code>null</code> <code>TileCache</code>, and tile recycling
0795:             * is enabled, then invoking <code>dispose()</code> will cause each
0796:             * of the tiles of this image currently in the cache to be passed to
0797:             * the configured <code>TileRecycler</code></li> via
0798:             * {@link TileRecycler#recycleTile(Raster)}.</li>
0799:             * <li> <code>JAI.KEY_CACHED_TILE_RECYCLING_ENABLED</code>: specifies a
0800:             * <code>Boolean</code> value which indicates whether {#dispose()}
0801:             * should pass to <code>tileRecycler.recycleTile()</code> any image
0802:             * tiles remaining in the cache.</li>
0803:             * </ul>
0804:             *
0805:             * <p> The <code>cobbleSources</code> indicates which one of the two
0806:             * variants of the <code>computeRect</code> method should be called.
0807:             * If a subclass does not follow the default tile computation scheme,
0808:             * then this argument may be irrelevant.
0809:             *
0810:             * @param layout  The layout of this image.
0811:             * @param sources  The immediate sources of this image.
0812:             * @param configuration Configurable attributes of the image including
0813:             *        configuration variables indexed by
0814:             *        <code>RenderingHints.Key</code>s and image properties indexed
0815:             *        by <code>String</code>s or <code>CaselessStringKey</code>s.
0816:             *        This parameter may be <code>null</code>.
0817:             * @param cobbleSources  Indicates which variant of the
0818:             *        <code>computeRect</code> method should be called.
0819:             *
0820:             * @throws IllegalArgumentException  If <code>sources</code>
0821:             *         is non-<code>null</code> and any object in
0822:             *         <code>sources</code> is <code>null</code>.
0823:             * @throws RuntimeException If default <code>ColorModel</code> setting
0824:             *         is enabled via a hint in the configuration <code>Map</code>
0825:             *         and the supplied <code>Method</code> does not conform to the
0826:             *         requirements stated in the <code>JAI</code> class for the
0827:             *         hint key <code>KEY_DEFAULT_COLOR_MODEL_METHOD</code>.
0828:             *
0829:             * @since JAI 1.1
0830:             */
0831:            public OpImage(Vector sources, ImageLayout layout,
0832:                    Map configuration, boolean cobbleSources) {
0833:                super (layoutHelper(layout, sources, configuration), sources,
0834:                        configuration);
0835:
0836:                if (configuration != null) {
0837:                    // Get the cache from the configuration map.
0838:                    Object cacheConfig = configuration.get(JAI.KEY_TILE_CACHE);
0839:
0840:                    // Ensure that it is a TileCache instance with positive capacity.
0841:                    if (cacheConfig != null
0842:                            && cacheConfig instanceof  TileCache
0843:                            && ((TileCache) cacheConfig).getMemoryCapacity() > 0) {
0844:                        cache = (TileCache) cacheConfig;
0845:                    }
0846:
0847:                    // Get the scheduler from the configuration map.
0848:                    Object schedulerConfig = configuration
0849:                            .get(JAI.KEY_TILE_SCHEDULER);
0850:
0851:                    // Ensure that it is a TileScheduler instance.
0852:                    if (schedulerConfig != null
0853:                            && schedulerConfig instanceof  TileScheduler) {
0854:                        scheduler = (TileScheduler) schedulerConfig;
0855:                    }
0856:
0857:                    try {
0858:                        // Test whether the TileScheduler is the default type.
0859:                        Class sunScheduler = Class
0860:                                .forName("com.sun.media.jai.util.SunTileScheduler");
0861:
0862:                        isSunTileScheduler = sunScheduler.isInstance(scheduler);
0863:                    } catch (Exception e) {
0864:                        // Deliberately ignore any Exceptions.
0865:                    }
0866:
0867:                    // Get the tile metric (cost or priority, for example)
0868:                    tileCacheMetric = configuration
0869:                            .get(JAI.KEY_TILE_CACHE_METRIC);
0870:
0871:                    // Set up cached tile recycling flag.
0872:                    Object recyclingEnabledValue = configuration
0873:                            .get(JAI.KEY_CACHED_TILE_RECYCLING_ENABLED);
0874:                    if (recyclingEnabledValue instanceof  Boolean) {
0875:                        isCachedTileRecyclingEnabled = ((Boolean) recyclingEnabledValue)
0876:                                .booleanValue();
0877:                    }
0878:
0879:                    // Set up the TileRecycler.
0880:                    Object recyclerValue = configuration
0881:                            .get(JAI.KEY_TILE_RECYCLER);
0882:                    if (recyclerValue instanceof  TileRecycler) {
0883:                        tileRecycler = (TileRecycler) recyclerValue;
0884:                    }
0885:                }
0886:
0887:                this .cobbleSources = cobbleSources;
0888:            }
0889:
0890:            /**
0891:             * A <code>TileComputationListener</code> to pass to the
0892:             * <code>TileScheduler</code> to intercept method calls such that the
0893:             * computed tiles are added to the <code>TileCache</code> of the image.
0894:             */
0895:            private class TCL implements  TileComputationListener {
0896:                OpImage opImage;
0897:
0898:                private TCL(OpImage opImage) {
0899:                    this .opImage = opImage;
0900:                }
0901:
0902:                public void tileComputed(Object eventSource,
0903:                        TileRequest[] requests, PlanarImage image, int tileX,
0904:                        int tileY, Raster tile) {
0905:                    if (image == opImage) {
0906:                        // Cache the tile.
0907:                        addTileToCache(tileX, tileY, tile);
0908:                    }
0909:                }
0910:
0911:                public void tileCancelled(Object eventSource,
0912:                        TileRequest[] requests, PlanarImage image, int tileX,
0913:                        int tileY) {
0914:                    // Do nothing.
0915:                }
0916:
0917:                public void tileComputationFailure(Object eventSource,
0918:                        TileRequest[] requests, PlanarImage image, int tileX,
0919:                        int tileY, Throwable situation) {
0920:                    // Do nothing.
0921:                }
0922:            }
0923:
0924:            /**
0925:             * Stores a <code>RenderedImage</code> in a <code>Vector</code>.
0926:             *
0927:             * @param image The image to be stored in the <code>Vector</code>.
0928:             *
0929:             * @return A <code>Vector</code> containing the image.
0930:             *
0931:             * @throws IllegalArgumentException if <code>image</code> is
0932:             * <code>null</code>.
0933:             *
0934:             * @since JAI 1.1
0935:             */
0936:            protected static Vector vectorize(RenderedImage image) {
0937:                if (image == null) {
0938:                    throw new IllegalArgumentException(JaiI18N
0939:                            .getString("OpImage3"));
0940:                }
0941:                Vector v = new Vector(1);
0942:                v.addElement(image);
0943:                return v;
0944:            }
0945:
0946:            /**
0947:             * Stores two <code>RenderedImage</code>s in a <code>Vector</code>.
0948:             *
0949:             * @param image1 The first image to be stored in the <code>Vector</code>.
0950:             * @param image2 The second image to be stored in the <code>Vector</code>.
0951:             *
0952:             * @return A <code>Vector</code> containing the images.
0953:             *
0954:             * @throws IllegalArgumentException if <code>image1</code> or
0955:             * <code>image2</code> is <code>null</code>.
0956:             *
0957:             * @since JAI 1.1
0958:             */
0959:            protected static Vector vectorize(RenderedImage image1,
0960:                    RenderedImage image2) {
0961:                if (image1 == null || image2 == null) {
0962:                    throw new IllegalArgumentException(JaiI18N
0963:                            .getString("OpImage3"));
0964:                }
0965:                Vector v = new Vector(2);
0966:                v.addElement(image1);
0967:                v.addElement(image2);
0968:                return v;
0969:            }
0970:
0971:            /**
0972:             * Stores three <code>RenderedImage</code>s in a <code>Vector</code>.
0973:             *
0974:             * @param image1 The first image to be stored in the <code>Vector</code>.
0975:             * @param image2 The second image to be stored in the <code>Vector</code>.
0976:             * @param image3 The third image to be stored in the <code>Vector</code>.
0977:             *
0978:             * @return A <code>Vector</code> containing the images.
0979:             *
0980:             * @throws IllegalArgumentException if <code>image1</code> or
0981:             * <code>image2</code> or <code>image3</code> is <code>null</code>.
0982:             *
0983:             * @since JAI 1.1
0984:             */
0985:            protected static Vector vectorize(RenderedImage image1,
0986:                    RenderedImage image2, RenderedImage image3) {
0987:                if (image1 == null || image2 == null || image3 == null) {
0988:                    throw new IllegalArgumentException(JaiI18N
0989:                            .getString("OpImage3"));
0990:                }
0991:                Vector v = new Vector(3);
0992:                v.addElement(image1);
0993:                v.addElement(image2);
0994:                v.addElement(image3);
0995:                return v;
0996:            }
0997:
0998:            /**
0999:             * Checks the source <code>Vector</code>.
1000:             *
1001:             * <p>Checks whether the <code>sources</code> parameter is <code>null</code>
1002:             * and optionally whether all elements are non-<code>null</code>.
1003:             *
1004:             * @param sources The source <code>Vector</code>.
1005:             * @param checkElements Whether the elements are to be checked.
1006:             *
1007:             * @return The <code>sources</code> parameter unmodified.
1008:             *
1009:             * @throws IllegalArgumentException  If <code>sources</code>
1010:             *         is <code>null</code>.
1011:             * @throws IllegalArgumentException  If <code>checkElements</code>
1012:             *         is <code>true</code>, <code>sources</code>
1013:             *         is non-<code>null</code> and any object in
1014:             *         <code>sources</code> is <code>null</code>.
1015:             */
1016:            static Vector checkSourceVector(Vector sources,
1017:                    boolean checkElements) {
1018:                // Check for null source Vector.
1019:                if (sources == null) {
1020:                    throw new IllegalArgumentException(JaiI18N
1021:                            .getString("OpImage2"));
1022:                }
1023:
1024:                if (checkElements) {
1025:                    // Check Vector elements.
1026:                    int numSources = sources.size();
1027:                    for (int i = 0; i < numSources; i++) {
1028:                        // Check for null element.
1029:                        if (sources.get(i) == null) {
1030:                            throw new IllegalArgumentException(JaiI18N
1031:                                    .getString("OpImage3"));
1032:                        }
1033:                    }
1034:                }
1035:
1036:                return sources;
1037:            }
1038:
1039:            /**
1040:             * Returns the tile cache object of this image by reference.
1041:             * If this image does not have a tile cache, this method returns
1042:             * <code>null</code>.
1043:             *
1044:             * @since JAI 1.1
1045:             */
1046:            public TileCache getTileCache() {
1047:                return cache;
1048:            }
1049:
1050:            /**
1051:             * Sets the tile cache object of this image.  A <code>null</code>
1052:             * input indicates that this image should have no tile cache and
1053:             * subsequently computed tiles will not be cached.
1054:             *
1055:             * <p> The existing cache object is informed to release all the
1056:             * currently cached tiles of this image.
1057:             *
1058:             * @param cache  A cache object to be used for caching this image's
1059:             *        tiles, or <code>null</code> if no tile caching is desired.
1060:             */
1061:            public void setTileCache(TileCache cache) {
1062:                if (this .cache != null) {
1063:                    this .cache.removeTiles(this );
1064:                }
1065:                this .cache = cache;
1066:            }
1067:
1068:            /**
1069:             * Retrieves a tile from the tile cache.  If this image does not
1070:             * have a tile cache, or the requested tile is not currently in
1071:             * the cache, this method returns <code>null</code>.
1072:             *
1073:             * @param tileX  The X index of the tile.
1074:             * @param tileY  The Y index of the tile.
1075:             *
1076:             * @return The requested tile as a <code>Raster</code> or
1077:             *         <code>null</code>.
1078:             */
1079:            protected Raster getTileFromCache(int tileX, int tileY) {
1080:                return cache != null ? cache.getTile(this , tileX, tileY) : null;
1081:            }
1082:
1083:            /**
1084:             * Adds a tile to the tile cache.  If this image does not have
1085:             * a tile cache, this method does nothing.
1086:             *
1087:             * @param tileX  The X index of the tile.
1088:             * @param tileY  The Y index of the tile.
1089:             * @param tile  The tile to be added to the cache.
1090:             */
1091:            protected void addTileToCache(int tileX, int tileY, Raster tile) {
1092:                if (cache != null) {
1093:                    cache.add(this , tileX, tileY, tile, tileCacheMetric);
1094:                }
1095:            }
1096:
1097:            /**
1098:             * Returns the <code>tileCacheMetric</code> instance variable by reference.
1099:             *
1100:             * @since JAI 1.1
1101:             */
1102:            public Object getTileCacheMetric() {
1103:                return tileCacheMetric;
1104:            }
1105:
1106:            /**
1107:             * Returns a tile of this image as a <code>Raster</code>.  If the
1108:             * requested tile is completely outside of this image's bounds,
1109:             * this method returns <code>null</code>.
1110:             *
1111:             * <p> This method attempts to retrieve the requested tile from the
1112:             * cache.  If the tile is not currently in the cache, it schedules
1113:             * the tile for computation and adds it to the cache once the tile
1114:             * has been computed.
1115:             *
1116:             * <p> If a subclass overrides this method, then it needs to handle
1117:             * tile caching and scheduling.  It should also override
1118:             * <code>computeTile()</code> which may be invoked directly by the
1119:             * <code>TileScheduler</code>.
1120:             *
1121:             * @param tileX  The X index of the tile.
1122:             * @param tileY  The Y index of the tile.
1123:             */
1124:            public Raster getTile(int tileX, int tileY) {
1125:                Raster tile = null; // the requested tile, to be returned
1126:
1127:                // Make sure the requested tile is inside this image's boundary.
1128:                if (tileX >= getMinTileX() && tileX <= getMaxTileX()
1129:                        && tileY >= getMinTileY() && tileY <= getMaxTileY()) {
1130:                    // Check if tile is available in the cache.
1131:                    tile = getTileFromCache(tileX, tileY);
1132:
1133:                    if (tile == null) { // tile not in cache
1134:                        try {
1135:                            tile = scheduler.scheduleTile(this , tileX, tileY);
1136:                        } catch (OutOfMemoryError e) {
1137:                            // Empty the cache and call System.gc()
1138:                            if (cache != null) {
1139:                                cache.flush();
1140:                                System.gc(); //slow
1141:                            }
1142:
1143:                            // Need to reissue the tile scheduling.
1144:                            tile = scheduler.scheduleTile(this , tileX, tileY);
1145:                        }
1146:
1147:                        // Cache the result tile.
1148:                        addTileToCache(tileX, tileY, tile);
1149:                    }
1150:                }
1151:
1152:                return tile;
1153:            }
1154:
1155:            /**
1156:             * Computes the image data of a tile.
1157:             *
1158:             * <p> When a tile is requested via the <code>getTile</code> method
1159:             * and that tile is not in this image's tile cache, this method is
1160:             * invoked by the <code>TileScheduler</code> to compute the data of
1161:             * the new tile.  Even though this method is marked <code>public</code>,
1162:             * it should not be called by the applications directly.  Rather, it
1163:             * is meant to be called by the <code>TileScheduler</code> for the
1164:             * actual computation.
1165:             *
1166:             * <p> The implementation of this method in this class assumes that
1167:             * the requested tile either intersects the image, or is within the
1168:             * image's bounds.  It creates a new <code>Raster</code> to
1169:             * represent the requested tile, then calls one of the two variants
1170:             * of <code>computeRect</code> to calculate the pixels of the
1171:             * tile that are within the image's bounds.  The value of
1172:             * <code>cobbleSources</code> determines which variant of
1173:             * <code>computeRect</code> is invoked, as described in the class
1174:             * comments.
1175:             *
1176:             * <p> Subclasses may provide a more optimized implementation of this
1177:             * method.  If they override this method not to call either variant of
1178:             * <code>computeRect</code>, then neither variant of
1179:             * <code>computeRect</code> needs to be implemented.
1180:             *
1181:             * @param tileX  The X index of the tile.
1182:             * @param tileY  The Y index of the tile.
1183:             */
1184:            public Raster computeTile(int tileX, int tileY) {
1185:                // Create a new Raster.
1186:                WritableRaster dest = createWritableRaster(sampleModel,
1187:                        new Point(tileXToX(tileX), tileYToY(tileY)));
1188:
1189:                // Determine the active area; tile intersects with image's bounds.
1190:                Rectangle destRect = getTileRect(tileX, tileY);
1191:
1192:                int numSources = getNumSources();
1193:
1194:                if (cobbleSources) {
1195:                    Raster[] rasterSources = new Raster[numSources];
1196:                    // Cobble areas
1197:                    for (int i = 0; i < numSources; i++) {
1198:                        PlanarImage source = getSource(i);
1199:                        Rectangle srcRect = mapDestRect(destRect, i);
1200:
1201:                        // If srcRect is empty, set the Raster for this source to
1202:                        // null; otherwise pass srcRect to getData(). If srcRect
1203:                        // is null, getData() will return a Raster containing the
1204:                        // data of the entire source image.
1205:                        rasterSources[i] = srcRect != null && srcRect.isEmpty() ? null
1206:                                : source.getData(srcRect);
1207:                    }
1208:                    computeRect(rasterSources, dest, destRect);
1209:
1210:                    for (int i = 0; i < numSources; i++) {
1211:                        Raster sourceData = rasterSources[i];
1212:                        if (sourceData != null) {
1213:                            PlanarImage source = getSourceImage(i);
1214:
1215:                            // Recycle the source tile
1216:                            if (source.overlapsMultipleTiles(sourceData
1217:                                    .getBounds())) {
1218:                                recycleTile(sourceData);
1219:                            }
1220:                        }
1221:                    }
1222:                } else {
1223:                    PlanarImage[] imageSources = new PlanarImage[numSources];
1224:                    for (int i = 0; i < numSources; i++) {
1225:                        imageSources[i] = getSource(i);
1226:                    }
1227:                    computeRect(imageSources, dest, destRect);
1228:                }
1229:
1230:                return dest;
1231:            }
1232:
1233:            /**
1234:             * Computes a rectangle of output, given <code>Raster</code>
1235:             * sources.  This method should be overridden by
1236:             * <code>OpImage</code> subclasses that make use of cobbled
1237:             * sources, as determined by the setting of the
1238:             * <code>cobbleSources</code> constructor argument to this class.
1239:             *
1240:             * <p> The source <code>Raster</code>s are guaranteed to include
1241:             * at least the area specified by <code>mapDestRect(destRect)</code>
1242:             * unless this area is empty or does not intersect the corresponding
1243:             * source in which case the source <code>Raster</code>
1244:             * will be <code>null</code>.  Only the specified destination region
1245:             * should be written.</p>
1246:             *
1247:             * <p> Since the subclasses of <code>OpImage</code> may choose
1248:             * between the cobbling and non-cobbling versions of
1249:             * <code>computeRect</code>, it is not possible to leave this
1250:             * method abstract in <code>OpImage</code>.  Instead, a default
1251:             * implementation is provided that throws a
1252:             * <code>RuntimeException</code>.</p>
1253:             *
1254:             * @param sources an array of source <code>Raster</code>s, one per
1255:             *        source image.
1256:             * @param dest a <code>WritableRaster</code> to be filled in.
1257:             * @param destRect the <code>Rectangle</code> within the
1258:             *        destination to be written.
1259:             *
1260:             * @throws RuntimeException  If this method is invoked on the subclass
1261:             *         that sets <code>cobbleSources</code> to <code>true</code>
1262:             *         but does not supply an implementation of this method.
1263:             */
1264:            protected void computeRect(Raster[] sources, WritableRaster dest,
1265:                    Rectangle destRect) {
1266:                String className = this .getClass().getName();
1267:                throw new RuntimeException(className + " "
1268:                        + JaiI18N.getString("OpImage0"));
1269:            }
1270:
1271:            /**
1272:             * Computes a rectangle of output, given <code>PlanarImage</code>
1273:             * sources.  This method should be overridden by
1274:             * <code>OpImage</code> subclasses that do not require cobbled
1275:             * sources; typically they will instantiate iterators to perform
1276:             * source access, but they may access sources directly (via the
1277:             * <code>SampleModel</code>/<code>DataBuffer</code> interfaces) if
1278:             * they wish.
1279:             *
1280:             * <p> Since the subclasses of <code>OpImage</code> may choose
1281:             * between the cobbling and non-cobbling versions of
1282:             * <code>computeRect</code>, it is not possible to leave this
1283:             * method abstract in <code>OpImage</code>.  Instead, a default
1284:             * implementation is provided that throws a
1285:             * <code>RuntimeException</code>.
1286:             *
1287:             * @param sources an array of <code>PlanarImage</code> sources.
1288:             * @param dest a <code>WritableRaster</code> to be filled in.
1289:             * @param destRect the <code>Rectangle</code> within the
1290:             * destination to be written.
1291:             *
1292:             * @throws RuntimeException  If this method is invoked on the subclass
1293:             *         that sets <code>cobbleSources</code> to <code>false</code>
1294:             *         but does not supply an implementation of this method.
1295:             */
1296:            protected void computeRect(PlanarImage[] sources,
1297:                    WritableRaster dest, Rectangle destRect) {
1298:                String className = this .getClass().getName();
1299:                throw new RuntimeException(className + " "
1300:                        + JaiI18N.getString("OpImage1"));
1301:            }
1302:
1303:            /**
1304:             * Returns a list of indices of the tiles of a given source image
1305:             * that may be required in order to compute a given tile.
1306:             * Ideally, only tiles that will be requested by means of calls to
1307:             * the source's <code>getTile()</code> method should be reported.
1308:             * The default implementation uses <code>mapDestRect()</code> to
1309:             * obtain a conservative estimate.
1310:             *
1311:             * <p> If no dependencies exist, this method returns
1312:             * <code>null</code>.
1313:             *
1314:             * <p> This method may be used by optimized implementations of JAI
1315:             * in order to predict future work and create an optimized
1316:             * schedule for performing it.
1317:             *
1318:             * <p> A given <code>OpImage</code> may mix calls to
1319:             * <code>getTile()</code> with calls to other methods such as
1320:             * <code>getData()</code> and <code>copyData()</code> in order to
1321:             * avoid requesting entire tiles where only a small portion is
1322:             * needed.  In such a case, this method may be overridden to
1323:             * provide a more accurate estimate of the set of
1324:             * <code>getTile()</code> calls that will actually be performed.
1325:             *
1326:             * @param tileX the X index of the tile.
1327:             * @param tileY the Y index of the tile.
1328:             * @param sourceIndex the index of the source image.
1329:             *
1330:             * @return An array of <code>Point</code>s indicating the source
1331:             *         tile dependencies.
1332:             *
1333:             * @throws IllegalArgumentException  If <code>sourceIndex</code> is
1334:             *         negative or greater than the index of the last source.
1335:             */
1336:            public Point[] getTileDependencies(int tileX, int tileY,
1337:                    int sourceIndex) {
1338:                if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
1339:                    // Specified source does not exist for this image.
1340:                    throw new IllegalArgumentException(JaiI18N
1341:                            .getString("Generic1"));
1342:                }
1343:
1344:                Rectangle rect = getTileRect(tileX, tileY);
1345:                if (rect.isEmpty()) {
1346:                    // The tile is outside of the image bounds.
1347:                    return null;
1348:                }
1349:
1350:                // Returns a list of tiles that belong to the source specified by
1351:                // the <code>sourceIndex</code> argument, which are need to compute
1352:                // the pixels within the rectangle region specified by the
1353:                // <code>rect</code> argument of this image.
1354:                //
1355:                // This method uses <code>mapDestRect</code> to conservatively
1356:                // determine the source region required.  However, only those tiles
1357:                // actually inside the source image bound are returned.  If the
1358:                // region of interest maps completely outside of the source image,
1359:                // <code>null</code> is returned.
1360:                PlanarImage src = getSource(sourceIndex);
1361:                Rectangle srcRect = mapDestRect(rect, sourceIndex);
1362:
1363:                int minTileX = src.XToTileX(srcRect.x);
1364:                int maxTileX = src.XToTileX(srcRect.x + srcRect.width - 1);
1365:
1366:                int minTileY = src.YToTileY(srcRect.y);
1367:                int maxTileY = src.YToTileY(srcRect.y + srcRect.height - 1);
1368:
1369:                // Make sure the tiles are really inside the source image.
1370:                minTileX = Math.max(minTileX, src.getMinTileX());
1371:                maxTileX = Math.min(maxTileX, src.getMaxTileX());
1372:
1373:                minTileY = Math.max(minTileY, src.getMinTileY());
1374:                maxTileY = Math.min(maxTileY, src.getMaxTileY());
1375:
1376:                int numXTiles = maxTileX - minTileX + 1;
1377:                int numYTiles = maxTileY - minTileY + 1;
1378:                if (numXTiles <= 0 || numYTiles <= 0) {
1379:                    // The tile maps outside of source image bound.
1380:                    return null;
1381:                }
1382:
1383:                Point[] ret = new Point[numYTiles * numXTiles];
1384:                int i = 0;
1385:
1386:                for (int y = minTileY; y <= maxTileY; y++) {
1387:                    for (int x = minTileX; x <= maxTileX; x++) {
1388:                        ret[i++] = new Point(x, y);
1389:                    }
1390:                }
1391:
1392:                return ret;
1393:            }
1394:
1395:            /**
1396:             * Computes the tiles indicated by the given tile indices.  This
1397:             * call is preferable to a series of <code>getTile()</code> calls
1398:             * because certain implementations can make optimizations based on
1399:             * the knowledge that multiple tiles are being asked for at once.
1400:             *
1401:             * <p> The implementation of this method in this class uses multiple
1402:             * threads to compute multiple tiles at a time.
1403:             *
1404:             * @param tileIndices An array of <code>Point</code>s representing
1405:             *        tile indices.
1406:             *
1407:             * @return An array of <code>Raster</code>s containing the tiles
1408:             *         corresponding to the given tile indices.
1409:             *
1410:             * @throws IllegalArgumentException  If <code>tileIndices</code> is
1411:             *         <code>null</code>.
1412:             */
1413:            public Raster[] getTiles(Point[] tileIndices) {
1414:                if (tileIndices == null) {
1415:                    throw new IllegalArgumentException(JaiI18N
1416:                            .getString("Generic0"));
1417:                }
1418:
1419:                int numTiles = tileIndices.length; // number of tiles requested
1420:
1421:                // The requested tiles, to be returned.
1422:                Raster[] tiles = new Raster[numTiles];
1423:
1424:                // Indicator for those tiles that actually need to be computed.
1425:                boolean[] computeTiles = new boolean[numTiles];
1426:
1427:                int minTileX = getMinTileX();
1428:                int maxTileX = getMaxTileX();
1429:                int minTileY = getMinTileY();
1430:                int maxTileY = getMaxTileY();
1431:
1432:                int count = 0; // number of tiles need to be computed
1433:
1434:                for (int i = 0; i < numTiles; i++) {
1435:                    int tileX = tileIndices[i].x;
1436:                    int tileY = tileIndices[i].y;
1437:
1438:                    // Make sure the tile is inside image boundary.
1439:                    if (tileX >= minTileX && tileX <= maxTileX
1440:                            && tileY >= minTileY && tileY <= maxTileY) {
1441:                        // Check if tile is available in the cache.
1442:                        tiles[i] = getTileFromCache(tileX, tileY);
1443:
1444:                        if (tiles[i] == null) {
1445:                            // Tile not in cache. needs computation.
1446:                            computeTiles[i] = true;
1447:                            count++;
1448:                        }
1449:                    }
1450:                }
1451:
1452:                if (count > 0) { // need to compute some tiles
1453:                    if (count == numTiles) {
1454:                        // None of the tiles is in cache.
1455:                        tiles = scheduler.scheduleTiles(this , tileIndices);
1456:
1457:                        if (cache != null) { // cache these tiles
1458:                            if (cache != null) {
1459:                                for (int i = 0; i < numTiles; i++) {
1460:                                    cache.add(this , tileIndices[i].x,
1461:                                            tileIndices[i].y, tiles[i],
1462:                                            tileCacheMetric);
1463:                                }
1464:                            }
1465:                        }
1466:
1467:                    } else {
1468:                        // Only schedule those tiles not in cache for computation.
1469:                        Point[] indices = new Point[count];
1470:                        count = 0;
1471:                        for (int i = 0; i < numTiles; i++) {
1472:                            if (computeTiles[i]) {
1473:                                indices[count++] = tileIndices[i];
1474:                            }
1475:                        }
1476:
1477:                        // Schedule needed tiles and return.
1478:                        Raster[] newTiles = scheduler.scheduleTiles(this ,
1479:                                indices);
1480:
1481:                        count = 0;
1482:                        for (int i = 0; i < numTiles; i++) {
1483:                            if (computeTiles[i]) {
1484:                                tiles[i] = newTiles[count++];
1485:                                addTileToCache(tileIndices[i].x,
1486:                                        tileIndices[i].y, tiles[i]);
1487:                            }
1488:                        }
1489:                    }
1490:                }
1491:
1492:                return tiles;
1493:            }
1494:
1495:            private static TileComputationListener[] prependListener(
1496:                    TileComputationListener[] listeners,
1497:                    TileComputationListener listener) {
1498:                if (listeners == null) {
1499:                    return new TileComputationListener[] { listener };
1500:                }
1501:
1502:                TileComputationListener[] newListeners = new TileComputationListener[listeners.length + 1];
1503:                newListeners[0] = listener;
1504:                System.arraycopy(listeners, 0, newListeners, 1,
1505:                        listeners.length);
1506:
1507:                return newListeners;
1508:            }
1509:
1510:            /**
1511:             * Returns an array of indices of tiles which are not cached or
1512:             * <code>null</code> if all are cached.
1513:             */
1514:            /* XXX
1515:            private Point[] pruneIndices(Point[] tileIndices) {
1516:                if(true)return tileIndices;//XXX
1517:                int numIndices = tileIndices.length;
1518:
1519:                ArrayList uncachedIndices = new ArrayList(numIndices);
1520:
1521:                for(int i = 0; i < numIndices; i++) {
1522:                    Point p = tileIndices[i];
1523:                    if(getTileFromCache(p.x, p.y) == null) {
1524:                        uncachedIndices.add(p);
1525:                    }
1526:                }
1527:
1528:                int numUncached = uncachedIndices.size();
1529:                return numUncached > 0 ?
1530:                    (Point[])uncachedIndices.toArray(new Point[numUncached]) : null;
1531:            }
1532:             */
1533:
1534:            /**
1535:             * Queues a list of tiles for computation.  Registered listeners will
1536:             * be notified after each tile has been computed.  The event source
1537:             * parameter passed to such listeners will be the <code>TileScheduler</code>
1538:             * and the image parameter will be this image.
1539:             *
1540:             * @param tileIndices A list of tile indices indicating which tiles
1541:             *        to schedule for computation.
1542:             * @throws IllegalArgumentException  If <code>tileIndices</code> is
1543:             *         <code>null</code>.
1544:             *
1545:             * @since JAI 1.1
1546:             */
1547:            public TileRequest queueTiles(Point[] tileIndices) {
1548:                if (tileIndices == null) {
1549:                    throw new IllegalArgumentException(JaiI18N
1550:                            .getString("Generic0"));
1551:                }
1552:
1553:                /* XXX bad idea probably
1554:                // Remove any tile indices corresponding to cached tiles.
1555:                tileIndices = pruneIndices(tileIndices);
1556:
1557:                // Return if no tiles remain, i.e., all are cached.
1558:                if(tileIndices == null) {
1559:                    return;
1560:                }
1561:                 */
1562:
1563:                // Get registered listeners.
1564:                TileComputationListener[] tileListeners = getTileComputationListeners();
1565:
1566:                // Add a listener to cache tiles only if not a SunTileScheduler.
1567:                // The SunTileScheduler caches tiles generated by an OpImage but
1568:                // this is not a requirement of the specification.
1569:                if (!isSunTileScheduler) {
1570:                    // Create a local listener.
1571:                    TileComputationListener localListener = new TCL(this );
1572:
1573:                    // Prepend local listener to array.
1574:                    tileListeners = prependListener(tileListeners,
1575:                            localListener);
1576:                }
1577:
1578:                // Queue the tiles to the scheduler.
1579:                return scheduler
1580:                        .scheduleTiles(this , tileIndices, tileListeners);
1581:            }
1582:
1583:            /**
1584:             * Issue an advisory cancellation request to nullify processing of
1585:             * the indicated tiles via the TileScheduler for this image.  This
1586:             * method should merely forward the request to the associated
1587:             * <code>TileScheduler</code>.
1588:             *
1589:             * @param request The request for which tiles are to be cancelled.
1590:             * @param tileIndices The tiles to be cancelled; may be <code>null</code>.
1591:             *        Any tiles not actually in the <code>TileRequest</code> will be
1592:             *        ignored.
1593:             * @throws IllegalArgumentException  If <code>request</code> is
1594:             *         <code>null</code>.
1595:             *
1596:             * @since JAI 1.1
1597:             */
1598:            public void cancelTiles(TileRequest request, Point[] tileIndices) {
1599:                if (request == null) {
1600:                    throw new IllegalArgumentException(JaiI18N
1601:                            .getString("Generic4"));
1602:                }
1603:                scheduler.cancelTiles(request, tileIndices);
1604:            }
1605:
1606:            /**
1607:             * Hints that the given tiles might be needed in the near future.
1608:             * Some implementations may spawn one or more threads
1609:             * to compute the tiles, while others may ignore the hint.
1610:             *
1611:             * @param tileIndices A list of tile indices indicating which tiles
1612:             *        to prefetch.
1613:             *
1614:             * @throws IllegalArgumentException  If <code>tileIndices</code> is
1615:             *         <code>null</code>.
1616:             */
1617:            public void prefetchTiles(Point[] tileIndices) {
1618:                if (tileIndices == null) {
1619:                    throw new IllegalArgumentException(JaiI18N
1620:                            .getString("Generic0"));
1621:                }
1622:
1623:                /* XXX bad idea probably
1624:                // Remove any tile indices corresponding to cached tiles.
1625:                tileIndices = pruneIndices(tileIndices);
1626:                 */
1627:
1628:                // Return if no tiles remain, i.e., all are cached.
1629:                if (tileIndices == null) {
1630:                    return;
1631:                }
1632:
1633:                // Prefetch any remaining tiles.
1634:                scheduler.prefetchTiles(this , tileIndices);
1635:            }
1636:
1637:            /**
1638:             * Computes the position in the specified source that best
1639:             * matches the supplied destination image position. If it
1640:             * is not possible to compute the requested position,
1641:             * <code>null</code> will be returned. If the point is mapped
1642:             * outside the source bounds, the coordinate value or <code>null</code>
1643:             * may be returned at the discretion of the implementation.
1644:             *
1645:             * <p>Floating-point input and output coordinates are supported,
1646:             * and recommended when possible.  Subclass implementations may
1647:             * however use integer computation if necessary for simplicity.</p>
1648:             *
1649:             * <p>The implementation in this class returns the value of
1650:             * <code>pt</code> in the following code snippet:
1651:             *
1652:             * <pre>
1653:             * Rectangle destRect = new Rectangle((int)destPt.getX(),
1654:             *                                    (int)destPt.getY(),
1655:             *                                    1, 1);
1656:             * Rectangle sourceRect = mapDestRect(destRect, sourceIndex);
1657:             * Point2D pt = (Point2D)destPt.clone();
1658:             * pt.setLocation(sourceRect.x + (sourceRect.width - 1.0)/2.0,
1659:             *                sourceRect.y + (sourceRect.height - 1.0)/2.0);
1660:             * </pre>
1661:             *
1662:             * Subclasses requiring different behavior should override this
1663:             * method.</p>
1664:             *
1665:             * @param destPt the position in destination image coordinates
1666:             * to map to source image coordinates.
1667:             * @param sourceIndex the index of the source image.
1668:             *
1669:             * @return a <code>Point2D</code> of the same class as
1670:             * <code>destPt</code> or <code>null</code>.
1671:             *
1672:             * @throws IllegalArgumentException if <code>destPt</code> is
1673:             * <code>null</code>.
1674:             * @throws IndexOutOfBoundsException if <code>sourceIndex</code> is
1675:             * negative or greater than or equal to the number of sources.
1676:             *
1677:             * @since JAI 1.1.2
1678:             */
1679:            public Point2D mapDestPoint(Point2D destPt, int sourceIndex) {
1680:                if (destPt == null) {
1681:                    throw new IllegalArgumentException(JaiI18N
1682:                            .getString("Generic0"));
1683:                } else if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
1684:                    throw new IndexOutOfBoundsException(JaiI18N
1685:                            .getString("Generic1"));
1686:                }
1687:
1688:                Rectangle destRect = new Rectangle((int) destPt.getX(),
1689:                        (int) destPt.getY(), 1, 1);
1690:
1691:                Rectangle sourceRect = mapDestRect(destRect, sourceIndex);
1692:
1693:                Point2D pt = (Point2D) destPt.clone();
1694:                pt.setLocation(sourceRect.x + (sourceRect.width - 1.0) / 2.0,
1695:                        sourceRect.y + (sourceRect.height - 1.0) / 2.0);
1696:
1697:                return pt;
1698:            }
1699:
1700:            /**
1701:             * Computes the position in the destination that best
1702:             * matches the supplied source image position. If it
1703:             * is not possible to compute the requested position,
1704:             * <code>null</code> will be returned. If the point is mapped
1705:             * outside the destination bounds, the coordinate value or
1706:             * <code>null</code> may be returned at the discretion of the
1707:             * implementation.
1708:             *
1709:             * <p>Floating-point input and output coordinates are supported,
1710:             * and recommended when possible.  Subclass implementations may
1711:             * however use integer computation if necessary for simplicity.</p>
1712:             *
1713:             * <p>The implementation in this class returns the value of
1714:             * <code>pt</code> in the following code snippet:
1715:             *
1716:             * <pre>
1717:             * Rectangle sourceRect = new Rectangle((int)sourcePt.getX(),
1718:             *                                      (int)sourcePt.getY(),
1719:             *                                      1, 1);
1720:             * Rectangle destRect = mapSourceRect(sourceRect, sourceIndex);
1721:             * Point2D pt = (Point2D)sourcePt.clone();
1722:             * pt.setLocation(destRect.x + (destRect.width - 1.0)/2.0,
1723:             *                destRect.y + (destRect.height - 1.0)/2.0);
1724:             * </pre>
1725:             *
1726:             * @param sourcePt the position in source image coordinates
1727:             * to map to destination image coordinates.
1728:             * @param sourceIndex the index of the source image.
1729:             *
1730:             * @return a <code>Point2D</code> of the same class as
1731:             * <code>sourcePt</code> or <code>null</code>.
1732:             *
1733:             * @throws IllegalArgumentException if <code>sourcePt</code> is
1734:             * <code>null</code>.
1735:             * @throws IndexOutOfBoundsException if <code>sourceIndex</code> is
1736:             * negative or greater than or equal to the number of sources.
1737:             *
1738:             * @since JAI 1.1.2
1739:             */
1740:            public Point2D mapSourcePoint(Point2D sourcePt, int sourceIndex) {
1741:                if (sourcePt == null) {
1742:                    throw new IllegalArgumentException(JaiI18N
1743:                            .getString("Generic0"));
1744:                } else if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
1745:                    throw new IndexOutOfBoundsException(JaiI18N
1746:                            .getString("Generic1"));
1747:                }
1748:
1749:                Rectangle sourceRect = new Rectangle((int) sourcePt.getX(),
1750:                        (int) sourcePt.getY(), 1, 1);
1751:
1752:                Rectangle destRect = mapSourceRect(sourceRect, sourceIndex);
1753:
1754:                // Return null of destination rectangle is not computable.
1755:                if (destRect == null) {
1756:                    return null;
1757:                }
1758:
1759:                Point2D pt = (Point2D) sourcePt.clone();
1760:                pt.setLocation(destRect.x + (destRect.width - 1.0) / 2.0,
1761:                        destRect.y + (destRect.height - 1.0) / 2.0);
1762:
1763:                return pt;
1764:            }
1765:
1766:            /**
1767:             * Returns a conservative estimate of the destination region that
1768:             * can potentially be affected by the pixels of a rectangle of a
1769:             * given source.  An empty <code>Rectangle</code> may be returned
1770:             * if the destination is unaffected by the contents of the source
1771:             * rectangle.  This is distinct from a <code>null</code> return value
1772:             * which serves rather to indicate that it is not possible to
1773:             * determine the bounds of the affected region.  The safest
1774:             * interpretation of a <code>null</code> return value is that the
1775:             * entire destination might be affected by any pixel within the
1776:             * given source rectangle.
1777:             *
1778:             * @param sourceRect  The <code>Rectangle</code> in source coordinates.
1779:             * @param sourceIndex  The index of the source image.
1780:             *
1781:             * @return A <code>Rectangle</code> indicating the potentially
1782:             *         affected destination region, or <code>null</code> if
1783:             *         the region is unknown.
1784:             *
1785:             * @throws IllegalArgumentException  If the source index is
1786:             *         negative or greater than that of the last source.
1787:             * @throws IllegalArgumentException  If <code>sourceRect</code> is
1788:             *         <code>null</code>.
1789:             */
1790:            public abstract Rectangle mapSourceRect(Rectangle sourceRect,
1791:                    int sourceIndex);
1792:
1793:            /**
1794:             * Returns a conservative estimate of the region of a specified
1795:             * source that is required in order to compute the pixels of a
1796:             * given destination rectangle.  The computation may as appropriate
1797:             * clip the mapped <code>Rectangle</code> to the actual bounds of the
1798:             * source or may treat the source as having infinite extent.
1799:             * It is therefore the responsibility of the invoking
1800:             * object to constrain the region in accordance with its needs.
1801:             * Returning an empty <code>Rectangle</code> should indicate that
1802:             * the data of the source image in question are not required for the
1803:             * computation of the specified destination region.  If the entire
1804:             * source image might be required to compute this destination
1805:             * region, then <code>getSourceImage(sourceIndex).getBounds()</code>
1806:             * should be returned.
1807:             *
1808:             * <p> To illustrate the issue of whether the source should be thought
1809:             * to have infinite extent, consider the case wherein computing a
1810:             * destination pixel requires multiple source pixels of context.  At
1811:             * the source image boundary, these pixels might only be available if the
1812:             * source data were extrapolated, e.g., using a {@link BorderExtender}.
1813:             * If such an extender were available, destination pixels could be
1814:             * computed even if they mapped to a region on the source boundary so
1815:             * in this case the source could be considered to have infinite extent.
1816:             * If no such extender were available, only destination pixels with
1817:             * source context contained within the source image bounds could be
1818:             * considered so that it might be preferable to clip the rectangle to
1819:             * the source bounds.</p>
1820:             *
1821:             * @param destRect  The <code>Rectangle</code> in destination coordinates.
1822:             * @param sourceIndex  The index of the source image.
1823:             *
1824:             * @return A non-<code>null</code> <code>Rectangle</code> indicating
1825:             *         the required source region.
1826:             *
1827:             * @throws IllegalArgumentException  If the source index is
1828:             *         negative or greater than that of the last source.
1829:             * @throws IllegalArgumentException  If <code>destRect</code> is
1830:             *         <code>null</code>.
1831:             */
1832:            public abstract Rectangle mapDestRect(Rectangle destRect,
1833:                    int sourceIndex);
1834:
1835:            /**
1836:             * Returns one of <code>OP_COMPUTE_BOUND</code>,
1837:             * <code>OP_IO_BOUND</code>, or <code>OP_NETWORK_BOUND</code> to
1838:             * indicate how the operation is likely to spend its time.  The
1839:             * answer does not affect the output of the operation, but may
1840:             * allow a scheduler to parallelize the computation of multiple
1841:             * operations more effectively.
1842:             *
1843:             * <p> The implementation of this method in this class
1844:             * returns <code>OP_COMPUTE_BOUND</code>.
1845:             */
1846:            public int getOperationComputeType() {
1847:                return OP_COMPUTE_BOUND;
1848:            }
1849:
1850:            /**
1851:             * Returns <code>true</code> if the <code>OpImage</code> returns an
1852:             * unique <code>Raster</code> object every time <code>computeTile</code>
1853:             * is called.  <code>OpImage</code>s that internally cache
1854:             * <code>Raster</code>s and return them via <code>computeTile</code>
1855:             * should return <code>false</code> for this method.  
1856:             *
1857:             * <p> The implementation of this method in this class always returns
1858:             * <code>true</code>.
1859:             */
1860:            public boolean computesUniqueTiles() {
1861:                return true;
1862:            }
1863:
1864:            /**
1865:             * Uncaches all tiles and calls <code>super.dispose()</code>.
1866:             * If a <code>TileRecycler</code> was defined via the configuration
1867:             * variable <code>JAI.KEY_TILE_RECYCLER</code> when this image was
1868:             * constructed and tile recycling was enabled via the configuration
1869:             * variable <code>JAI.KEY_CACHED_TILE_RECYCLING_ENABLED</code>, then each
1870:             * of this image's tiles which is currently in the cache will be
1871:             * recycled.  This method may be invoked more than once although
1872:             * invocations after the first one may do nothing.
1873:             *
1874:             * <p> The results of referencing an image after a call to
1875:             * <code>dispose()</code> are undefined.</p>
1876:             *
1877:             * @since JAI 1.1.2
1878:             */
1879:            public synchronized void dispose() {
1880:                if (isDisposed) {
1881:                    return;
1882:                }
1883:
1884:                isDisposed = true;
1885:
1886:                if (cache != null) {
1887:                    if (isCachedTileRecyclingEnabled && tileRecycler != null) {
1888:                        Raster[] tiles = cache.getTiles(this );
1889:                        if (tiles != null) {
1890:                            int numTiles = tiles.length;
1891:                            for (int i = 0; i < numTiles; i++) {
1892:                                tileRecycler.recycleTile(tiles[i]);
1893:                            }
1894:                        }
1895:                    }
1896:                    cache.removeTiles(this );
1897:                }
1898:                super .dispose();
1899:            }
1900:
1901:            /**
1902:             * Indicates whether the source with the given index has a
1903:             * <code>BorderExtender</code>. If the source index is out of bounds
1904:             * for the source vector of this <code>OpImage</code> then an
1905:             * <code>ArrayIndexOutOfBoundsException</code> may be thrown.
1906:             *
1907:             * @param sourceIndex The index of the source in question.
1908:             * @return <code>true</code> if the indicated source has an extender.
1909:             *
1910:             * @deprecated as of JAI 1.1.
1911:             */
1912:            public boolean hasExtender(int sourceIndex) {
1913:                if (sourceIndex != 0) {
1914:                    throw new ArrayIndexOutOfBoundsException();
1915:                } else if (this  instanceof  AreaOpImage) {
1916:                    return ((AreaOpImage) this ).getBorderExtender() != null;
1917:                } else if (this  instanceof  GeometricOpImage) {
1918:                    return ((GeometricOpImage) this ).getBorderExtender() != null;
1919:                }
1920:                return false;
1921:            }
1922:
1923:            /**
1924:             * Returns the effective number of bands of an image with a given
1925:             * <code>SampleModel</code> and <code>ColorModel</code>.
1926:             * Normally, this is given by
1927:             * <code>sampleModel.getNumBands()</code>, but for images with an
1928:             * <code>IndexColorModel</code> the effective number of bands is
1929:             * given by <code>colorModel.getNumComponents()</code>, since
1930:             * a single physical sample represents multiple color components.
1931:             *
1932:             * @deprecated as of JAI 1.1.
1933:             */
1934:            public static int getExpandedNumBands(SampleModel sampleModel,
1935:                    ColorModel colorModel) {
1936:                if (colorModel instanceof  IndexColorModel) {
1937:                    return colorModel.getNumComponents();
1938:                } else {
1939:                    return sampleModel.getNumBands();
1940:                }
1941:            }
1942:
1943:            /**
1944:             * Returns the image's format tags to be used with
1945:             * a <code>RasterAccessor</code>.
1946:             *
1947:             * <p> This method will compute and cache the tags the first time
1948:             * it is called on a particular image.  The image's
1949:             * <code>SampleModel</code> and <code>ColorModel</code> must be
1950:             * set to their final values before calling this method.
1951:             *
1952:             * @return An array containing <code>RasterFormatTag</code>s for the
1953:             * sources in the first <code>getNumSources()</code> elements and a
1954:             * <code>RasterFormatTag</code> for the destination in the last element.
1955:             */
1956:            // XXX This method should be removed if we stop using RasterAccessor.
1957:            protected synchronized RasterFormatTag[] getFormatTags() {
1958:                if (formatTags == null) {
1959:                    RenderedImage[] sourceArray = new RenderedImage[getNumSources()];
1960:                    if (sourceArray.length > 0) {
1961:                        getSources().toArray(sourceArray);
1962:                    }
1963:                    formatTags = RasterAccessor.findCompatibleTags(sourceArray,
1964:                            this );
1965:                }
1966:
1967:                return formatTags;
1968:            }
1969:
1970:            /**
1971:             * Returns the value of the instance variable <code>tileRecycler</code>.
1972:             *
1973:             * @since JAI 1.1.2
1974:             */
1975:            public TileRecycler getTileRecycler() {
1976:                return tileRecycler;
1977:            }
1978:
1979:            /**
1980:             * Creates a <code>WritableRaster</code> at the given tile grid position.
1981:             * The superclass method {@link #createWritableRaster(SampleModel,Point)}
1982:             * will be invoked with this image's <code>SampleModel</code> and the
1983:             * location of the specified tile.
1984:             *
1985:             * <p>Subclasses should ideally use this method to create destination
1986:             * tiles as this method will take advantage of any
1987:             * <code>TileFactory</code> specified to the <code>OpImage</code> at
1988:             * construction.</p>
1989:             *
1990:             * @since JAI 1.1.2
1991:             */
1992:            protected final WritableRaster createTile(int tileX, int tileY) {
1993:                return createWritableRaster(sampleModel, new Point(
1994:                        tileXToX(tileX), tileYToY(tileY)));
1995:            }
1996:
1997:            /**
1998:             * A tile recycling convenience method.
1999:             *
2000:             * <p>If <code>tileRecycler</code> is non-<code>null</code>, the call
2001:             * is forwarded to {@link TileRecycler.recycleTile(Raster)}; otherwise
2002:             * the method does nothing.</p>
2003:             *
2004:             * <p>This method is for use by subclasses which create
2005:             * <code>Raster</code>s with limited scope which therefore may easily
2006:             * be identified as safe candidates for recycling.  This might occur
2007:             * for example within
2008:             * {@link #computeRect(Raster[],WritableRaster,Rectangle)} or
2009:             * {@link #computeTile(int,int)} wherein <code>Raster</code>s may be
2010:             * created for use within the method but be eligible for garbage
2011:             * collection once the method is exited.</p>
2012:             *
2013:             * @throws IllegalArgumentException if <code>tile</code> is
2014:             *         <code>null</code>.
2015:             *
2016:             * @since JAI 1.1.2
2017:             */
2018:            protected void recycleTile(Raster tile) {
2019:                if (tile == null)
2020:                    throw new IllegalArgumentException(JaiI18N
2021:                            .getString("Generic0"));
2022:
2023:                if (tileRecycler != null) {
2024:                    tileRecycler.recycleTile(tile);
2025:                }
2026:            }
2027:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.