Source Code Cross Referenced for ScaleOpImage.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: ScaleOpImage.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:21 $
0010:         * $State: Exp $
0011:         */
0012:        package javax.media.jai;
0013:
0014:        import com.sun.media.jai.util.Rational;
0015:        import com.sun.media.jai.util.ImageUtil;
0016:        import java.awt.Rectangle;
0017:        import java.awt.RenderingHints;
0018:        import java.awt.geom.Point2D;
0019:        import java.awt.image.Raster;
0020:        import java.awt.image.RenderedImage;
0021:        import java.awt.image.WritableRaster;
0022:        import java.awt.Point;
0023:        import java.util.Map;
0024:        import java.util.LinkedList;
0025:        import javax.media.jai.util.CaselessStringKey;
0026:
0027:        /**
0028:         * A class extending <code>WarpOpImage</code> for use by further
0029:         * extension classes that perform image scaling.  Image scaling operations
0030:         * require rectilinear backwards mapping and padding by the resampling
0031:         * filter dimensions.
0032:         *
0033:         * <p> When applying scale factors of scaleX, scaleY to a source image
0034:         * with the upper left pixel at (srcMinX, srcMinY) and width of srcWidth
0035:         * and height of srcHeight, the resulting image is defined to have the
0036:         * following bounds:
0037:         *
0038:         * <code>
0039:         *       dstMinX = ceil(A), where A = srcMinX * scaleX - 0.5 + transX,
0040:         *       dstMinY = ceil(B), where B = srcMinY * scaleY - 0.5 + transY,
0041:         *       dstMaxX = ceil(C), where C = (srcMaxX + 1) * scaleX - 1.5 + transX
0042:         *                          and srcMaxX = srcMinX + srcWidth - 1    
0043:         *       dstMaxY = ceil(D), where D = (srcMaxY + 1) * scaleY - 1.5 + transY
0044:         *                          and srcMaxY = srcMinY + srcHeight - 1    
0045:         *       dstWidth = dstMaxX - dstMinX + 1
0046:         *       dstHeight = dstMaxY - dstMinY + 1
0047:         * </code>
0048:         *
0049:         * <p> In the case where source's upper left pixel is located is (0, 0),
0050:         * the formulae simplify to
0051:         *
0052:         * <code>
0053:         *       dstMinX = 0
0054:         *       dstMinY = 0
0055:         *       dstWidth = ceil (srcWidth * scaleX - 0.5 + transX)
0056:         *       dstHeight = ceil (srcHeight * scaleY - 0.5 + transY)
0057:         * </code>
0058:         *
0059:         * <p> In the case where the source's upper left pixel is located at (0, 0)
0060:         * and the scaling factors are integers, the formulae further simplify to
0061:         *
0062:         * <code>
0063:         *       dstMinX = 0
0064:         *       dstMinY = 0
0065:         *       dstWidth = ceil (srcWidth * scaleX + transX)
0066:         *       dstWidth = ceil (srcHeight * scaleY + transY)
0067:         * </code>
0068:         *
0069:         * <p> When interpolations which require padding the source such as Bilinear
0070:         * or Bicubic interpolation are specified, the source needs to be extended
0071:         * such that it has the extra pixels needed to compute all the destination
0072:         * pixels. This extension is performed via the <code>BorderExtender</code>
0073:         * class. The type of border extension can be specified as a
0074:         * <code>RenderingHint</code> to the <code>JAI.create</code> method.
0075:         *
0076:         * <p> If no <code>BorderExtender</code> is specified, the source will
0077:         * not be extended.  The scaled image size is still calculated
0078:         * according to the formula specified above. However since there is not
0079:         * enough source to compute all the destination pixels, only that
0080:         * subset of the destination image's pixels which can be computed,
0081:         * will be written in the destination. The rest of the destination
0082:         * will be set to zeros.
0083:         *
0084:         * <p> It may be noted that the minX, minY, width and height hints as
0085:         * specified through the <code>JAI.KEY_IMAGE_LAYOUT</code> hint in the
0086:         * <code>RenderingHints</code> object are not honored, as this operator
0087:         * calculates the destination image bounds itself. The other
0088:         * <code>ImageLayout</code> hints, like tileWidth and tileHeight,
0089:         * however are honored.
0090:         *
0091:         * It should be noted that the superclass <code>GeometricOpImage</code>
0092:         * automatically adds a value of <code>Boolean.TRUE</code> for the
0093:         * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> to the given
0094:         * <code>configuration</code> and passes it up to its superclass constructor
0095:         * so that geometric operations are performed on the pixel values instead
0096:         * of being performed on the indices into the color map for those
0097:         * operations whose source(s) have an <code>IndexColorModel</code>.
0098:         * This addition will take place only if a value for the 
0099:         * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> has not already been
0100:         * provided by the user. Note that the <code>configuration</code> Map
0101:         * is cloned before the new hint is added to it. Regarding the value for
0102:         * the <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code>
0103:         * <code>RenderingHints</code>, the operator itself can be smart
0104:         * based on the parameters, i.e. while the default value for
0105:         * the <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> is
0106:         * <code>Boolean.TRUE</code> for operations that extend this class,
0107:         * in some cases the operator could set the default.
0108:         *
0109:         * @see WarpOpImage
0110:         * @see OpImage
0111:         *
0112:         */
0113:        public abstract class ScaleOpImage extends GeometricOpImage {
0114:
0115:            /** The horizontal scale factor. */
0116:            protected float scaleX;
0117:
0118:            /** The vertical scale factor. */
0119:            protected float scaleY;
0120:
0121:            /** Thee horizontal translation factor */
0122:            protected float transX;
0123:
0124:            /** The vertical translation factor */
0125:            protected float transY;
0126:
0127:            /*** Rational representations */
0128:            protected Rational scaleXRational, scaleYRational;
0129:            protected long scaleXRationalNum, scaleXRationalDenom;
0130:            protected long scaleYRationalNum, scaleYRationalDenom;
0131:
0132:            protected Rational invScaleXRational, invScaleYRational;
0133:            protected long invScaleXRationalNum, invScaleXRationalDenom;
0134:            protected long invScaleYRationalNum, invScaleYRationalDenom;
0135:
0136:            protected Rational transXRational, transYRational;
0137:            protected long transXRationalNum, transXRationalDenom;
0138:            protected long transYRationalNum, transYRationalDenom;
0139:
0140:            protected static float rationalTolerance = 0.000001F;
0141:
0142:            // Padding
0143:            private int lpad, rpad, tpad, bpad;
0144:
0145:            // FORMULAE FOR FORWARD MAP are derived as follows
0146:            //     Nearest
0147:            //        Minimum:
0148:            //            srcMin = floor ((dstMin + 0.5 - trans) / scale)
0149:            //            srcMin <= (dstMin + 0.5 - trans) / scale < srcMin + 1
0150:            //            srcMin*scale <= dstMin + 0.5 - trans < (srcMin + 1)*scale
0151:            //            srcMin*scale - 0.5 + trans
0152:            //                       <= dstMin < (srcMin + 1)*scale - 0.5 + trans
0153:            //            Let A = srcMin*scale - 0.5 + trans,
0154:            //            Let B = (srcMin + 1)*scale - 0.5 + trans
0155:            //
0156:            //            dstMin = ceil(A)
0157:            //
0158:            //        Maximum:
0159:            //            Note that srcMax is defined to be srcMin + dimension - 1
0160:            //            srcMax = floor ((dstMax + 0.5 - trans) / scale)
0161:            //            srcMax <= (dstMax + 0.5 - trans) / scale < srcMax + 1
0162:            //            srcMax*scale <= dstMax + 0.5 - trans < (srcMax + 1)*scale
0163:            //            srcMax*scale - 0.5 + trans
0164:            //                       <= dstMax < (srcMax+1) * scale - 0.5 + trans
0165:            //            Let float A = (srcMax + 1) * scale - 0.5 + trans
0166:            //
0167:            //            dstMax = floor(A), if floor(A) < A, else
0168:            //            dstMax = floor(A) - 1
0169:            //            OR dstMax = ceil(A - 1)
0170:            //
0171:            //     Other interpolations
0172:            //
0173:            //        First the source should be shrunk by the padding that is
0174:            //        required for the particular interpolation. Then the
0175:            //        shrunk source should be forward mapped as follows:
0176:            //
0177:            //        Minimum:
0178:            //            srcMin = floor (((dstMin + 0.5 - trans)/scale) - 0.5)
0179:            //            srcMin <= ((dstMin + 0.5 - trans)/scale) - 0.5 < srcMin+1
0180:            //            (srcMin+0.5)*scale <= dstMin+0.5-trans <
0181:            //                                                  (srcMin+1.5)*scale
0182:            //            (srcMin+0.5)*scale - 0.5 + trans
0183:            //                       <= dstMin < (srcMin+1.5)*scale - 0.5 + trans
0184:            //            Let A = (srcMin+0.5)*scale - 0.5 + trans,
0185:            //            Let B = (srcMin+1.5)*scale - 0.5 + trans
0186:            //
0187:            //            dstMin = ceil(A)
0188:            //
0189:            //        Maximum:
0190:            //            srcMax is defined as srcMin + dimension - 1
0191:            //            srcMax = floor (((dstMax + 0.5 - trans) / scale) - 0.5)
0192:            //            srcMax <= ((dstMax + 0.5 - trans)/scale) - 0.5 < srcMax+1
0193:            //            (srcMax+0.5)*scale <= dstMax + 0.5 - trans <
0194:            //                                                   (srcMax+1.5)*scale
0195:            //            (srcMax+0.5)*scale - 0.5 + trans
0196:            //                       <= dstMax < (srcMax+1.5)*scale - 0.5 + trans
0197:            //            Let float A = (srcMax+1.5)*scale - 0.5 + trans
0198:            //
0199:            //            dstMax = floor(A), if floor(A) < A, else
0200:            //            dstMax = floor(A) - 1
0201:            //            OR dstMax = ceil(A - 1)
0202:            //
0203:
0204:            private static ImageLayout layoutHelper(RenderedImage source,
0205:                    float scaleX, float scaleY, float transX, float transY,
0206:                    Interpolation interp, ImageLayout il) {
0207:
0208:                // Represent the scale factors as Rational numbers.
0209:                // Since a value of 1.2 is represented as 1.200001 which
0210:                // throws the forward/backward mapping in certain situations.
0211:                // Convert the scale and translation factors to Rational numbers
0212:                Rational scaleXRational = Rational.approximate(scaleX,
0213:                        rationalTolerance);
0214:
0215:                Rational scaleYRational = Rational.approximate(scaleY,
0216:                        rationalTolerance);
0217:
0218:                long scaleXRationalNum = (long) scaleXRational.num;
0219:                long scaleXRationalDenom = (long) scaleXRational.denom;
0220:                long scaleYRationalNum = (long) scaleYRational.num;
0221:                long scaleYRationalDenom = (long) scaleYRational.denom;
0222:
0223:                Rational transXRational = Rational.approximate(transX,
0224:                        rationalTolerance);
0225:
0226:                Rational transYRational = Rational.approximate(transY,
0227:                        rationalTolerance);
0228:
0229:                long transXRationalNum = (long) transXRational.num;
0230:                long transXRationalDenom = (long) transXRational.denom;
0231:                long transYRationalNum = (long) transYRational.num;
0232:                long transYRationalDenom = (long) transYRational.denom;
0233:
0234:                ImageLayout layout = (il == null) ? new ImageLayout()
0235:                        : (ImageLayout) il.clone();
0236:
0237:                int x0 = source.getMinX();
0238:                int y0 = source.getMinY();
0239:                int w = source.getWidth();
0240:                int h = source.getHeight();
0241:
0242:                // Variables to store the calculated destination upper left coordinate
0243:                long dx0Num, dx0Denom, dy0Num, dy0Denom;
0244:
0245:                // Variables to store the calculated destination bottom right 
0246:                // coordinate
0247:                long dx1Num, dx1Denom, dy1Num, dy1Denom;
0248:
0249:                // Start calculations for destination
0250:
0251:                dx0Num = x0;
0252:                dx0Denom = 1;
0253:
0254:                dy0Num = y0;
0255:                dy0Denom = 1;
0256:
0257:                // Formula requires srcMaxX + 1 = (x0 + w - 1) + 1 = x0 + w
0258:                dx1Num = x0 + w;
0259:                dx1Denom = 1;
0260:
0261:                // Formula requires srcMaxY + 1 = (y0 + h - 1) + 1 = y0 + h
0262:                dy1Num = y0 + h;
0263:                dy1Denom = 1;
0264:
0265:                dx0Num *= scaleXRationalNum;
0266:                dx0Denom *= scaleXRationalDenom;
0267:
0268:                dy0Num *= scaleYRationalNum;
0269:                dy0Denom *= scaleYRationalDenom;
0270:
0271:                dx1Num *= scaleXRationalNum;
0272:                dx1Denom *= scaleXRationalDenom;
0273:
0274:                dy1Num *= scaleYRationalNum;
0275:                dy1Denom *= scaleYRationalDenom;
0276:
0277:                // Equivalent to subtracting 0.5
0278:                dx0Num = 2 * dx0Num - dx0Denom;
0279:                dx0Denom *= 2;
0280:
0281:                dy0Num = 2 * dy0Num - dy0Denom;
0282:                dy0Denom *= 2;
0283:
0284:                // Equivalent to subtracting 1.5
0285:                dx1Num = 2 * dx1Num - 3 * dx1Denom;
0286:                dx1Denom *= 2;
0287:
0288:                dy1Num = 2 * dy1Num - 3 * dy1Denom;
0289:                dy1Denom *= 2;
0290:
0291:                // Adding translation factors
0292:
0293:                //  Equivalent to float dx0 += transX
0294:                dx0Num = dx0Num * transXRationalDenom + transXRationalNum
0295:                        * dx0Denom;
0296:                dx0Denom *= transXRationalDenom;
0297:
0298:                //  Equivalent to float dy0 += transY
0299:                dy0Num = dy0Num * transYRationalDenom + transYRationalNum
0300:                        * dy0Denom;
0301:                dy0Denom *= transYRationalDenom;
0302:
0303:                //  Equivalent to float dx1 += transX
0304:                dx1Num = dx1Num * transXRationalDenom + transXRationalNum
0305:                        * dx1Denom;
0306:                dx1Denom *= transXRationalDenom;
0307:
0308:                //  Equivalent to float dy1 += transY
0309:                dy1Num = dy1Num * transYRationalDenom + transYRationalNum
0310:                        * dy1Denom;
0311:                dy1Denom *= transYRationalDenom;
0312:
0313:                // Get the integral coordinates
0314:                int l_x0, l_y0, l_x1, l_y1;
0315:
0316:                l_x0 = Rational.ceil(dx0Num, dx0Denom);
0317:                l_y0 = Rational.ceil(dy0Num, dy0Denom);
0318:
0319:                l_x1 = Rational.ceil(dx1Num, dx1Denom);
0320:                l_y1 = Rational.ceil(dy1Num, dy1Denom);
0321:
0322:                // Set the top left coordinate of the destination
0323:                layout.setMinX(l_x0);
0324:                layout.setMinY(l_y0);
0325:
0326:                // Width and height
0327:                layout.setWidth(l_x1 - l_x0 + 1);
0328:                layout.setHeight(l_y1 - l_y0 + 1);
0329:
0330:                return layout;
0331:            }
0332:
0333:            private static Map configHelper(RenderedImage source,
0334:                    Map configuration, Interpolation interp) {
0335:
0336:                Map config = configuration;
0337:
0338:                // If source image is binary and the interpolation is either nearest
0339:                // or bilinear, do not expand
0340:                if (ImageUtil.isBinary(source.getSampleModel())
0341:                        && (interp == null
0342:                                || interp instanceof  InterpolationNearest || interp instanceof  InterpolationBilinear)) {
0343:
0344:                    // Set to false	    
0345:                    if (configuration == null) {
0346:                        config = new RenderingHints(
0347:                                JAI.KEY_REPLACE_INDEX_COLOR_MODEL,
0348:                                Boolean.FALSE);
0349:                    } else {
0350:
0351:                        // If the user specified a value for this hint, we don't
0352:                        // want to change that
0353:                        if (!config
0354:                                .containsKey(JAI.KEY_REPLACE_INDEX_COLOR_MODEL)) {
0355:                            RenderingHints hints = new RenderingHints(null);
0356:                            // This is effectively a clone of configuration
0357:                            hints.putAll(configuration);
0358:                            config = hints;
0359:                            config.put(JAI.KEY_REPLACE_INDEX_COLOR_MODEL,
0360:                                    Boolean.TRUE);
0361:                        }
0362:                    }
0363:                }
0364:
0365:                return config;
0366:            }
0367:
0368:            /**
0369:             * Constructs a <code>ScaleOpImage</code> from a <code>RenderedImage</code>
0370:             * source, an optional <code>BorderExtender</code>, x and y scale
0371:             * and translation factors, and an <code>Interpolation</code>
0372:             * object.  The image dimensions are determined by forward-mapping
0373:             * the source bounds, and are passed to the superclass constructor
0374:             * by means of the <code>layout</code> parameter.  Other fields of
0375:             * the layout are passed through unchanged.  If
0376:             * <code>layout</code> is <code>null</code>, a new
0377:             * <code>ImageLayout</code> will be constructor to hold the bounds
0378:             * information.
0379:             *
0380:             * Note that the scale factors are represented internally as Rational
0381:             * numbers in order to workaround inexact device specific representation
0382:             * of floating point numbers. For instance the floating point number 1.2
0383:             * is internally represented as 1.200001, which can throw the
0384:             * calculations off during a forward/backward map.
0385:             *
0386:             * <p> The Rational approximation is valid upto the sixth decimal place.
0387:             *
0388:             * @param layout an <code>ImageLayout</code> optionally containing
0389:             *        the tile grid layout, <code>SampleModel</code>, and
0390:             *        <code>ColorModel</code>, or <code>null</code>.
0391:             * @param source a <code>RenderedImage</code>.
0392:             * @param configuration Configurable attributes of the image including
0393:             *        configuration variables indexed by
0394:             *        <code>RenderingHints.Key</code>s and image properties indexed
0395:             *        by <code>String</code>s or <code>CaselessStringKey</code>s.
0396:             *        This is simply forwarded to the superclass constructor.
0397:             * @param cobbleSources a boolean indicating whether
0398:             *        <code>computeRect</code> expects contiguous sources.
0399:             * @param extender a <code>BorderExtender</code>, or <code>null</code>.
0400:             * @param interp an <code>Interpolation</code> object to use for
0401:             *        resampling.
0402:             * @param scaleX scale factor along x axis.
0403:             * @param scaleY scale factor along y axis.
0404:             * @param transX translation factor along x axis.
0405:             * @param transY translation factor along y axis.
0406:             *
0407:             * @throws IllegalArgumentException if <code>source</code>
0408:             *         is <code>null</code>.
0409:             * @throws IllegalArgumentException if combining the
0410:             *         source bounds with the layout parameter results in negative
0411:             *         output width or height.
0412:             *
0413:             * @since JAI 1.1
0414:             */
0415:            public ScaleOpImage(RenderedImage source, ImageLayout layout,
0416:                    Map configuration, boolean cobbleSources,
0417:                    BorderExtender extender, Interpolation interp,
0418:                    float scaleX, float scaleY, float transX, float transY) {
0419:                super (
0420:                        vectorize(source), // vectorize() checks for null source.
0421:                        layoutHelper(source, scaleX, scaleY, transX, transY,
0422:                                interp, layout), configHelper(source,
0423:                                configuration, interp), cobbleSources,
0424:                        extender, interp, null);
0425:
0426:                this .scaleX = scaleX;
0427:                this .scaleY = scaleY;
0428:                this .transX = transX;
0429:                this .transY = transY;
0430:
0431:                // Represent the scale factors as Rational numbers.
0432:                // Since a value of 1.2 is represented as 1.200001 which
0433:                // throws the forward/backward mapping in certain situations.
0434:                // Convert the scale and translation factors to Rational numbers
0435:                this .scaleXRational = Rational.approximate(scaleX,
0436:                        rationalTolerance);
0437:                this .scaleYRational = Rational.approximate(scaleY,
0438:                        rationalTolerance);
0439:
0440:                this .scaleXRationalNum = (long) this .scaleXRational.num;
0441:                this .scaleXRationalDenom = (long) this .scaleXRational.denom;
0442:                this .scaleYRationalNum = (long) this .scaleYRational.num;
0443:                this .scaleYRationalDenom = (long) this .scaleYRational.denom;
0444:
0445:                this .transXRational = Rational.approximate(transX,
0446:                        rationalTolerance);
0447:                this .transYRational = Rational.approximate(transY,
0448:                        rationalTolerance);
0449:
0450:                this .transXRationalNum = (long) this .transXRational.num;
0451:                this .transXRationalDenom = (long) this .transXRational.denom;
0452:                this .transYRationalNum = (long) this .transYRational.num;
0453:                this .transYRationalDenom = (long) this .transYRational.denom;
0454:
0455:                // Inverse scale factors as Rationals
0456:                invScaleXRational = new Rational(scaleXRational);
0457:                invScaleXRational.invert();
0458:                invScaleYRational = new Rational(scaleYRational);
0459:                invScaleYRational.invert();
0460:                invScaleXRationalNum = invScaleXRational.num;
0461:                invScaleXRationalDenom = invScaleXRational.denom;
0462:                invScaleYRationalNum = invScaleYRational.num;
0463:                invScaleYRationalDenom = invScaleYRational.denom;
0464:
0465:                lpad = interp.getLeftPadding();
0466:                rpad = interp.getRightPadding();
0467:                tpad = interp.getTopPadding();
0468:                bpad = interp.getBottomPadding();
0469:
0470:                if (extender == null) {
0471:
0472:                    // Get the source dimensions
0473:                    int x0 = source.getMinX();
0474:                    int y0 = source.getMinY();
0475:                    int w = source.getWidth();
0476:                    int h = source.getHeight();
0477:
0478:                    // The first source pixel (x0, y0)
0479:                    long dx0Num, dx0Denom, dy0Num, dy0Denom;
0480:
0481:                    // The first pixel (x1, y1) that is just outside the source
0482:                    long dx1Num, dx1Denom, dy1Num, dy1Denom;
0483:
0484:                    if (interp instanceof  InterpolationNearest) {
0485:
0486:                        // First point inside the source
0487:                        dx0Num = x0;
0488:                        dx0Denom = 1;
0489:
0490:                        dy0Num = y0;
0491:                        dy0Denom = 1;
0492:
0493:                        // First point outside source
0494:                        // for nearest, x1 = x0 + w, y1 = y0 + h
0495:                        // since anything >= a but < (a+1) maps to a for nearest
0496:
0497:                        // Equivalent to float d_x1 = x0 + w
0498:                        dx1Num = x0 + w;
0499:                        dx1Denom = 1;
0500:
0501:                        // Equivalent to float d_y1 = y0 + h
0502:                        dy1Num = y0 + h;
0503:                        dy1Denom = 1;
0504:
0505:                    } else {
0506:
0507:                        // First point inside the source
0508:                        dx0Num = 2 * x0 + 1;
0509:                        dx0Denom = 2;
0510:
0511:                        dy0Num = 2 * y0 + 1;
0512:                        dy0Denom = 2;
0513:
0514:                        // for other interpolations, x1 = x0+w+0.5, y1 = y0+h+0.5
0515:                        // as derived in the formulae derivation above.
0516:                        dx1Num = 2 * x0 + 2 * w + 1;
0517:                        dx1Denom = 2;
0518:
0519:                        dy1Num = 2 * y0 + 2 * h + 1;
0520:                        dy1Denom = 2;
0521:
0522:                        // Equivalent to x0 += lpad;
0523:                        dx0Num += dx0Denom * lpad;
0524:                        // Equivalent to y0 += tpad;
0525:                        dy0Num += dy0Denom * tpad;
0526:
0527:                        // Equivalent to x1 -= rpad;
0528:                        dx1Num -= dx1Denom * rpad;
0529:                        // Equivalent to y1 += bpad;
0530:                        dy1Num -= dy1Denom * bpad;
0531:                    }
0532:
0533:                    // Forward map the first and last source points
0534:
0535:                    // Equivalent to  float d_x0 = x0 * scaleX;
0536:                    dx0Num *= scaleXRationalNum;
0537:                    dx0Denom *= scaleXRationalDenom;
0538:
0539:                    // Add the X translation factor d_x0 += transX
0540:                    dx0Num = dx0Num * transXRationalDenom + transXRationalNum
0541:                            * dx0Denom;
0542:                    dx0Denom *= transXRationalDenom;
0543:
0544:                    // Equivalent to float d_y0 = y0 * scaleY;
0545:                    dy0Num *= scaleYRationalNum;
0546:                    dy0Denom *= scaleYRationalDenom;
0547:
0548:                    //  Add the Y translation factor, float d_y0 += transY
0549:                    dy0Num = dy0Num * transYRationalDenom + transYRationalNum
0550:                            * dy0Denom;
0551:                    dy0Denom *= transYRationalDenom;
0552:
0553:                    // Equivalent to  float d_x1 = x1 * scaleX;
0554:                    dx1Num *= scaleXRationalNum;
0555:                    dx1Denom *= scaleXRationalDenom;
0556:
0557:                    // Add the X translation factor d_x1 += transX
0558:                    dx1Num = dx1Num * transXRationalDenom + transXRationalNum
0559:                            * dx1Denom;
0560:                    dx1Denom *= transXRationalDenom;
0561:
0562:                    // Equivalent to float d_y1 = y1 * scaleY;
0563:                    dy1Num *= scaleYRationalNum;
0564:                    dy1Denom *= scaleYRationalDenom;
0565:
0566:                    //  Add the Y translation factor, float d_y1 += transY
0567:                    dy1Num = dy1Num * transYRationalDenom + transYRationalNum
0568:                            * dy1Denom;
0569:                    dy1Denom *= transYRationalDenom;
0570:
0571:                    // Get the integral coordinates
0572:
0573:                    int l_x0, l_y0, l_x1, l_y1;
0574:
0575:                    // Subtract 0.5 from dx0, dy0
0576:                    dx0Num = 2 * dx0Num - dx0Denom;
0577:                    dx0Denom *= 2;
0578:
0579:                    dy0Num = 2 * dy0Num - dy0Denom;
0580:                    dy0Denom *= 2;
0581:
0582:                    l_x0 = Rational.ceil(dx0Num, dx0Denom);
0583:                    l_y0 = Rational.ceil(dy0Num, dy0Denom);
0584:
0585:                    // Subtract 0.5 from dx1, dy1
0586:                    dx1Num = 2 * dx1Num - dx1Denom;
0587:                    dx1Denom *= 2;
0588:
0589:                    dy1Num = 2 * dy1Num - dy1Denom;
0590:                    dy1Denom *= 2;
0591:
0592:                    l_x1 = (int) Rational.floor(dx1Num, dx1Denom);
0593:                    // l_x1 must be less than but not equal to (dx1Num/dx1Denom)
0594:                    if ((l_x1 * dx1Denom) == dx1Num) {
0595:                        l_x1 -= 1;
0596:                    }
0597:
0598:                    l_y1 = (int) Rational.floor(dy1Num, dy1Denom);
0599:                    if (l_y1 * dy1Denom == dy1Num) {
0600:                        l_y1 -= 1;
0601:                    }
0602:
0603:                    computableBounds = new Rectangle(l_x0, l_y0,
0604:                            (l_x1 - l_x0 + 1), (l_y1 - l_y0 + 1));
0605:                } else {
0606:                    // If extender is present we can write the entire destination.
0607:                    computableBounds = getBounds();
0608:                }
0609:            }
0610:
0611:            /**
0612:             * Returns the number of samples required to the left of the center.
0613:             *
0614:             * @return The left padding factor.
0615:             *
0616:             * @deprecated as of JAI 1.1.
0617:             */
0618:            public int getLeftPadding() {
0619:                return interp == null ? 0 : interp.getLeftPadding();
0620:            }
0621:
0622:            /**
0623:             * Returns the number of samples required to the right of the center.
0624:             *
0625:             * @return The right padding factor.
0626:             *
0627:             * @deprecated as of JAI 1.1.
0628:             */
0629:            public int getRightPadding() {
0630:                return interp == null ? 0 : interp.getRightPadding();
0631:            }
0632:
0633:            /**
0634:             * Returns the number of samples required above the center.
0635:             *
0636:             * @return The top padding factor.
0637:             *
0638:             * @deprecated as of JAI 1.1.
0639:             */
0640:            public int getTopPadding() {
0641:                return interp == null ? 0 : interp.getTopPadding();
0642:            }
0643:
0644:            /**
0645:             * Returns the number of samples required below the center.
0646:             *
0647:             * @return The bottom padding factor.
0648:             *
0649:             * @deprecated as of JAI 1.1.
0650:             */
0651:            public int getBottomPadding() {
0652:                return interp == null ? 0 : interp.getBottomPadding();
0653:            }
0654:
0655:            /**
0656:             * Computes the position in the specified source that best
0657:             * matches the supplied destination image position.
0658:             *
0659:             * <p>The implementation in this class returns the value of
0660:             * <code>pt</code> in the following code snippet:
0661:             *
0662:             * <pre>
0663:             * Point2D pt = (Point2D)destPt.clone();
0664:             * pt.setLocation((destPt.getX() - transX + 0.5)/scaleX - 0.5,
0665:             *                (destPt.getY() - transY + 0.5)/scaleY - 0.5);
0666:             * </pre>
0667:             *
0668:             * Subclasses requiring different behavior should override this
0669:             * method.</p>
0670:             *
0671:             * @param destPt the position in destination image coordinates
0672:             * to map to source image coordinates.
0673:             * @param sourceIndex the index of the source image.
0674:             *
0675:             * @return a <code>Point2D</code> of the same class as
0676:             * <code>destPt</code>.
0677:             *
0678:             * @throws IllegalArgumentException if <code>destPt</code> is
0679:             * <code>null</code>.
0680:             * @throws IndexOutOfBoundsException if <code>sourceIndex</code> is
0681:             * non-zero.
0682:             *
0683:             * @since JAI 1.1.2
0684:             */
0685:            public Point2D mapDestPoint(Point2D destPt, int sourceIndex) {
0686:                if (destPt == null) {
0687:                    throw new IllegalArgumentException(JaiI18N
0688:                            .getString("Generic0"));
0689:                } else if (sourceIndex != 0) {
0690:                    throw new IndexOutOfBoundsException(JaiI18N
0691:                            .getString("Generic1"));
0692:                }
0693:
0694:                Point2D pt = (Point2D) destPt.clone();
0695:
0696:                pt.setLocation((destPt.getX() - transX + 0.5) / scaleX - 0.5,
0697:                        (destPt.getY() - transY + 0.5) / scaleY - 0.5);
0698:
0699:                return pt;
0700:            }
0701:
0702:            /**
0703:             * Computes the position in the destination that best
0704:             * matches the supplied source image position.
0705:             *
0706:             * <p>The implementation in this class returns the value of
0707:             * <code>pt</code> in the following code snippet:
0708:             *
0709:             * <pre>
0710:             * Point2D pt = (Point2D)sourcePt.clone();
0711:             * pt.setLocation(scaleX*(sourcePt.getX() + 0.5) + transX - 0.5,
0712:             *                scaleY*(sourcePt.getY() + 0.5) + transY - 0.5);
0713:             * </pre>
0714:             *
0715:             * Subclasses requiring different behavior should override this
0716:             * method.</p>
0717:             *
0718:             * @param sourcePt the position in source image coordinates
0719:             * to map to destination image coordinates.
0720:             * @param sourceIndex the index of the source image.
0721:             *
0722:             * @return a <code>Point2D</code> of the same class as
0723:             * <code>sourcePt</code>.
0724:             *
0725:             * @throws IllegalArgumentException if <code>sourcePt</code> is
0726:             * <code>null</code>.
0727:             * @throws IndexOutOfBoundsException if <code>sourceIndex</code> is
0728:             * non-zero.
0729:             *
0730:             * @since JAI 1.1.2
0731:             */
0732:            public Point2D mapSourcePoint(Point2D sourcePt, int sourceIndex) {
0733:                if (sourcePt == null) {
0734:                    throw new IllegalArgumentException(JaiI18N
0735:                            .getString("Generic0"));
0736:                } else if (sourceIndex != 0) {
0737:                    throw new IndexOutOfBoundsException(JaiI18N
0738:                            .getString("Generic1"));
0739:                }
0740:
0741:                Point2D pt = (Point2D) sourcePt.clone();
0742:
0743:                pt.setLocation(scaleX * (sourcePt.getX() + 0.5) + transX - 0.5,
0744:                        scaleY * (sourcePt.getY() + 0.5) + transY - 0.5);
0745:
0746:                return pt;
0747:            }
0748:
0749:            /**
0750:             * Returns the minimum bounding box of the region of the destination
0751:             * to which a particular <code>Rectangle</code> of the specified source
0752:             * will be mapped.
0753:             *
0754:             * @param sourceRect the <code>Rectangle</code> in source coordinates.
0755:             * @param sourceIndex the index of the source image.
0756:             *
0757:             * @return a <code>Rectangle</code> indicating the destination
0758:             *         bounding box, or <code>null</code> if the bounding box
0759:             *         is unknown.
0760:             *
0761:             * @throws IllegalArgumentException if <code>sourceIndex</code> is
0762:             *         negative or greater than the index of the last source.
0763:             * @throws IllegalArgumentException if <code>sourceRect</code> is
0764:             *         <code>null</code>.
0765:             *
0766:             * @since JAI 1.1
0767:             */
0768:            protected Rectangle forwardMapRect(Rectangle sourceRect,
0769:                    int sourceIndex) {
0770:
0771:                if (sourceRect == null) {
0772:                    throw new IllegalArgumentException(JaiI18N
0773:                            .getString("Generic0"));
0774:                }
0775:
0776:                if (sourceIndex != 0) {
0777:                    throw new IllegalArgumentException(JaiI18N
0778:                            .getString("Generic1"));
0779:                }
0780:
0781:                // Get the source dimensions
0782:                int x0 = sourceRect.x;
0783:                int y0 = sourceRect.y;
0784:                int w = sourceRect.width;
0785:                int h = sourceRect.height;
0786:
0787:                // Variables to represent the first pixel inside the destination. 
0788:                long dx0Num, dx0Denom, dy0Num, dy0Denom;
0789:
0790:                // Variables to represent the last destination pixel.
0791:                long dx1Num, dx1Denom, dy1Num, dy1Denom;
0792:
0793:                if (interp instanceof  InterpolationNearest) {
0794:
0795:                    // First point inside the source
0796:                    dx0Num = x0;
0797:                    dx0Denom = 1;
0798:
0799:                    dy0Num = y0;
0800:                    dy0Denom = 1;
0801:
0802:                    // First point outside source
0803:                    // for nearest, x1 = x0 + w, y1 = y0 + h
0804:                    // since anything >= a and < a+1 maps to a for nearest, since
0805:                    // we use floor to calculate the integral source position
0806:
0807:                    // Equivalent to float d_x1 = x0 + w
0808:                    dx1Num = x0 + w;
0809:                    dx1Denom = 1;
0810:
0811:                    // Equivalent to float d_y1 = y0 + h
0812:                    dy1Num = y0 + h;
0813:                    dy1Denom = 1;
0814:
0815:                } else {
0816:
0817:                    // First point inside the source (x0 + 0.5, y0 + 0.5)
0818:                    dx0Num = 2 * x0 + 1;
0819:                    dx0Denom = 2;
0820:
0821:                    dy0Num = 2 * y0 + 1;
0822:                    dy0Denom = 2;
0823:
0824:                    // for other interpolations, x1 = x0 + w + 0.5, y1 = y0 + h + 0.5
0825:                    // as derived in the formulae derivation above.
0826:                    dx1Num = 2 * x0 + 2 * w + 1;
0827:                    dx1Denom = 2;
0828:
0829:                    dy1Num = 2 * y0 + 2 * h + 1;
0830:                    dy1Denom = 2;
0831:                }
0832:
0833:                // Forward map first and last source positions
0834:
0835:                // Equivalent to  float d_x0 = x0 * scaleX;
0836:                dx0Num = dx0Num * scaleXRationalNum;
0837:                dx0Denom *= scaleXRationalDenom;
0838:
0839:                // Equivalent to float d_y0 = y0 * scaleY;
0840:                dy0Num = dy0Num * scaleYRationalNum;
0841:                dy0Denom *= scaleYRationalDenom;
0842:
0843:                // Equivalent to  float d_x1 = x1 * scaleX;
0844:                dx1Num = dx1Num * scaleXRationalNum;
0845:                dx1Denom *= scaleXRationalDenom;
0846:
0847:                // Equivalent to float d_y1 = y1 * scaleY;
0848:                dy1Num = dy1Num * scaleYRationalNum;
0849:                dy1Denom *= scaleYRationalDenom;
0850:
0851:                // Add the translation factors.
0852:
0853:                //  Equivalent to float d_x0 += transX
0854:                dx0Num = dx0Num * transXRationalDenom + transXRationalNum
0855:                        * dx0Denom;
0856:                dx0Denom *= transXRationalDenom;
0857:
0858:                //  Equivalent to float d_y0 += transY
0859:                dy0Num = dy0Num * transYRationalDenom + transYRationalNum
0860:                        * dy0Denom;
0861:                dy0Denom *= transYRationalDenom;
0862:
0863:                //  Equivalent to float d_x1 += transX
0864:                dx1Num = dx1Num * transXRationalDenom + transXRationalNum
0865:                        * dx1Denom;
0866:                dx1Denom *= transXRationalDenom;
0867:
0868:                //  Equivalent to float d_y1 += transY
0869:                dy1Num = dy1Num * transYRationalDenom + transYRationalNum
0870:                        * dy1Denom;
0871:                dy1Denom *= transYRationalDenom;
0872:
0873:                // Get the integral coordinates
0874:                int l_x0, l_y0, l_x1, l_y1;
0875:
0876:                // Subtract 0.5 from dx0, dy0
0877:                dx0Num = 2 * dx0Num - dx0Denom;
0878:                dx0Denom *= 2;
0879:
0880:                dy0Num = 2 * dy0Num - dy0Denom;
0881:                dy0Denom *= 2;
0882:
0883:                l_x0 = Rational.ceil(dx0Num, dx0Denom);
0884:                l_y0 = Rational.ceil(dy0Num, dy0Denom);
0885:
0886:                // Subtract 0.5 from dx1, dy1
0887:                dx1Num = 2 * dx1Num - dx1Denom;
0888:                dx1Denom *= 2;
0889:
0890:                dy1Num = 2 * dy1Num - dy1Denom;
0891:                dy1Denom *= 2;
0892:
0893:                l_x1 = (int) Rational.floor(dx1Num, dx1Denom);
0894:                if ((l_x1 * dx1Denom) == dx1Num) {
0895:                    l_x1 -= 1;
0896:                }
0897:
0898:                l_y1 = (int) Rational.floor(dy1Num, dy1Denom);
0899:                if ((l_y1 * dy1Denom) == dy1Num) {
0900:                    l_y1 -= 1;
0901:                }
0902:
0903:                return new Rectangle(l_x0, l_y0, (l_x1 - l_x0 + 1), (l_y1
0904:                        - l_y0 + 1));
0905:            }
0906:
0907:            /**
0908:             * Returns the minimum bounding box of the region of the specified
0909:             * source to which a particular <code>Rectangle</code> of the
0910:             * destination will be mapped.
0911:             *
0912:             * @param destRect the <code>Rectangle</code> in destination coordinates.
0913:             * @param sourceIndex the index of the source image.
0914:             *
0915:             * @return a <code>Rectangle</code> indicating the source bounding box,
0916:             *         or <code>null</code> if the bounding box is unknown.
0917:             *
0918:             * @throws IllegalArgumentException if <code>sourceIndex</code> is
0919:             *         negative or greater than the index of the last source.
0920:             * @throws IllegalArgumentException if <code>destRect</code> is
0921:             *         <code>null</code>.
0922:             *
0923:             * @since JAI 1.1
0924:             */
0925:            protected Rectangle backwardMapRect(Rectangle destRect,
0926:                    int sourceIndex) {
0927:
0928:                if (destRect == null) {
0929:                    throw new IllegalArgumentException(JaiI18N
0930:                            .getString("Generic0"));
0931:                }
0932:
0933:                if (sourceIndex != 0) {
0934:                    throw new IllegalArgumentException(JaiI18N
0935:                            .getString("Generic1"));
0936:                }
0937:
0938:                // Get the destination rectangle coordinates and dimensions
0939:                int x0 = destRect.x;
0940:                int y0 = destRect.y;
0941:                int w = destRect.width;
0942:                int h = destRect.height;
0943:
0944:                // Variables that will eventually hold the source pixel
0945:                // positions which are the result of the backward map
0946:                long sx0Num, sx0Denom, sy0Num, sy0Denom;
0947:
0948:                // First destination point that will be backward mapped
0949:                // will be dx0 + 0.5, dy0 + 0.5
0950:                sx0Num = (x0 * 2 + 1);
0951:                sx0Denom = 2;
0952:
0953:                sy0Num = (y0 * 2 + 1);
0954:                sy0Denom = 2;
0955:
0956:                // The last destination pixel to be backward mapped will be
0957:                // dx0 + w - 1 + 0.5, dy0 + h - 1 + 0.5 i.e.
0958:                // dx0 + w - 0.5, dy0 + h - 0.5
0959:                long sx1Num, sx1Denom, sy1Num, sy1Denom;
0960:
0961:                // Equivalent to float sx1 = dx0 + dw - 0.5;
0962:                sx1Num = 2 * x0 + 2 * w - 1;
0963:                sx1Denom = 2;
0964:
0965:                // Equivalent to float sy1 = dy0 + dh - 0.5;
0966:                sy1Num = 2 * y0 + 2 * h - 1;
0967:                sy1Denom = 2;
0968:
0969:                // Subtract the translation factors.
0970:                sx0Num = sx0Num * transXRationalDenom - transXRationalNum
0971:                        * sx0Denom;
0972:                sx0Denom *= transXRationalDenom;
0973:
0974:                sy0Num = sy0Num * transYRationalDenom - transYRationalNum
0975:                        * sy0Denom;
0976:                sy0Denom *= transYRationalDenom;
0977:
0978:                sx1Num = sx1Num * transXRationalDenom - transXRationalNum
0979:                        * sx1Denom;
0980:                sx1Denom *= transXRationalDenom;
0981:
0982:                sy1Num = sy1Num * transYRationalDenom - transYRationalNum
0983:                        * sy1Denom;
0984:                sy1Denom *= transYRationalDenom;
0985:
0986:                // Backward map both the destination positions
0987:
0988:                // Equivalent to  float sx0 = x0 / scaleX;
0989:                sx0Num *= invScaleXRationalNum;
0990:                sx0Denom *= invScaleXRationalDenom;
0991:
0992:                sy0Num *= invScaleYRationalNum;
0993:                sy0Denom *= invScaleYRationalDenom;
0994:
0995:                sx1Num *= invScaleXRationalNum;
0996:                sx1Denom *= invScaleXRationalDenom;
0997:
0998:                sy1Num *= invScaleYRationalNum;
0999:                sy1Denom *= invScaleYRationalDenom;
1000:
1001:                int s_x0 = 0, s_y0 = 0, s_x1 = 0, s_y1 = 0;
1002:                if (interp instanceof  InterpolationNearest) {
1003:
1004:                    // Floor sx0, sy0
1005:                    s_x0 = Rational.floor(sx0Num, sx0Denom);
1006:                    s_y0 = Rational.floor(sy0Num, sy0Denom);
1007:
1008:                    // Equivalent to (int)Math.floor(sx1)
1009:                    s_x1 = Rational.floor(sx1Num, sx1Denom);
1010:
1011:                    // Equivalent to (int)Math.floor(sy1)
1012:                    s_y1 = Rational.floor(sy1Num, sy1Denom);
1013:
1014:                } else {
1015:                    // For all other interpolations
1016:
1017:                    // Equivalent to (int) Math.floor(sx0 - 0.5)
1018:                    s_x0 = Rational.floor(2 * sx0Num - sx0Denom, 2 * sx0Denom);
1019:
1020:                    // Equivalent to (int) Math.floor(sy0 - 0.5)
1021:                    s_y0 = Rational.floor(2 * sy0Num - sy0Denom, 2 * sy0Denom);
1022:
1023:                    // Calculate the last source point
1024:                    s_x1 = Rational.floor(2 * sx1Num - sx1Denom, 2 * sx1Denom);
1025:
1026:                    // Equivalent to (int)Math.ceil(sy1 - 0.5)
1027:                    s_y1 = Rational.floor(2 * sy1Num - sy1Denom, 2 * sy1Denom);
1028:                }
1029:
1030:                return new Rectangle(s_x0, s_y0, (s_x1 - s_x0 + 1), (s_y1
1031:                        - s_y0 + 1));
1032:            }
1033:
1034:            /**
1035:             * Computes a tile.  If source cobbling was requested at
1036:             * construction time, the source tile boundaries are overlayed
1037:             * onto the destination, cobbling is performed for areas that
1038:             * intersect multiple source tiles, and
1039:             * <code>computeRect(Raster[], WritableRaster, Rectangle)</code>
1040:             * is called for each of the resulting regions.  Otherwise,
1041:             * <code>computeRect(PlanarImage[], WritableRaster,
1042:             * Rectangle)</code> is called once to compute the entire active
1043:             * area of the tile.
1044:             *
1045:             * <p> The image bounds may be larger than the bounds of the
1046:             * source image.  In this case, samples for which there are no
1047:             * corresponding sources are set to zero.
1048:             *
1049:             * <p> The following steps are performed in order to compute the tile:
1050:             * <ul>
1051:             * <li> The destination tile is backward mapped to compute the needed
1052:             * source.
1053:             * <li> This source is then split on tile boundaries to produce rectangles
1054:             * that do not cross tile boundaries.
1055:             * <li> These source rectangles are then forward mapped to produce
1056:             * destination rectangles, and the computeRect method is called for
1057:             * each corresponding pair of source and destination rectangles.
1058:             * <li> For higher order interpolations, some source cobbling across tile
1059:             * boundaries does occur.
1060:             * </ul>
1061:             *
1062:             * @param tileX The X index of the tile.
1063:             * @param tileY The Y index of the tile.
1064:             *
1065:             * @return The tile as a <code>Raster</code>.
1066:             */
1067:            public Raster computeTile(int tileX, int tileY) {
1068:
1069:                if (!cobbleSources) {
1070:                    return super .computeTile(tileX, tileY);
1071:                }
1072:
1073:                // X and Y coordinate of the pixel pixel of the tile.
1074:                int orgX = tileXToX(tileX);
1075:                int orgY = tileYToY(tileY);
1076:
1077:                // Create a new WritableRaster to represent this tile.
1078:                WritableRaster dest = createWritableRaster(sampleModel,
1079:                        new Point(orgX, orgY));
1080:
1081:                Rectangle rect = new Rectangle(orgX, orgY, tileWidth,
1082:                        tileHeight);
1083:
1084:                // Clip dest rectangle against the part of the destination
1085:                // rectangle that can be written.
1086:                Rectangle destRect = rect.intersection(computableBounds);
1087:                if ((destRect.width <= 0) || (destRect.height <= 0)) {
1088:                    // If empty rectangle, return empty tile.
1089:                    return dest;
1090:                }
1091:
1092:                // Get the source rectangle required to compute the destRect
1093:                Rectangle srcRect = mapDestRect(destRect, 0);
1094:                Raster[] sources = new Raster[1];
1095:
1096:                // Split the source on tile boundaries.
1097:                // Get the new pairs of src & dest Rectangles
1098:
1099:                // The tileWidth and tileHeight of the source image
1100:                // may differ from this tileWidth and tileHeight.
1101:                PlanarImage source0 = getSource(0);
1102:
1103:                IntegerSequence srcXSplits = new IntegerSequence();
1104:                IntegerSequence srcYSplits = new IntegerSequence();
1105:                source0.getSplits(srcXSplits, srcYSplits, srcRect);
1106:
1107:                if (srcXSplits.getNumElements() == 1
1108:                        && srcYSplits.getNumElements() == 1) {
1109:
1110:                    // If the source is fully contained within
1111:                    // a tile there is no need to split it any further.
1112:                    if (extender == null) {
1113:                        sources[0] = source0.getData(srcRect);
1114:                    } else {
1115:                        sources[0] = source0.getExtendedData(srcRect, extender);
1116:                    }
1117:
1118:                    // Compute the destination tile.
1119:                    computeRect(sources, dest, destRect);
1120:                } else {
1121:                    // Source Rect straddles 2 or more tiles
1122:
1123:                    // Get Source Tilewidth & height
1124:                    int srcTileWidth = source0.getTileWidth();
1125:                    int srcTileHeight = source0.getTileHeight();
1126:
1127:                    srcYSplits.startEnumeration();
1128:                    while (srcYSplits.hasMoreElements()) {
1129:                        // Along Y TileBoundaries
1130:                        int ysplit = srcYSplits.nextElement();
1131:
1132:                        srcXSplits.startEnumeration();
1133:                        while (srcXSplits.hasMoreElements()) {
1134:                            // Along X TileBoundaries
1135:                            int xsplit = srcXSplits.nextElement();
1136:
1137:                            // Construct a pseudo tile for intersection purposes
1138:                            Rectangle srcTile = new Rectangle(xsplit, ysplit,
1139:                                    srcTileWidth, srcTileHeight);
1140:
1141:                            // Intersect the tile with the source Rectangle
1142:                            Rectangle newSrcRect = srcRect
1143:                                    .intersection(srcTile);
1144:
1145:                            //
1146:                            // The new source rect could be of size less than or equal
1147:                            // to the interpolation kernel dimensions. In which case
1148:                            // the forward map produces null destination rectangles.
1149:                            // Hence we need to deal with these cases in the manner
1150:                            // implemented below (grow the source before the map. This
1151:                            // would result in source cobbling). Not an issue for
1152:                            // Nearest-Neighbour.
1153:                            //
1154:                            if (!(interp instanceof  InterpolationNearest)) {
1155:
1156:                                if (newSrcRect.width <= interp.getWidth()) {
1157:
1158:                                    //
1159:                                    // Need to forward map this source rectangle.
1160:                                    // Since we need a minimum of 2 * (lpad + rpad + 1)
1161:                                    // in order to process, we contsruct a source
1162:                                    // rectangle of that size, forward map and then
1163:                                    // process the resulting destination rectangle.
1164:                                    //
1165:                                    Rectangle wSrcRect = new Rectangle();
1166:                                    Rectangle wDestRect;
1167:
1168:                                    wSrcRect.x = newSrcRect.x;
1169:                                    wSrcRect.y = newSrcRect.y - tpad - 1;
1170:                                    wSrcRect.width = 2 * (lpad + rpad + 1);
1171:                                    wSrcRect.height = newSrcRect.height + bpad
1172:                                            + tpad + 2;
1173:
1174:                                    wSrcRect = wSrcRect.intersection(source0
1175:                                            .getBounds());
1176:
1177:                                    wDestRect = mapSourceRect(wSrcRect, 0);
1178:
1179:                                    //
1180:                                    // Make sure this destination rectangle is
1181:                                    // within the bounds of our original writable
1182:                                    // destination rectangle
1183:                                    //
1184:                                    wDestRect = wDestRect
1185:                                            .intersection(destRect);
1186:
1187:                                    if ((wDestRect.width > 0)
1188:                                            && (wDestRect.height > 0)) {
1189:                                        // Do the operations with these new rectangles
1190:                                        if (extender == null) {
1191:                                            sources[0] = source0
1192:                                                    .getData(wSrcRect);
1193:                                        } else {
1194:                                            sources[0] = source0
1195:                                                    .getExtendedData(wSrcRect,
1196:                                                            extender);
1197:                                        }
1198:
1199:                                        // Compute the destination tile.
1200:                                        computeRect(sources, dest, wDestRect);
1201:                                    }
1202:                                }
1203:
1204:                                if (newSrcRect.height <= interp.getHeight()) {
1205:
1206:                                    //
1207:                                    // Need to forward map this source rectangle.
1208:                                    // Since we need a minimum of 2 * (tpad + bpad + 1)
1209:                                    // in order to process, we create a source
1210:                                    // rectangle of that size, forward map and then
1211:                                    // process the resulting destinaltion rectangle
1212:                                    //
1213:                                    Rectangle hSrcRect = new Rectangle();
1214:                                    Rectangle hDestRect;
1215:
1216:                                    hSrcRect.x = newSrcRect.x - lpad - 1;
1217:                                    hSrcRect.y = newSrcRect.y;
1218:                                    hSrcRect.width = newSrcRect.width + lpad
1219:                                            + rpad + 2;
1220:                                    hSrcRect.height = 2 * (tpad + bpad + 1);
1221:
1222:                                    hSrcRect = hSrcRect.intersection(source0
1223:                                            .getBounds());
1224:
1225:                                    hDestRect = mapSourceRect(hSrcRect, 0);
1226:
1227:                                    //
1228:                                    // Make sure this destination rectangle is
1229:                                    // within the bounds of our original writable
1230:                                    // destination rectangle
1231:                                    //
1232:                                    hDestRect = hDestRect
1233:                                            .intersection(destRect);
1234:
1235:                                    if ((hDestRect.width > 0)
1236:                                            && (hDestRect.height > 0)) {
1237:                                        // Do the operations with these new rectangles
1238:                                        if (extender == null) {
1239:                                            sources[0] = source0
1240:                                                    .getData(hSrcRect);
1241:                                        } else {
1242:                                            sources[0] = source0
1243:                                                    .getExtendedData(hSrcRect,
1244:                                                            extender);
1245:                                        }
1246:
1247:                                        // Compute the destination tile.
1248:                                        computeRect(sources, dest, hDestRect);
1249:                                    }
1250:                                }
1251:                            }
1252:
1253:                            // Process source rectangle
1254:                            if ((newSrcRect.width > 0)
1255:                                    && (newSrcRect.height > 0)) {
1256:
1257:                                // Forward map this source rectangle
1258:                                // to get the destination rectangle
1259:                                Rectangle newDestRect = mapSourceRect(
1260:                                        newSrcRect, 0);
1261:
1262:                                // Make sure this destination rectangle is
1263:                                // within the bounds of our original writable
1264:                                // destination rectangle
1265:                                newDestRect = newDestRect
1266:                                        .intersection(destRect);
1267:
1268:                                if ((newDestRect.width > 0)
1269:                                        && (newDestRect.height > 0)) {
1270:
1271:                                    // Do the operations with these new rectangles
1272:                                    if (extender == null) {
1273:                                        sources[0] = source0
1274:                                                .getData(newSrcRect);
1275:                                    } else {
1276:                                        sources[0] = source0.getExtendedData(
1277:                                                newSrcRect, extender);
1278:                                    }
1279:
1280:                                    // Compute the destination tile.
1281:                                    computeRect(sources, dest, newDestRect);
1282:                                }
1283:
1284:                                //
1285:                                // Since mapSourceRect (forward map) shrinks the
1286:                                // source rectangle before the map, there are areas
1287:                                // of this rectangle which never get mapped.
1288:                                //
1289:                                // These occur at the tile boundaries between
1290:                                // rectangles. The following algorithm handles
1291:                                // these edge conditions.
1292:                                //
1293:                                // The cases :
1294:                                //     Right edge
1295:                                //     Bottom edge
1296:                                //     Lower Right Corner
1297:                                //
1298:
1299:                                if (!(interp instanceof  InterpolationNearest)) {
1300:                                    Rectangle RTSrcRect = new Rectangle();
1301:                                    Rectangle RTDestRect;
1302:
1303:                                    // Right Edge
1304:                                    RTSrcRect.x = newSrcRect.x
1305:                                            + newSrcRect.width - 1 - rpad
1306:                                            - lpad;
1307:                                    RTSrcRect.y = newSrcRect.y;
1308:
1309:                                    //
1310:                                    // The amount of src not used from the end of
1311:                                    // the first tile is rpad + 0.5. The amount
1312:                                    // not used from the beginning of the next tile
1313:                                    // is lpad + 0.5. Since we cannot start mapping
1314:                                    // at 0.5, we need to get the area of the half
1315:                                    // pixel on both sides. So we get another 0,5
1316:                                    // from both sides. In total (rpad + 0.5 +
1317:                                    // 0.5) + (lpad + 0.5 + 0.5)
1318:                                    // Since mapSourceRect subtracts rpad + 0.5 and
1319:                                    // lpad + 0.5 from the source before the
1320:                                    // forward map, we need to add that in.
1321:                                    //
1322:                                    RTSrcRect.width = 2 * (lpad + rpad + 1);
1323:                                    RTSrcRect.height = newSrcRect.height;
1324:
1325:                                    RTDestRect = mapSourceRect(RTSrcRect, 0);
1326:
1327:                                    // Clip this against the whole destrect
1328:                                    RTDestRect = RTDestRect
1329:                                            .intersection(destRect);
1330:
1331:                                    // RTSrcRect may be out of image bounds;
1332:                                    // map one more time
1333:                                    RTSrcRect = mapDestRect(RTDestRect, 0);
1334:
1335:                                    if (RTDestRect.width > 0
1336:                                            && RTDestRect.height > 0) {
1337:                                        // Do the operations with these new rectangles
1338:                                        if (extender == null) {
1339:                                            sources[0] = source0
1340:                                                    .getData(RTSrcRect);
1341:                                        } else {
1342:                                            sources[0] = source0
1343:                                                    .getExtendedData(RTSrcRect,
1344:                                                            extender);
1345:                                        }
1346:
1347:                                        computeRect(sources, dest, RTDestRect);
1348:                                    }
1349:
1350:                                    // Bottom Edge
1351:                                    Rectangle BTSrcRect = new Rectangle();
1352:                                    Rectangle BTDestRect;
1353:
1354:                                    BTSrcRect.x = newSrcRect.x;
1355:                                    BTSrcRect.y = newSrcRect.y
1356:                                            + newSrcRect.height - 1 - bpad
1357:                                            - tpad;
1358:
1359:                                    //
1360:                                    // The amount of src not used from the end of
1361:                                    // the first tile is tpad + 0.5. The amount
1362:                                    // not used from the beginning of the next tile
1363:                                    // is bpad + 0.5. Since we cannot start mapping
1364:                                    // at 0.5, we need to get the area of the half
1365:                                    // pixel on both sides. So we get another 0,5
1366:                                    // from both sides. In total (tpad + 0.5 +
1367:                                    // 0.5) + (bpad + 0.5 + 0.5)
1368:                                    // Since mapSourceRect subtracts tpad + 0.5 and
1369:                                    // bpad + 0.5 from the source before the
1370:                                    // forward map, we need to add that in.
1371:                                    //
1372:                                    BTSrcRect.width = newSrcRect.width;
1373:                                    BTSrcRect.height = 2 * (tpad + bpad + 1);
1374:
1375:                                    BTDestRect = mapSourceRect(BTSrcRect, 0);
1376:
1377:                                    // Clip this against the whole destrect
1378:                                    BTDestRect = BTDestRect
1379:                                            .intersection(destRect);
1380:
1381:                                    //BTSrcRect maybe out of bounds
1382:                                    //map one more time
1383:                                    BTSrcRect = mapDestRect(BTDestRect, 0);
1384:                                    //end
1385:
1386:                                    if (BTDestRect.width > 0
1387:                                            && BTDestRect.height > 0) {
1388:
1389:                                        // Do the operations with these new rectangles
1390:                                        if (extender == null) {
1391:                                            sources[0] = source0
1392:                                                    .getData(BTSrcRect);
1393:                                        } else {
1394:                                            sources[0] = source0
1395:                                                    .getExtendedData(BTSrcRect,
1396:                                                            extender);
1397:                                        }
1398:
1399:                                        computeRect(sources, dest, BTDestRect);
1400:                                    }
1401:
1402:                                    // Lower Right Area
1403:                                    Rectangle LRTSrcRect = new Rectangle();
1404:                                    Rectangle LRTDestRect;
1405:
1406:                                    LRTSrcRect.x = newSrcRect.x
1407:                                            + newSrcRect.width - 1 - rpad
1408:                                            - lpad;
1409:                                    LRTSrcRect.y = newSrcRect.y
1410:                                            + newSrcRect.height - 1 - bpad
1411:                                            - tpad;
1412:
1413:                                    // Comment forthcoming
1414:                                    LRTSrcRect.width = 2 * (rpad + lpad + 1);
1415:                                    LRTSrcRect.height = 2 * (tpad + bpad + 1);
1416:
1417:                                    LRTDestRect = mapSourceRect(LRTSrcRect, 0);
1418:
1419:                                    // Clip this against the whole destrect
1420:                                    LRTDestRect = LRTDestRect
1421:                                            .intersection(destRect);
1422:
1423:                                    // LRTSrcRect may still be out of bounds
1424:                                    LRTSrcRect = mapDestRect(LRTDestRect, 0);
1425:
1426:                                    if (LRTDestRect.width > 0
1427:                                            && LRTDestRect.height > 0) {
1428:                                        // Do the operations with these new rectangles
1429:                                        if (extender == null) {
1430:                                            sources[0] = source0
1431:                                                    .getData(LRTSrcRect);
1432:                                        } else {
1433:                                            sources[0] = source0
1434:                                                    .getExtendedData(
1435:                                                            LRTSrcRect,
1436:                                                            extender);
1437:                                        }
1438:
1439:                                        computeRect(sources, dest, LRTDestRect);
1440:                                    }
1441:                                }
1442:                            }
1443:                        }
1444:                    }
1445:                }
1446:
1447:                // Return the written destination raster
1448:                return dest;
1449:            }
1450:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.