Source Code Cross Referenced for PointOpImage.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: PointOpImage.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:15 $
0010:         * $State: Exp $
0011:         */
0012:        package javax.media.jai;
0013:
0014:        import java.awt.Point;
0015:        import java.awt.Rectangle;
0016:        import java.awt.image.ColorModel;
0017:        import java.awt.image.ComponentSampleModel;
0018:        import java.awt.image.DataBuffer;
0019:        import java.awt.image.IndexColorModel;
0020:        import java.awt.image.MultiPixelPackedSampleModel;
0021:        import java.awt.image.Raster;
0022:        import java.awt.image.RenderedImage;
0023:        import java.awt.image.SampleModel;
0024:        import java.awt.image.SinglePixelPackedSampleModel;
0025:        import java.awt.image.WritableRaster;
0026:        import java.awt.image.WritableRenderedImage;
0027:        import java.lang.reflect.Method;
0028:        import java.util.Map;
0029:        import java.util.Vector;
0030:        import java.security.AccessController;
0031:        import java.security.PrivilegedAction;
0032:        import javax.media.jai.util.CaselessStringKey;
0033:        import com.sun.media.jai.util.ImageUtil;
0034:        import com.sun.media.jai.util.JDKWorkarounds;
0035:
0036:        /**
0037:         * An abstract base class for image operators that require only the
0038:         * (x, y) pixel from each source image in order to compute the
0039:         * destination pixel (x, y).
0040:         *
0041:         * <p> <code>PointOpImage</code> is intended as a convenient
0042:         * superclass for <code>OpImage</code>s that only need to look at each
0043:         * destination pixel's corresponding source pixels.  Some examples are
0044:         * lookup, contrast adjustment, pixel arithmetic, and color space
0045:         * conversion.
0046:         *
0047:         * @see OpImage
0048:         */
0049:        public abstract class PointOpImage extends OpImage {
0050:
0051:            /* Flag indicating that dispose() has been invoked. */
0052:            private boolean isDisposed = false;
0053:
0054:            /* Flag indicating whether the various flags have been set. */
0055:            private boolean areFieldsInitialized = false;
0056:
0057:            /* Flag indicating that in-place compatibility should be checked. */
0058:            private boolean checkInPlaceOperation = false;
0059:
0060:            /* Flag indicating whether in-place operation is enabled. */
0061:            private boolean isInPlaceEnabled = false;
0062:
0063:            /// BEGIN: Variable fields used only when in-place operation is enabled.
0064:            /* The first source cast to a WritableRenderedImage. */
0065:            private WritableRenderedImage source0AsWritableRenderedImage;
0066:
0067:            /* The first source cast to an OpImage. */
0068:            private OpImage source0AsOpImage;
0069:
0070:            /* Flag indicating whether the first source is a WritableRenderedImage. */
0071:            private boolean source0IsWritableRenderedImage;
0072:            /// END: Variable fields use only when in-place operation is enabled.
0073:
0074:            /* Flag indicating whether the bounds are the same as for all sources. */
0075:            private boolean sameBounds;
0076:
0077:            /* Flag indicating whether the tile grid is the same as for all sources. */
0078:            private boolean sameTileGrid;
0079:
0080:            // END in-place fields.
0081:
0082:            /** Fills in the default layout settings. */
0083:            private static ImageLayout layoutHelper(ImageLayout layout,
0084:                    Vector sources, Map config) {
0085:                int numSources = sources.size();
0086:
0087:                if (numSources < 1) {
0088:                    throw new IllegalArgumentException(JaiI18N
0089:                            .getString("Generic5"));
0090:                }
0091:
0092:                RenderedImage source0 = (RenderedImage) sources.get(0);
0093:                Rectangle isect = new Rectangle(source0.getMinX(), source0
0094:                        .getMinY(), source0.getWidth(), source0.getHeight());
0095:
0096:                Rectangle rect = new Rectangle();
0097:                for (int i = 1; i < numSources; i++) {
0098:                    RenderedImage s = (RenderedImage) sources.get(i);
0099:                    rect.setBounds(s.getMinX(), s.getMinY(), s.getWidth(), s
0100:                            .getHeight());
0101:                    isect = isect.intersection(rect);
0102:                }
0103:
0104:                if (isect.isEmpty()) {
0105:                    throw new IllegalArgumentException(JaiI18N
0106:                            .getString("PointOpImage0"));
0107:                }
0108:
0109:                if (layout == null) {
0110:                    layout = new ImageLayout(isect.x, isect.y, isect.width,
0111:                            isect.height);
0112:                } else {
0113:                    layout = (ImageLayout) layout.clone();
0114:                    if (!layout.isValid(ImageLayout.MIN_X_MASK)) {
0115:                        layout.setMinX(isect.x);
0116:                    }
0117:                    if (!layout.isValid(ImageLayout.MIN_Y_MASK)) {
0118:                        layout.setMinY(isect.y);
0119:                    }
0120:                    if (!layout.isValid(ImageLayout.WIDTH_MASK)) {
0121:                        layout.setWidth(isect.width);
0122:                    }
0123:                    if (!layout.isValid(ImageLayout.HEIGHT_MASK)) {
0124:                        layout.setHeight(isect.height);
0125:                    }
0126:
0127:                    Rectangle r = new Rectangle(layout.getMinX(null), layout
0128:                            .getMinY(null), layout.getWidth(null), layout
0129:                            .getHeight(null));
0130:                    if (r.isEmpty()) {
0131:                        throw new IllegalArgumentException(JaiI18N
0132:                                .getString("PointOpImage1"));
0133:                    }
0134:
0135:                    if (!isect.contains(r)) {
0136:                        throw new IllegalArgumentException(JaiI18N
0137:                                .getString("PointOpImage2"));
0138:                    }
0139:                }
0140:
0141:                // If no SampleModel is given, create a new SampleModel (and perhaps
0142:                // ColorModel) corresponding to the minimum band count and maximum
0143:                // data depth.
0144:                if (numSources > 1
0145:                        && !layout.isValid(ImageLayout.SAMPLE_MODEL_MASK)) {
0146:                    // Determine the min number of bands and max range of data
0147:
0148:                    SampleModel sm = source0.getSampleModel();
0149:                    ColorModel cm = source0.getColorModel();
0150:                    int dtype0 = getAppropriateDataType(sm);
0151:                    int bands0 = getBandCount(sm, cm);
0152:                    int dtype = dtype0;
0153:                    int bands = bands0;
0154:
0155:                    for (int i = 1; i < numSources; i++) {
0156:                        RenderedImage source = (RenderedImage) sources.get(i);
0157:                        sm = source.getSampleModel();
0158:                        cm = source.getColorModel();
0159:                        int sourceBands = getBandCount(sm, cm);
0160:
0161:                        dtype = mergeTypes(dtype, getPixelType(sm));
0162:                        bands = Math.min(bands, sourceBands);
0163:                    }
0164:
0165:                    // Force data type to byte for multi-band bilevel data.
0166:                    if (dtype == PixelAccessor.TYPE_BIT && bands > 1) {
0167:                        dtype = DataBuffer.TYPE_BYTE;
0168:                    }
0169:
0170:                    // Set a new SampleModel if and only if that of source 0 is
0171:                    // not compatible.
0172:                    SampleModel sm0 = source0.getSampleModel();
0173:                    if (dtype != sm0.getDataType()
0174:                            || bands != sm0.getNumBands()) {
0175:                        int tw = layout.getTileWidth(source0);
0176:                        int th = layout.getTileHeight(source0);
0177:                        SampleModel sampleModel;
0178:                        if (dtype == PixelAccessor.TYPE_BIT) {
0179:                            sampleModel = new MultiPixelPackedSampleModel(
0180:                                    DataBuffer.TYPE_BYTE, tw, th, 1);
0181:                        } else {
0182:                            sampleModel = RasterFactory
0183:                                    .createPixelInterleavedSampleModel(dtype,
0184:                                            tw, th, bands);
0185:                        }
0186:
0187:                        layout.setSampleModel(sampleModel);
0188:
0189:                        // Set a new ColorModel only if this one is incompatible.
0190:                        if (cm != null
0191:                                && !JDKWorkarounds.areCompatibleDataModels(
0192:                                        sampleModel, cm)) {
0193:                            cm = ImageUtil.getCompatibleColorModel(sampleModel,
0194:                                    config);
0195:                            layout.setColorModel(cm);
0196:                        }
0197:                    }
0198:                }
0199:
0200:                return layout;
0201:            }
0202:
0203:            /**
0204:             * Returns the pixel type.
0205:             */
0206:            private static int getPixelType(SampleModel sampleModel) {
0207:                return ImageUtil.isBinary(sampleModel) ? PixelAccessor.TYPE_BIT
0208:                        : sampleModel.getDataType();
0209:            }
0210:
0211:            /**
0212:             * Returns the number of bands.
0213:             */
0214:            private static int getBandCount(SampleModel sampleModel,
0215:                    ColorModel colorModel) {
0216:                if (ImageUtil.isBinary(sampleModel)) {
0217:                    return 1;
0218:                } else if (colorModel instanceof  IndexColorModel) {
0219:                    return colorModel.getNumComponents();
0220:                } else {
0221:                    return sampleModel.getNumBands();
0222:                }
0223:            }
0224:
0225:            /**
0226:             * Determine the appropriate data type for the SampleModel.
0227:             */
0228:            private static int getAppropriateDataType(SampleModel sampleModel) {
0229:                int dataType = sampleModel.getDataType();
0230:                int retVal = dataType;
0231:
0232:                if (ImageUtil.isBinary(sampleModel)) {
0233:                    retVal = PixelAccessor.TYPE_BIT;
0234:                } else if (dataType == DataBuffer.TYPE_USHORT
0235:                        || dataType == DataBuffer.TYPE_INT) {
0236:                    boolean canUseBytes = true;
0237:                    boolean canUseShorts = true;
0238:
0239:                    int[] ss = sampleModel.getSampleSize();
0240:                    for (int i = 0; i < ss.length; i++) {
0241:                        if (ss[i] > 16) {
0242:                            canUseBytes = false;
0243:                            canUseShorts = false;
0244:                            break;
0245:                        }
0246:                        if (ss[i] > 8) {
0247:                            canUseBytes = false;
0248:                        }
0249:                    }
0250:
0251:                    if (canUseBytes) {
0252:                        retVal = DataBuffer.TYPE_BYTE;
0253:                    } else if (canUseShorts) {
0254:                        retVal = DataBuffer.TYPE_USHORT;
0255:                    }
0256:                }
0257:
0258:                return retVal;
0259:            }
0260:
0261:            /**
0262:             * Returns a type (one of the enumerated constants from
0263:             * DataBuffer) that has sufficent range to contain values from
0264:             * either of two given types.  This corresponds to an upwards move
0265:             * in the type lattice.
0266:             *
0267:             * <p> Note that the merge of SHORT and USHORT is INT, so it is not
0268:             * correct to simply use the larger of the types.
0269:             */
0270:            private static int mergeTypes(int type0, int type1) {
0271:                if (type0 == type1) {
0272:                    return type0;
0273:                }
0274:
0275:                // Default to second type.
0276:                int type = type1;
0277:
0278:                // Use switch logic to avoid depending on monotonicity of
0279:                // DataBuffer.TYPE_*.
0280:                switch (type0) {
0281:                case PixelAccessor.TYPE_BIT:
0282:                case DataBuffer.TYPE_BYTE:
0283:                    // Do nothing.
0284:                    break;
0285:                case DataBuffer.TYPE_SHORT:
0286:                    if (type1 == DataBuffer.TYPE_BYTE) {
0287:                        type = DataBuffer.TYPE_SHORT;
0288:                    } else if (type1 == DataBuffer.TYPE_USHORT) {
0289:                        type = DataBuffer.TYPE_INT;
0290:                    }
0291:                    break;
0292:                case DataBuffer.TYPE_USHORT:
0293:                    if (type1 == DataBuffer.TYPE_BYTE) {
0294:                        type = DataBuffer.TYPE_USHORT;
0295:                    } else if (type1 == DataBuffer.TYPE_SHORT) {
0296:                        type = DataBuffer.TYPE_INT;
0297:                    }
0298:                    break;
0299:                case DataBuffer.TYPE_INT:
0300:                    if (type1 == DataBuffer.TYPE_BYTE
0301:                            || type1 == DataBuffer.TYPE_SHORT
0302:                            || type1 == DataBuffer.TYPE_USHORT) {
0303:                        type = DataBuffer.TYPE_INT;
0304:                    }
0305:                    break;
0306:                case DataBuffer.TYPE_FLOAT:
0307:                    if (type1 != DataBuffer.TYPE_DOUBLE) {
0308:                        type = DataBuffer.TYPE_FLOAT;
0309:                    }
0310:                    break;
0311:                case DataBuffer.TYPE_DOUBLE:
0312:                    type = DataBuffer.TYPE_DOUBLE;
0313:                    break;
0314:                }
0315:
0316:                return type;
0317:            }
0318:
0319:            /**
0320:             * Constructor.
0321:             *
0322:             * <p> There must be at least one valid source supplied via the
0323:             * <code>sources</code> argument.  However, there is no upper limit
0324:             * on the number of sources this image may have.
0325:             *
0326:             * <p> The image's layout is encapsulated in the <code>layout</code>
0327:             * argument.  If the image bounds are supplied they must be contained
0328:             * within the intersected source bounds which must be non-empty.
0329:             * If the bounds are not supplied, they are calculated to be the
0330:             * intersection of the bounds of all sources.
0331:             *
0332:             * <p> If no <code>SampleModel</code> is specified in the layout, a new
0333:             * <code>SampleModel</code> will be created.  This <code>SampleModel</code>
0334:             * will have a number of bands equal to the minimum band count of all
0335:             * sources and a depth which can accomodate the data of all sources.
0336:             * The band count of sources which have an <code>IndexColorModel</code>
0337:             * will be set to the number of components of the
0338:             * <code>IndexColorModel</code> instead of to the number of bands of the
0339:             * <code>SampleModel</code>.
0340:             *
0341:             * <p> In all cases, the layout is forwarded to the <code>OpImage</code>
0342:             * constructor which sets the default layout values in the standard way.
0343:             *
0344:             * @param layout  The layout parameters of the destination image.
0345:             * @param sources  The source images.
0346:             * @param configuration Configurable attributes of the image including
0347:             *        configuration variables indexed by
0348:             *        <code>RenderingHints.Key</code>s and image properties indexed
0349:             *        by <code>String</code>s or <code>CaselessStringKey</code>s.
0350:             *        This is simply forwarded to the superclass constructor.
0351:             * @param cobbleSources  <code>true</code> if computeRect() expects
0352:             *        contiguous sources.
0353:             *
0354:             * @throws IllegalArgumentException  If <code>sources</code> or any
0355:             *         object in <code>sources</code> is <code>null</code>.
0356:             * @throws IllegalArgumentException if <code>sources</code> does not
0357:             *         contain at least one element.
0358:             * @throws ClassCastException  If any object in <code>sources</code>
0359:             *         is not a <code>RenderedImage</code>.
0360:             * @throws IllegalArgumentException  If combining the intersected
0361:             *         source bounds with the user-specified bounds, if any,
0362:             *         yields an empty rectangle, or the user-specified image bounds
0363:             *         extends beyond the intersection of all the source bounds.
0364:             *
0365:             * @since JAI 1.1
0366:             */
0367:            public PointOpImage(Vector sources, ImageLayout layout,
0368:                    Map configuration, boolean cobbleSources) {
0369:                super (checkSourceVector(sources, true), layoutHelper(layout,
0370:                        sources, configuration), configuration, cobbleSources);
0371:            }
0372:
0373:            /**
0374:             * Constructs a <code>PointOpImage</code> with one source image.
0375:             * The image layout is computed as described in the constructor
0376:             * taking a <code>Vector</code> of sources.
0377:             *
0378:             * @param layout  The layout parameters of the destination image.
0379:             * @param source  The source image.
0380:             * @param configuration Configurable attributes of the image including
0381:             *        configuration variables indexed by
0382:             *        <code>RenderingHints.Key</code>s and image properties indexed
0383:             *        by <code>String</code>s or <code>CaselessStringKey</code>s.
0384:             *        This is simply forwarded to the superclass constructor.
0385:             * @param cobbleSources  Indicates whether <code>computeRect()</code>
0386:             *        expects contiguous sources.
0387:             *
0388:             * @throws IllegalArgumentException if <code>source</code>
0389:             *         is <code>null</code>.
0390:             *
0391:             * @since JAI 1.1
0392:             */
0393:            public PointOpImage(RenderedImage source, ImageLayout layout,
0394:                    Map configuration, boolean cobbleSources) {
0395:                this (vectorize(source), // vectorize() checks for null source.
0396:                        layout, configuration, cobbleSources);
0397:            }
0398:
0399:            /**
0400:             * Constructs a <code>PointOpImage</code> with two source images.
0401:             * The image layout is computed as described in the constructor
0402:             * taking a <code>Vector</code> of sources.
0403:             *
0404:             * @param layout  The layout parameters of the destination image.
0405:             * @param source0  The first source image.
0406:             * @param source1  The second source image.
0407:             * @param configuration Configurable attributes of the image including
0408:             *        configuration variables indexed by
0409:             *        <code>RenderingHints.Key</code>s and image properties indexed
0410:             *        by <code>String</code>s or <code>CaselessStringKey</code>s.
0411:             *        This is simply forwarded to the superclass constructor.
0412:             * @param cobbleSources  Indicates whether <code>computeRect()</code>
0413:             *        expects contiguous sources.
0414:             *
0415:             * @throws IllegalArgumentException if <code>source0</code> or
0416:             *         <code>source1</code> is <code>null</code>.
0417:             *
0418:             * @since JAI 1.1
0419:             */
0420:            public PointOpImage(RenderedImage source0, RenderedImage source1,
0421:                    ImageLayout layout, Map configuration, boolean cobbleSources) {
0422:                this (vectorize(source0, source1), // vectorize() checks for null sources.
0423:                        layout, configuration, cobbleSources);
0424:            }
0425:
0426:            /**
0427:             * Constructs a <code>PointOpImage</code> with three source
0428:             * images.  The image layout is computed as described in the
0429:             * constructor taking a <code>Vector</code> of sources.
0430:             *
0431:             * @param layout  The layout parameters of the destination image.
0432:             * @param source0  The first source image.
0433:             * @param source1  The second source image.
0434:             * @param source2  The third source image.
0435:             * @param configuration Configurable attributes of the image including
0436:             *        configuration variables indexed by
0437:             *        <code>RenderingHints.Key</code>s and image properties indexed
0438:             *        by <code>String</code>s or <code>CaselessStringKey</code>s.
0439:             *        This is simply forwarded to the superclass constructor.
0440:             * @param cobbleSources  Indicates whether <code>computeRect()</code>
0441:             *        expects contiguous sources.
0442:             *
0443:             * @throws IllegalArgumentException if <code>source0</code> or
0444:             *         <code>source1</code> or <code>source2</code> is
0445:             *         <code>null</code>.
0446:             *
0447:             * @since JAI 1.1
0448:             */
0449:            public PointOpImage(RenderedImage source0, RenderedImage source1,
0450:                    RenderedImage source2, ImageLayout layout,
0451:                    Map configuration, boolean cobbleSources) {
0452:                this (vectorize(source0, source1, source2), // vectorize() checks null
0453:                        layout, configuration, cobbleSources);
0454:
0455:            }
0456:
0457:            /*
0458:             * Initialize flags and instance variables.
0459:             */
0460:            private synchronized void initializeFields() {
0461:
0462:                if (areFieldsInitialized)
0463:                    return;
0464:
0465:                PlanarImage source0 = getSource(0);
0466:
0467:                if (checkInPlaceOperation) {
0468:                    // Set the in-place operation flag.
0469:                    // XXX: In-place operation could work equally well when source0
0470:                    // is a WritableRenderedImage. However this could produce
0471:                    // unexpected results so consequently it would be desirable if
0472:                    // some kind of hint could be set that in-place operation is to
0473:                    // be used. The following statement should then be changed such
0474:                    // that instead of
0475:                    //
0476:                    //     source0 instanceof OpImage &&
0477:                    //
0478:                    // we have
0479:                    //
0480:                    //     (source0 instanceof OpImage ||
0481:                    //      (source0 instanceof WritableRenderedImage &&
0482:                    //       isInPlaceHintSet))
0483:                    //
0484:                    Vector source0Sinks = source0.getSinks();
0485:                    isInPlaceEnabled = source0 != null
0486:                            && getTileGridXOffset() == source0
0487:                                    .getTileGridXOffset()
0488:                            && getTileGridYOffset() == source0
0489:                                    .getTileGridYOffset()
0490:                            && getBounds().equals(source0.getBounds())
0491:                            && source0 instanceof  OpImage
0492:                            && hasCompatibleSampleModel(source0)
0493:                            && !(source0Sinks != null && source0Sinks.size() > 1);
0494:
0495:                    // Ensure that source0 computes unique tiles, i.e.,
0496:                    // computesUniqueTiles() returns false.  This disqualifies
0497:                    // for example in-place operations when source0 is an instance
0498:                    // of NullOpImage or of a subclass of NullOpImage or
0499:                    // SourcelessOpImage which does not override
0500:                    // computesUniqueTiles() to return true.
0501:                    if (isInPlaceEnabled
0502:                            && !((OpImage) source0).computesUniqueTiles()) {
0503:                        isInPlaceEnabled = false;
0504:                    }
0505:
0506:                    // Unset the in-place flag if getTile() is overridden by the
0507:                    // class of which source0 is an instance.
0508:                    if (isInPlaceEnabled) {
0509:                        try {
0510:                            Method getTileMethod = source0
0511:                                    .getClass()
0512:                                    .getMethod(
0513:                                            "getTile",
0514:                                            new Class[] { int.class, int.class });
0515:                            Class opImageClass = Class
0516:                                    .forName("javax.media.jai.OpImage");
0517:                            Class declaringClass = getTileMethod
0518:                                    .getDeclaringClass();
0519:
0520:                            // Unset in-place flag if getTile() is overridden.
0521:                            if (!declaringClass.equals(opImageClass)) {
0522:                                isInPlaceEnabled = false;
0523:                            }
0524:                        } catch (ClassNotFoundException e) {
0525:                            isInPlaceEnabled = false;
0526:                        } catch (NoSuchMethodException e) {
0527:                            isInPlaceEnabled = false;
0528:                        }
0529:                    }
0530:
0531:                    // Set local fields as a function of the in-place operation flag.
0532:                    if (isInPlaceEnabled) {
0533:                        // Set the flag indicating source0's type.
0534:                        source0IsWritableRenderedImage = source0 instanceof  WritableRenderedImage;
0535:
0536:                        // Cast the first source to one of the cached image variables.
0537:                        if (source0IsWritableRenderedImage) {
0538:                            source0AsWritableRenderedImage = (WritableRenderedImage) source0;
0539:                        } else {
0540:                            source0AsOpImage = (OpImage) source0;
0541:                        }
0542:                    }
0543:
0544:                    // Unset this flag.
0545:                    checkInPlaceOperation = false;
0546:                }
0547:
0548:                // Get the number of sources.
0549:                int numSources = getNumSources();
0550:
0551:                // Initialize the bounds and tile grid flags.
0552:                sameBounds = true;
0553:                sameTileGrid = true;
0554:
0555:                // Loop over all sources or until both flags are false.
0556:                for (int i = 0; i < numSources && (sameBounds || sameTileGrid); i++) {
0557:                    PlanarImage source = getSource(i);
0558:
0559:                    // Update the bounds flag.
0560:                    if (sameBounds) {
0561:                        sameBounds = sameBounds && minX == source.minX
0562:                                && minY == source.minY && width == source.width
0563:                                && height == source.height;
0564:                    }
0565:
0566:                    // Update the tile grid flag.
0567:                    if (sameTileGrid) {
0568:                        sameTileGrid = sameTileGrid
0569:                                && tileGridXOffset == source.tileGridXOffset
0570:                                && tileGridYOffset == source.tileGridYOffset
0571:                                && tileWidth == source.tileWidth
0572:                                && tileHeight == source.tileHeight;
0573:                    }
0574:                }
0575:
0576:                // Set this flag.
0577:                areFieldsInitialized = true;
0578:            }
0579:
0580:            /*
0581:             * Check whether the <code>SampleModel</code> of the argument
0582:             * <code>PlanarImage</code>is compatible with that of this
0583:             * <code>PointOpImage</code>.
0584:             *
0585:             * @param src The <code>PlanarImage</code> whose <code>SampleModel</code>
0586:             * is to be checked.
0587:             * @return Whether the parameter has a compatible <code>SampleModel</code>.
0588:             */
0589:            private boolean hasCompatibleSampleModel(PlanarImage src) {
0590:                SampleModel srcSM = src.getSampleModel();
0591:                int numBands = sampleModel.getNumBands();
0592:
0593:                boolean isCompatible = srcSM.getTransferType() == sampleModel
0594:                        .getTransferType()
0595:                        && srcSM.getWidth() == sampleModel.getWidth()
0596:                        && srcSM.getHeight() == sampleModel.getHeight()
0597:                        && srcSM.getNumBands() == numBands
0598:                        && srcSM.getClass().equals(sampleModel.getClass());
0599:
0600:                if (isCompatible) {
0601:                    if (sampleModel instanceof  ComponentSampleModel) {
0602:                        ComponentSampleModel smSrc = (ComponentSampleModel) srcSM;
0603:                        ComponentSampleModel smDst = (ComponentSampleModel) sampleModel;
0604:                        isCompatible = isCompatible
0605:                                && smSrc.getPixelStride() == smDst
0606:                                        .getPixelStride()
0607:                                && smSrc.getScanlineStride() == smDst
0608:                                        .getScanlineStride();
0609:                        int[] biSrc = smSrc.getBankIndices();
0610:                        int[] biDst = smDst.getBankIndices();
0611:                        int[] boSrc = smSrc.getBandOffsets();
0612:                        int[] boDst = smDst.getBandOffsets();
0613:                        for (int b = 0; b < numBands && isCompatible; b++) {
0614:                            isCompatible = isCompatible && biSrc[b] == biDst[b]
0615:                                    && boSrc[b] == boDst[b];
0616:                        }
0617:                    } else if (sampleModel instanceof  SinglePixelPackedSampleModel) {
0618:                        SinglePixelPackedSampleModel smSrc = (SinglePixelPackedSampleModel) srcSM;
0619:                        SinglePixelPackedSampleModel smDst = (SinglePixelPackedSampleModel) sampleModel;
0620:                        isCompatible = isCompatible
0621:                                && smSrc.getScanlineStride() == smDst
0622:                                        .getScanlineStride();
0623:                        int[] bmSrc = smSrc.getBitMasks();
0624:                        int[] bmDst = smDst.getBitMasks();
0625:                        for (int b = 0; b < numBands && isCompatible; b++) {
0626:                            isCompatible = isCompatible && bmSrc[b] == bmDst[b];
0627:                        }
0628:                    } else if (sampleModel instanceof  MultiPixelPackedSampleModel) {
0629:                        MultiPixelPackedSampleModel smSrc = (MultiPixelPackedSampleModel) srcSM;
0630:                        MultiPixelPackedSampleModel smDst = (MultiPixelPackedSampleModel) sampleModel;
0631:                        isCompatible = isCompatible
0632:                                && smSrc.getPixelBitStride() == smDst
0633:                                        .getPixelBitStride()
0634:                                && smSrc.getScanlineStride() == smDst
0635:                                        .getScanlineStride()
0636:                                && smSrc.getDataBitOffset() == smDst
0637:                                        .getDataBitOffset();
0638:                    } else {
0639:                        isCompatible = false;
0640:                    }
0641:                }
0642:
0643:                return isCompatible;
0644:            }
0645:
0646:            /**
0647:             * Causes a flag to be set to indicate that in-place operation should
0648:             * be permitted if the image bounds, tile grid offset, tile dimensions,
0649:             * and SampleModels of the source and destination images are compatible.
0650:             * This method should be invoked in the constructor of the implementation
0651:             * of a given operation only if that implementation is amenable to
0652:             * in-place computation.  Invocation of this method is a necessary but
0653:             * not a sufficient condition for in-place computation actually to occur.
0654:             * If the system property "javax.media.jai.PointOpImage.InPlace" is equal
0655:             * to the string "false" in a case-insensitive fashion then in-place
0656:             * operation will not be permitted.
0657:             */
0658:            protected void permitInPlaceOperation() {
0659:                // Retrieve the in-place property.
0660:                Object inPlaceProperty = null;
0661:                try {
0662:                    inPlaceProperty = AccessController
0663:                            .doPrivileged(new PrivilegedAction() {
0664:                                public Object run() {
0665:                                    String name = "javax.media.jai.PointOpImage.InPlace";
0666:                                    return System.getProperty(name);
0667:                                }
0668:                            });
0669:                } catch (SecurityException se) {
0670:                    /// as if the property isn't set
0671:                }
0672:                // Set the flag to false if and only if the property is set to
0673:                // the string "false" (case-insensitive).
0674:                checkInPlaceOperation = !(inPlaceProperty != null
0675:                        && inPlaceProperty instanceof  String && ((String) inPlaceProperty)
0676:                        .equalsIgnoreCase("false"));
0677:            }
0678:
0679:            /**
0680:             * Indicates whether the operation is being effected directly on the
0681:             * associated colormap.  This method will in general return
0682:             * <code>true</code> if the image is the destination of a unary,
0683:             * shift-invariant operation with an <code>IndexColorModel</code> equal
0684:             * to that of its unique source.
0685:             *
0686:             * <p> When this method returns <code>true</code> the
0687:             * <code>computeTile()</code> method in this class will return either
0688:             * a copy of the corresponding region of the first source image or,
0689:             * if the operation is being performed in place, the corresponding
0690:             * tile of the first source image.
0691:             *
0692:             * <p> The implementation in this class always returns <code>false</code>.
0693:             *
0694:             * @since JAI 1.1
0695:             */
0696:            protected boolean isColormapOperation() {
0697:                return false;
0698:            }
0699:
0700:            /**
0701:             * Computes a tile.  If source cobbling was requested at
0702:             * construction time, the source tile boundaries are overlayed
0703:             * onto the destination and <code>computeRect(Raster[],
0704:             * WritableRaster, Rectangle)</code> is called for each of the
0705:             * resulting regions.  Otherwise, <code>computeRect(PlanarImage[],
0706:             * WritableRaster, Rectangle)</code> is called once to compute the
0707:             * entire active area of the tile.
0708:             *
0709:             * <p> The image bounds may be larger than the bounds of the
0710:             * source image.  In this case, samples for which there are no
0711:             * corresponding sources are set to zero.
0712:             *
0713:             * @param tileX  The X index of the tile.
0714:             * @param tileY The Y index of the tile.
0715:             */
0716:            public Raster computeTile(int tileX, int tileY) {
0717:                if (!cobbleSources) {
0718:                    return super .computeTile(tileX, tileY);
0719:                }
0720:
0721:                // Make sure the fields are initialized.
0722:                initializeFields();
0723:
0724:                // Get a WritableRaster to represent this tile.
0725:                WritableRaster dest = null;
0726:                if (isInPlaceEnabled) {
0727:                    if (source0IsWritableRenderedImage) {
0728:                        // Check one out from the WritableRenderedImage source.
0729:                        dest = source0AsWritableRenderedImage.getWritableTile(
0730:                                tileX, tileY);
0731:                    } else { // source0 is OpImage
0732:                        // Re-use one from the OpImage source.
0733:                        // First check whether the source raster is cached.
0734:                        Raster raster = source0AsOpImage.getTileFromCache(
0735:                                tileX, tileY);
0736:
0737:                        if (raster == null) {
0738:                            // Compute the tile.
0739:                            try {
0740:                                raster = source0AsOpImage.computeTile(tileX,
0741:                                        tileY);
0742:                                if (raster instanceof  WritableRaster) {
0743:                                    dest = (WritableRaster) raster;
0744:                                }
0745:                            } catch (Exception e) {
0746:                                // Do nothing: this catch is simply in case the
0747:                                // OpImage in question does not itself implement
0748:                                // computeTile() in which case it may be resolved
0749:                                // to OpImage.computeTile() which will throw an
0750:                                // Exception.
0751:                            }
0752:                        }
0753:                    }
0754:                }
0755:
0756:                // Set tile recycling flag.
0757:                boolean recyclingSource0Tile = dest != null;
0758:
0759:                if (!recyclingSource0Tile) {
0760:                    // Create a new WritableRaster.
0761:                    Point org = new Point(tileXToX(tileX), tileYToY(tileY));
0762:                    dest = createWritableRaster(sampleModel, org);
0763:                }
0764:
0765:                // Colormap operation: return the source Raster if operating
0766:                // in place or a copy thereof otherwise.
0767:                if (isColormapOperation()) {
0768:                    if (!recyclingSource0Tile) {
0769:                        PlanarImage src = getSource(0);
0770:                        Raster srcTile = null;
0771:                        Rectangle srcRect = null;
0772:                        Rectangle dstRect = dest.getBounds();
0773:
0774:                        // Confirm that the tile grids of the source and destination
0775:                        // are the same
0776:                        if (sameTileGrid) {
0777:                            // Tile grids are aligned so the tile indices correspond
0778:                            // to pixels at the same locations in source and destination
0779:                            srcTile = getSource(0).getTile(tileX, tileY);
0780:                        } else if (dstRect.intersects(src.getBounds())) {
0781:                            // Tile grids are not aligned but the destination rectangle
0782:                            // intersects the source bounds so get the data using
0783:                            // the destination rectangle
0784:                            srcTile = src.getData(dstRect);
0785:                        } else {
0786:                            // The destination rectangle does not interest the source
0787:                            // bounds so just return the destination.
0788:                            return dest;
0789:                        }
0790:
0791:                        srcRect = srcTile.getBounds();
0792:
0793:                        // Ensure that the source tile doesn't lie outside the
0794:                        // destination tile.
0795:                        if (!dstRect.contains(srcRect)) {
0796:                            srcRect = dstRect.intersection(srcRect);
0797:                            srcTile = srcTile.createChild(srcTile.getMinX(),
0798:                                    srcTile.getMinY(), srcRect.width,
0799:                                    srcRect.height, srcRect.x, srcRect.y, null);
0800:                        }
0801:
0802:                        JDKWorkarounds.setRect(dest, srcTile, 0, 0);
0803:                    }
0804:                    return dest;
0805:                }
0806:
0807:                // Output bounds are initially equal to the tile bounds.
0808:                int destMinX = dest.getMinX();
0809:                int destMinY = dest.getMinY();
0810:                int destMaxX = destMinX + dest.getWidth();
0811:                int destMaxY = destMinY + dest.getHeight();
0812:
0813:                // Clip output bounds to the dest image bounds.
0814:                Rectangle bounds = getBounds();
0815:                if (destMinX < bounds.x) {
0816:                    destMinX = bounds.x;
0817:                }
0818:                int boundsMaxX = bounds.x + bounds.width;
0819:                if (destMaxX > boundsMaxX) {
0820:                    destMaxX = boundsMaxX;
0821:                }
0822:                if (destMinY < bounds.y) {
0823:                    destMinY = bounds.y;
0824:                }
0825:                int boundsMaxY = bounds.y + bounds.height;
0826:                if (destMaxY > boundsMaxY) {
0827:                    destMaxY = boundsMaxY;
0828:                }
0829:
0830:                // Get the number of sources.
0831:                int numSrcs = getNumSources();
0832:
0833:                // Branch to actual destination rectangle computation as a
0834:                // function of in-place operation and layout compatibility.
0835:                if (recyclingSource0Tile && numSrcs == 1) {
0836:                    // Recycling tile from a single source.
0837:                    Raster[] sources = new Raster[] { dest };
0838:                    Rectangle destRect = new Rectangle(destMinX, destMinY,
0839:                            destMaxX - destMinX, destMaxY - destMinY);
0840:                    computeRect(sources, dest, destRect);
0841:                } else if (recyclingSource0Tile && sameBounds && sameTileGrid) {
0842:                    // Recycling tile from first of layout-compatible sources.
0843:                    Raster[] sources = new Raster[numSrcs];
0844:                    sources[0] = dest;
0845:                    for (int i = 1; i < numSrcs; i++) {
0846:                        sources[i] = getSource(i).getTile(tileX, tileY);
0847:                    }
0848:                    Rectangle destRect = new Rectangle(destMinX, destMinY,
0849:                            destMaxX - destMinX, destMaxY - destMinY);
0850:                    computeRect(sources, dest, destRect);
0851:                } else {
0852:                    // Clip against source bounds only if necessary.
0853:                    if (!sameBounds) {
0854:                        // Clip output bounds to each source image bounds
0855:                        for (int i = recyclingSource0Tile ? 1 : 0; i < numSrcs; i++) {
0856:                            bounds = getSource(i).getBounds();
0857:                            if (destMinX < bounds.x) {
0858:                                destMinX = bounds.x;
0859:                            }
0860:                            boundsMaxX = bounds.x + bounds.width;
0861:                            if (destMaxX > boundsMaxX) {
0862:                                destMaxX = boundsMaxX;
0863:                            }
0864:                            if (destMinY < bounds.y) {
0865:                                destMinY = bounds.y;
0866:                            }
0867:                            boundsMaxY = bounds.y + bounds.height;
0868:                            if (destMaxY > boundsMaxY) {
0869:                                destMaxY = boundsMaxY;
0870:                            }
0871:
0872:                            if (destMinX >= destMaxX || destMinY >= destMaxY) {
0873:                                return dest; // no corresponding source region
0874:                            }
0875:                        }
0876:                    }
0877:
0878:                    // Initialize the (possibly clipped) destination Rectangle.
0879:                    Rectangle destRect = new Rectangle(destMinX, destMinY,
0880:                            destMaxX - destMinX, destMaxY - destMinY);
0881:
0882:                    // Allocate memory for source Rasters.
0883:                    Raster[] sources = new Raster[numSrcs];
0884:
0885:                    if (sameTileGrid) {
0886:                        // All sources share the tile grid of the destination so
0887:                        // there is no need for splits.
0888:                        if (recyclingSource0Tile) {
0889:                            sources[0] = dest;
0890:                        }
0891:                        for (int i = recyclingSource0Tile ? 1 : 0; i < numSrcs; i++) {
0892:                            sources[i] = getSource(i).getTile(tileX, tileY);
0893:                        }
0894:
0895:                        computeRect(sources, dest, destRect);
0896:                    } else {
0897:                        //
0898:                        // The tileWidth and tileHeight of the source image
0899:                        // may differ from this tileWidth and tileHeight.
0900:                        //
0901:                        IntegerSequence xSplits = new IntegerSequence(destMinX,
0902:                                destMaxX);
0903:                        xSplits.insert(destMinX);
0904:                        xSplits.insert(destMaxX);
0905:
0906:                        IntegerSequence ySplits = new IntegerSequence(destMinY,
0907:                                destMaxY);
0908:                        ySplits.insert(destMinY);
0909:                        ySplits.insert(destMaxY);
0910:
0911:                        for (int i = recyclingSource0Tile ? 1 : 0; i < numSrcs; i++) {
0912:                            PlanarImage s = getSource(i);
0913:                            s.getSplits(xSplits, ySplits, destRect);
0914:                        }
0915:
0916:                        //
0917:                        // Divide destRect into sub rectangles based on the source
0918:                        // splits, and compute each sub rectangle separately.
0919:                        //
0920:                        int x1, x2, y1, y2, w, h;
0921:                        Rectangle subRect = new Rectangle();
0922:
0923:                        ySplits.startEnumeration();
0924:                        for (y1 = ySplits.nextElement(); ySplits
0925:                                .hasMoreElements(); y1 = y2) {
0926:                            y2 = ySplits.nextElement();
0927:                            h = y2 - y1;
0928:
0929:                            xSplits.startEnumeration();
0930:                            for (x1 = xSplits.nextElement(); xSplits
0931:                                    .hasMoreElements(); x1 = x2) {
0932:                                x2 = xSplits.nextElement();
0933:                                w = x2 - x1;
0934:
0935:                                // Get sources.
0936:                                if (recyclingSource0Tile) {
0937:                                    sources[0] = dest;
0938:                                }
0939:                                for (int i = recyclingSource0Tile ? 1 : 0; i < numSrcs; i++) {
0940:                                    PlanarImage s = getSource(i);
0941:                                    int tx = s.XToTileX(x1);
0942:                                    int ty = s.YToTileY(y1);
0943:                                    sources[i] = s.getTile(tx, ty);
0944:                                }
0945:
0946:                                subRect.x = x1;
0947:                                subRect.y = y1;
0948:                                subRect.width = w;
0949:                                subRect.height = h;
0950:                                computeRect(sources, dest, subRect);
0951:                            }
0952:                        }
0953:                    }
0954:                }
0955:
0956:                if (recyclingSource0Tile && source0IsWritableRenderedImage) {
0957:                    source0AsWritableRenderedImage.releaseWritableTile(tileX,
0958:                            tileY);
0959:                }
0960:
0961:                return dest;
0962:            }
0963:
0964:            /**
0965:             * Returns a conservative estimate of the destination region that
0966:             * can potentially be affected by the pixels of a rectangle of a
0967:             * given source. The resulting <code>Rectangle</code> is <u>not</u>
0968:             * clipped to the destination image bounds.
0969:             *
0970:             * @param sourceRect the <code>Rectangle</code> in source coordinates.
0971:             * @param sourceIndex the index of the source image.
0972:             * @return a <code>Rectangle</code> indicating the potentially affected
0973:             *         destination region, or <code>null</code> if the region is unknown.
0974:             * @throws IllegalArgumentException if <code>sourceIndex</code> is
0975:             *         negative or greater than the index of the last source.
0976:             * @throws IllegalArgumentException if <code>sourceRect</code> is
0977:             *         <code>null</code>.
0978:             */
0979:            public final Rectangle mapSourceRect(Rectangle sourceRect,
0980:                    int sourceIndex) {
0981:                if (sourceRect == null) {
0982:                    throw new IllegalArgumentException(JaiI18N
0983:                            .getString("Generic0"));
0984:                }
0985:
0986:                if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
0987:                    throw new IllegalArgumentException(JaiI18N
0988:                            .getString("Generic1"));
0989:                }
0990:                return new Rectangle(sourceRect);
0991:            }
0992:
0993:            /**
0994:             * Returns a conservative estimate of the region of a specific
0995:             * source that is required in order to compute the pixels of a
0996:             * given destination rectangle. The resulting <code>Rectangle</code>
0997:             * is <u>not</u> clipped to the source image bounds.
0998:             *
0999:             * @param destRect the <code>Rectangle</code> in source coordinates.
1000:             * @param sourceIndex the index of the source image.
1001:             * @return a <code>Rectangle</code> indicating the potentially affected
1002:             *         destination region.
1003:             *
1004:             * @throws IllegalArgumentException if <code>sourceIndex</code> is
1005:             *         negative or greater than the index of the last source.
1006:             * @throws IllegalArgumentException if <code>destRect</code> is
1007:             *         <code>null</code>.
1008:             */
1009:            public final Rectangle mapDestRect(Rectangle destRect,
1010:                    int sourceIndex) {
1011:                if (destRect == null) {
1012:                    throw new IllegalArgumentException(JaiI18N
1013:                            .getString("Generic0"));
1014:                }
1015:
1016:                if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
1017:                    throw new IllegalArgumentException(JaiI18N
1018:                            .getString("Generic1"));
1019:                }
1020:                return new Rectangle(destRect);
1021:            }
1022:
1023:            /**
1024:             * Disposes of any remaining tiles in the <code>TileCache</code>.
1025:             *
1026:             * <p>If <code>cache</code> is non-<code>null</code>, in place operation
1027:             * is enabled, and <code>tileRecycler</code> is non-<code>null</code>,
1028:             * then all tiles owned by this specific image are removed from the cache.
1029:             * Subsequent to this <code>super.dispose()</code> is invoked.</p>
1030:             *
1031:             * @since JAI 1.1.2
1032:             */
1033:            public synchronized void dispose() {
1034:                if (isDisposed) {
1035:                    return;
1036:                }
1037:
1038:                isDisposed = true;
1039:
1040:                if (cache != null && isInPlaceEnabled && tileRecycler != null) {
1041:                    cache.removeTiles(this);
1042:                }
1043:
1044:                super.dispose();
1045:            }
1046:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.