Source Code Cross Referenced for FilteredSubsampleOpImage.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » com » sun » media » jai » opimage » 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 » com.sun.media.jai.opimage 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: FilteredSubsampleOpImage.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:56:26 $
0010:         * $State: Exp $
0011:         */
0012:        package com.sun.media.jai.opimage;
0013:
0014:        import java.awt.Rectangle;
0015:        import java.awt.geom.Point2D;
0016:        import java.awt.image.Raster;
0017:        import java.awt.image.RenderedImage;
0018:        import java.awt.image.WritableRaster;
0019:        import java.awt.image.DataBuffer;
0020:        import java.awt.image.renderable.ParameterBlock;
0021:        import javax.media.jai.ImageLayout;
0022:        import java.util.Map;
0023:        import javax.media.jai.GeometricOpImage;
0024:        import javax.media.jai.BorderExtender;
0025:        import javax.media.jai.Interpolation;
0026:        import javax.media.jai.InterpolationNearest;
0027:        import javax.media.jai.InterpolationBilinear;
0028:        import javax.media.jai.InterpolationBicubic;
0029:        import javax.media.jai.InterpolationBicubic2;
0030:        import javax.media.jai.RasterAccessor;
0031:        import javax.media.jai.RasterFormatTag;
0032:        import com.sun.media.jai.util.ImageUtil;
0033:
0034:        /**
0035:         * <p> A class extending <code>GeometricOpImage</code> to
0036:         * subsample and antialias filter images.  Image scaling operations
0037:         * require rectilinear backwards mapping and padding by the resampling
0038:         * and filter dimensions.
0039:         *
0040:         * <p> When applying scale factors of scaleX, scaleY to a source image
0041:         * with width of src_width and height of src_height, the resulting image
0042:         * is defined to have the following bounds:
0043:         *
0044:         * <code></pre>
0045:         *       dst minX  = round(src minX  / scaleX) <br>
0046:         *       dst minY  = round(src minY  / scaleY) <br>
0047:         *       dst width  =  round(src width  / scaleX) <br>
0048:         *       dst height =  round(src height / scaleY) <br>
0049:         * </pre></code>
0050:         *
0051:         * <p> The applied filter is quadrant symmetric (typically antialias + resample). The
0052:         * filter is product-separable, quadrant symmetric, and is defined by half of its
0053:         * span. For example, if the input filter, qsFilter, was of size 3, it would have
0054:         * width and height 5 and have the symmetric form:
0055:         *   qs[2] qs[1] qs[0] qs[1] qs[2]
0056:         * Because we have chosen to keep the filters in compact form we need
0057:         * to keep track of parity.
0058:         *
0059:         * <p> A fully expanded 5 by 5 kernel has format (25 entries defined by
0060:         * only 3 entries):
0061:         *
0062:         *   <code>
0063:         *   <p align=center> qs[2]*qs[2]  qs[2]*qs[1]  qs[2]*qs[0]  qs[2]*qs[1]  qs[2]*qs[2] <br>
0064:         *
0065:         *                    qs[1]*qs[2]  qs[1]*qs[1]  qs[1]*qs[0]  qs[1]*qs[1]  qs[1]*qs[2] <br>
0066:         *
0067:         *                    qs[0]*qs[2]  qs[0]*qs[1]  qs[0]*qs[0]  qs[0]*qs[1]  qs[0]*qs[2] <br>
0068:         *
0069:         *                    qs[1]*qs[2]  qs[1]*qs[1]  qs[1]*qs[0]  qs[1]*qs[1]  qs[1]*qs[2] <br>
0070:         *
0071:         *                    qs[2]*qs[2]  qs[2]*qs[1]  qs[2]*qs[0]  qs[2]*qs[1]  qs[2]*qs[2]
0072:         *   </p> </code>
0073:         *
0074:         * <p> Horizontal and vertical kernels representing convolved resample and qsFilter
0075:         * kernels are computed from the input filter, the resample type, and because the
0076:         * downsample factors affect resample weights, the downsample scale factors.  If the
0077:         * scale factors are odd, then the resample kernel is unity.  Parity is used to
0078:         * signify whether the symmetric kernel has a double center (even parity) or a
0079:         * single center value (odd parity).
0080:         *
0081:         * <p> This operator is similar to the image scale operator.  Important
0082:         * differences are described here.  The coordinate transformation differences
0083:         * between the FilteredDownsampleOpImage and the ScaleOpImage operators can be
0084:         * understood by comparing their mapping equations directly.
0085:         *
0086:         * <p> For the scale operator, the destination (D) to source (S) mapping
0087:         * equations are given by
0088:         *
0089:         * <code>
0090:         *   <p> xS = (xD - xTrans)/xScale <br>
0091:         *       yS = (yD - yTrans)/yScale
0092:         * </code>
0093:         *
0094:         * <p> The scale and translation terms are floating point values in D-frame
0095:         * pixel units.  For scale this means that one S pixel maps to xScale
0096:         * by yScale D-frame pixels.  The translation vector, (xTrans, yTrans),
0097:         * is in D-frame pixel units.
0098:         *
0099:         * <p> The filtered downsample operator mapping equations are given by
0100:         *
0101:         * <code>
0102:         *   <p> xS = xD*scaleX + (int)(hKernel.length/2) <br>
0103:         *   yS = yD*scaleY + (int)(vKernel.length/2)
0104:         * </code>
0105:         *
0106:         * <p> The mapping equations have the intended property that the convolution
0107:         * kernel overlays the upper left source pixels for the upper left destination
0108:         * pixel.
0109:         *
0110:         * <p> The downsample terms are restricted to positive integral values.
0111:         * Geometrically, one D-frame pixel maps to scaleX by scaleY S-frame
0112:         * pixels.  The combination of downsampling and filtering has performance
0113:         * benefits over sequential operator usage in part due to the symmetry
0114:         * constraints imposed by only allowing integer parameters for scaling and
0115:         * only allowing separable symmetric filters.  With odd scale factors, D-frame
0116:         * pixels map directly onto S-frame pixel centers.  With even scale factors,
0117:         * D-frame pixels map squarely between S-frame pixel centers.  Below are
0118:         * examples of even, odd, and combination cases.
0119:         *
0120:         *   <p>  s = S-frame pixel centers <br>
0121:         *        d = D-frame pixel centers mapped to S-frame
0122:         *   </p>
0123:         *   <kbd>
0124:         *   <pre> s   s   s   s   s   s           s   s   s   s   s   s  </pre>
0125:         *   <pre>   d       d       d  </pre>
0126:         *   <pre> s   s   s   s   s   s           s   d   s   s   d   s  </pre>
0127:         *   <pre>  </pre>
0128:         *   <pre> s   s   s   s   s   s           s   s   s   s   s   s  </pre>
0129:         *   <pre>   d       d       d  </pre>
0130:         *   <pre> s   s   s   s   s   s           s   s   s   s   s   s  </pre>
0131:         *   <pre>  </pre>
0132:         *   <pre> s   s   s   s   s   s           s   d   s   s   d   s  </pre>
0133:         *   <pre>   d       d       d  </pre>
0134:         *   <pre> s   s   s   s   s   s           s   s   s   s   s   s  </pre>
0135:         *   <pre>  </pre>
0136:         *   <pre> Even scaleX/Y factors            Odd scaleX/Y factors  </pre>
0137:         *   <pre>   </pre>
0138:         *   <pre> s   s   s   s   s   s           s   s   s   s   s   s  </pre>
0139:         *   <pre>     d           d    </pre>
0140:         *   <pre> s   s   s   s   s   s           s d s   s d s   s d s  </pre>
0141:         *   <pre>   </pre>
0142:         *   <pre> s   s   s   s   s   s           s   s   s   s   s   s  </pre>
0143:         *   <pre>     d           d    </pre>
0144:         *   <pre> s   s   s   s   s   s           s   s   s   s   s   s  </pre>
0145:         *   <pre>   </pre>
0146:         *   <pre> s   s   s   s   s   s           s d s   s d s   s d s  </pre>
0147:         *   <pre>     d           d    </pre>
0148:         *   <pre> s   s   s   s   s   s           s   s   s   s   s   s  </pre>
0149:         *   <pre>   </pre>
0150:         * <pre>  Odd/even scaleX/Y factors      Even/odd scaleX/Y factors  </pre> <br>
0151:         *   </kbd>
0152:         *
0153:         * <p> The convolution kernel is restricted to have quadrant symmetry (qs). This
0154:         * type of symmetry is also product separable.  The qsFilter is specified by
0155:         * a floating array.  If qsFilter[0], qsFilter[1], ... , qsFilter[qsFilter.len() - 1]
0156:         * is the filter input, then the entire separable kernel is given by <br>
0157:         *   qsFilter[qsFilter.len() - 1], ... , qsFilter[0], ... , qsFilter[qsFilter.len() - 1] <br>
0158:         *
0159:         * <p> The restriction of integer parameter constraints allows full product
0160:         * separablity and symmetry when applying the combined resample and filter
0161:         * convolution operations.
0162:         *
0163:         * <p> If Bilinear or Bicubic interpolation is specified, the source needs
0164:         * to be extended such that it has the extra pixels needed to compute all
0165:         * the destination pixels. This extension is performed via the
0166:         * <code>BorderExtender</code> class. The type of border extension can be
0167:         * specified as a <code>RenderingHint</code> to the <code>JAI.create</code>
0168:         * method.
0169:         *
0170:         * <p> If no <code>BorderExtender</code> is specified, the source will
0171:         * not be extended.  The scaled image size is still calculated
0172:         * according to the formula specified above. However since there is not
0173:         * enough source to compute all the destination pixels, only that
0174:         * subset of the destination image's pixels which can be computed,
0175:         * will be written in the destination. The rest of the destination
0176:         * will be set to zeros.
0177:         *
0178:         * <p> The current implementation of this operator does not support
0179:         * <code>MultiPixelPackedSampleModel</code> source data.  The Rendered Image
0180:         * Factory for this operator, <code>FilteredSubsampleRIF</code>, will throw an
0181:         * <code>IllegalArgumentException</code> for this type of input.
0182:         *
0183:         * @see GeometricOpImage
0184:         */
0185:        public class FilteredSubsampleOpImage extends GeometricOpImage {
0186:
0187:            /** <p> The horizontal downsample factor. */
0188:            protected int scaleX;
0189:
0190:            /** <p> The vertical downsample factor. */
0191:            protected int scaleY;
0192:
0193:            /** <p> Horizontal filter parity.  Rules: 0 => even, 1 => odd.  See hKernel */
0194:            protected int hParity;
0195:
0196:            /** <p> Vertical filter parity.  Rules: 0 => even, 1 => odd.  See vKernel */
0197:            protected int vParity;
0198:
0199:            /** <p> Compact form of combined resample and antialias filters
0200:             *  used by computeRect method.  hKernel is the horizontal kernel.
0201:             *
0202:             *  <p> The symmetric filter is applied even or odd depending on filter
0203:             *  parity.
0204:             *
0205:             *  <p> Expanded even kernel example (<code>hParity = 0</code>): <br>
0206:             *  <code>
0207:             *      hKernel[2] hKernel[1] hKernel[0] hKernel[0] hKernel[1] hKernel[2]
0208:             *  </code>
0209:             *
0210:             *  <p> Expanded odd kernel example (<code>hParity = 1</code>): <br>
0211:             *  <code>
0212:             *      hKernel[2] hKernel[1] hKernel[0] hKernel[1] hKernel[2]
0213:             *  </code>
0214:             */
0215:            protected float[] hKernel;
0216:
0217:            /** <p> Compact form of combined resample and antialias filters
0218:             *  used by computeRect method.  vKernel is the vertical kernel.
0219:             *
0220:             *  <p> The symmetric filter is applied even or odd depending on filter
0221:             *  parity.
0222:             *
0223:             *  <p> Expanded even kernel example (<code>vParity = 0</code>): <br>
0224:             *  <code>
0225:             *      vKernel[2] vKernel[1] vKernel[0] vKernel[0] vKernel[1] vKernel[2]
0226:             *  </code>
0227:             *
0228:             *  <p> Expanded odd kernel example (<code>vParity = 1</code>): <br>
0229:             *  <code>
0230:             *      vKernel[2] vKernel[1] vKernel[0] vKernel[1] vKernel[2]
0231:             *  </code>
0232:             */
0233:            protected float[] vKernel;
0234:
0235:            /** <p> <code>convolveFullKernels</code> -- convolve two kernels and return the
0236:             * result in a floating array.
0237:             *
0238:             * @param a floating kernel array.
0239:             * @param b floating kernel array.
0240:             * @return floating kernel array representing a*b (full convolution)
0241:             */
0242:            private static float[] convolveFullKernels(float[] a, float[] b) {
0243:                int lenA = a.length;
0244:                int lenB = b.length;
0245:                float[] c = new float[lenA + lenB - 1];
0246:
0247:                for (int k = 0; k < c.length; k++)
0248:                    for (int j = Math.max(0, k - lenB + 1); j <= Math.min(k,
0249:                            lenA - 1); j++)
0250:                        c[k] += a[j] * b[k - j];
0251:
0252:                return c;
0253:
0254:            } // convolveFullKernels
0255:
0256:            /** <p> <code>convolveSymmetricKernels</code> uses a symmetric representation
0257:             * (partial kernels) of input and output kernels.  For example, with
0258:             * aParity 1 (odd) and bParity 0 (even) the passed kernels a and b would
0259:             * have form:
0260:             * <code>
0261:             * a:  a[lenA-1] ... a[1] a[0] a[1] ... a[lenA-1]
0262:             * b:  b[lenB-1] ... b[1] b[0] b[0] b[1] ... b[lenB-1]
0263:             * </code>
0264:             *
0265:             * (i.e., don't send symmetric parts but assumes parity controls filter
0266:             * lengths).
0267:             *
0268:             * <p> It is possible to do this convolution without resorting to full
0269:             * kernels but this is messy.  @see convolveFullKernels for details.
0270:             *
0271:             * <p> Further notes:
0272:             * 1. The return kernel, <code>c</code>, has parity
0273:             *    <code>1 + aParity + bParity mod 2</code>
0274:             * 2. The reason for setting up the kernels this way is to enforce symmetry
0275:             *    constraints.  (Design choice.)
0276:             *
0277:             * @param aParity int that is 0 or 1.
0278:             * @param bParity int that is 0 or 1.
0279:             * @param a floating partial kernel array.
0280:             * @param b floating partial kernel array.
0281:             * @return symmetric portion of floating array representing a*b (convolution).
0282:             */
0283:            private static float[] convolveSymmetricKernels(int aParity,
0284:                    int bParity, float[] a, float[] b) {
0285:                int lenA = a.length;
0286:                int lenB = b.length;
0287:                int lenTmpA = 2 * lenA - aParity;
0288:                int lenTmpB = 2 * lenB - bParity;
0289:                int lenTmpC = lenTmpA + lenTmpB - 1;
0290:                float[] tmpA = new float[lenTmpA];
0291:                float[] tmpB = new float[lenTmpB];
0292:                float[] tmpC;
0293:                float[] c = new float[(lenTmpC + 1) / 2];
0294:
0295:                // Construct "full" a
0296:                for (int k = 0; k < lenTmpA; k++)
0297:                    tmpA[k] = a[Math.abs(k - lenA + (aParity - 1) * (k / lenA)
0298:                            + 1)];
0299:
0300:                // Construct "full" b
0301:                for (int k = 0; k < lenTmpB; k++)
0302:                    tmpB[k] = b[Math.abs(k - lenB + (bParity - 1) * (k / lenB)
0303:                            + 1)];
0304:
0305:                // Convolve "full" a with "full" b to get a "full" tempC
0306:                tmpC = convolveFullKernels(tmpA, tmpB);
0307:
0308:                // Carve out and return the portion of c that holds
0309:                int cParity = tmpC.length % 2;
0310:                for (int k = 0; k < c.length; k++)
0311:                    c[k] = tmpC[lenTmpC - c.length - k - 1 + cParity];
0312:
0313:                return c;
0314:
0315:            } // convolveSymmetricKernels
0316:
0317:            /** <p> <code>combineFilters</code> based on <code>resampleType</code> and
0318:             * input partial <code>qsFilter</code> (see above for details on qsFilter format).
0319:             * Input <code>qsFilter</code> is restricted to have odd parity
0320:             * (<code>qsFilter[0]</code> is at the center of the kernel).
0321:             *
0322:             * @param scaleFactor positive int representing the downsample factor.
0323:             * @param resampleType int representing the interpolation type.
0324:             * @param qsFilter floating partial kernel array (antialias filter).
0325:             * @return floating partial kernel representing combined resample and qsFilter.
0326:             */
0327:            private static float[] combineFilters(int scaleFactor,
0328:                    int resampleType, float[] qsFilter) {
0329:
0330:                // Odd scale factors imply no resample filter is required
0331:                // return pointer to the qsFilter
0332:                if ((scaleFactor % 2) == 1)
0333:                    return (float[]) qsFilter.clone();
0334:
0335:                int qsParity = 1;
0336:                int resampParity = 0; // Unless nearest neighbor case is selected (ignored)
0337:
0338:                switch (resampleType) {
0339:                case Interpolation.INTERP_NEAREST: // Return a copy of the qsFilter
0340:                    return (float[]) qsFilter.clone();
0341:                case Interpolation.INTERP_BILINEAR: // 2 by 2 resample filter
0342:                    float[] bilinearKernel = { 1.0F / 2.0F };
0343:                    return convolveSymmetricKernels(qsParity, resampParity,
0344:                            qsFilter, bilinearKernel);
0345:                case Interpolation.INTERP_BICUBIC: // 4 by 4 resample filter
0346:                    float[] bicubicKernel = { 9.0F / 16.0F, -1.0F / 16.0F };
0347:                    return convolveSymmetricKernels(qsParity, resampParity,
0348:                            qsFilter, bicubicKernel);
0349:                case Interpolation.INTERP_BICUBIC_2: // alternate 4 by 4 resample filter
0350:                    float[] bicubic2Kernel = { 5.0F / 8.0F, -1.0F / 8.0F };
0351:                    return convolveSymmetricKernels(qsParity, resampParity,
0352:                            qsFilter, bicubic2Kernel);
0353:                default:
0354:                    throw new IllegalArgumentException(JaiI18N
0355:                            .getString("FilteredSubsample0"));
0356:                }
0357:
0358:            } // combineFilters
0359:
0360:            /** <p> <code>filterParity</code> -- Returns combined filter/resample parity.
0361:             * This is odd only when we have an odd scale factor or we have nearest neighbor
0362:             * filtering (no resample kernel needed).  <code>scaleFactor</code> was validated
0363:             * by the constructor.  Possible return values are 0 or 1.
0364:             *
0365:             * @param scaleFactor positive int representing the downsample factor.
0366:             * @param resampleType int representing the interpolation type.
0367:             * @return int representing combined filter parity (0 or 1).
0368:             */
0369:            private static int filterParity(int scaleFactor, int resampleType) {
0370:
0371:                // Test scale factor for oddness or nearest neighbor resampling
0372:                if ((scaleFactor % 2 == 1)
0373:                        || (resampleType == Interpolation.INTERP_NEAREST))
0374:                    return 1;
0375:
0376:                // for all other cases we will be convolving an odd filter with an even
0377:                // filter, thus producing an even filter
0378:                return 0;
0379:
0380:            } // filterParity
0381:
0382:            /** <p> <code>layoutHelper</code> validates input and returns an
0383:             *  <code>ImageLayout</code> object.
0384:             *
0385:             * @param source a RenderedImage object.
0386:             * @param interp an Interpolation object.
0387:             * @param scaleX an int downsample factor.
0388:             * @param scaleY an int downsample factor.
0389:             * @param filterSize an int representing the size of the combined
0390:             *        filter and resample kernel.
0391:             * @param il an ImageLayout object.
0392:             * @return validated ImageLayout object.
0393:             */
0394:            private static final ImageLayout layoutHelper(RenderedImage source,
0395:                    Interpolation interp, int scaleX, int scaleY,
0396:                    int filterSize, ImageLayout il) {
0397:
0398:                if (scaleX < 1 || scaleY < 1) {
0399:                    throw new IllegalArgumentException(JaiI18N
0400:                            .getString("FilteredSubsample1"));
0401:                }
0402:                if (filterSize < 1) {
0403:                    throw new IllegalArgumentException(JaiI18N
0404:                            .getString("FilteredSubsample2"));
0405:                }
0406:
0407:                // Set the bounds to the scaled source bounds.
0408:                Rectangle bounds = forwardMapRect(source.getMinX(), source
0409:                        .getMinY(), source.getWidth(), source.getHeight(),
0410:                        scaleX, scaleY);
0411:
0412:                // If the user has supplied a layout, use it
0413:                ImageLayout layout = (il == null) ? new ImageLayout(bounds.x,
0414:                        bounds.y, bounds.width, bounds.height)
0415:                        : (ImageLayout) il.clone();
0416:
0417:                // Override dimensions if user passed a hint
0418:                if (il != null) {
0419:                    layout.setWidth(bounds.width);
0420:                    layout.setHeight(bounds.height);
0421:                    layout.setMinX(bounds.x);
0422:                    layout.setMinY(bounds.y);
0423:                }
0424:
0425:                return layout;
0426:
0427:            } // setLayout
0428:
0429:            /** <p> <code>FilteredSubsampleOpImage</code> constructs an OpImage representing
0430:             * filtered integral subsampling.  The scale factors represent the ratio of
0431:             * source to destination dimensions.
0432:             *
0433:             * @param source a RenderedImage.
0434:             * @param extender a BorderExtender, or null.
0435:             * @param config a Map object possibly holding tile cache information
0436:             * @param layout an ImageLayout optionally containing the tile grid layout,
0437:             *	  SampleModel, and ColorModel, or null.
0438:             * @param interp a Interpolation object to use for resampling.
0439:             * @param scaleX downsample factor along x axis.
0440:             * @param scaleY downsample factor along y axis.
0441:             * @param qsFilter symmetric filter coefficients (partial kernel).
0442:             * @throws IllegalArgumentException if the interp type is not one of:
0443:             *    INTERP_NEAREST, INTERP_BILINEAR, INTERP_BICUBIC, or INTERP_BICUBIC_2
0444:             */
0445:            public FilteredSubsampleOpImage(RenderedImage source,
0446:                    BorderExtender extender, Map config, ImageLayout layout,
0447:                    int scaleX, int scaleY, float[] qsFilter,
0448:                    Interpolation interp) {
0449:
0450:                // Propagate to GeometricOpImage constructor
0451:                super (vectorize(source), layoutHelper(source, interp, scaleX,
0452:                        scaleY, qsFilter.length, layout), config, // Map object
0453:                        true, // cobbleSources,
0454:                        extender, // extender
0455:                        interp, // Interpolation object
0456:                        null);
0457:
0458:                int resampleType;
0459:
0460:                // Determine the interpolation type, if not supported throw exception
0461:                if (interp instanceof  InterpolationNearest) {
0462:                    resampleType = Interpolation.INTERP_NEAREST;
0463:                } else if (interp instanceof  InterpolationBilinear) {
0464:                    resampleType = Interpolation.INTERP_BILINEAR;
0465:                } else if (interp instanceof  InterpolationBicubic) {
0466:                    resampleType = Interpolation.INTERP_BICUBIC;
0467:                } else if (interp instanceof  InterpolationBicubic2) {
0468:                    resampleType = Interpolation.INTERP_BICUBIC_2;
0469:                } else {
0470:                    throw new IllegalArgumentException(JaiI18N
0471:                            .getString("FilteredSubsample3"));
0472:                }
0473:
0474:                // Construct combined anti-alias and resample kernels.
0475:                this .hParity = filterParity(scaleX, resampleType);
0476:                this .vParity = filterParity(scaleY, resampleType);
0477:                this .hKernel = combineFilters(scaleX, resampleType, qsFilter);
0478:                this .vKernel = combineFilters(scaleY, resampleType, qsFilter);
0479:
0480:                this .scaleX = scaleX;
0481:                this .scaleY = scaleY;
0482:
0483:            } // FilteredSubsampleOpImage
0484:
0485:            /**
0486:             * Computes the source point corresponding to the supplied point.
0487:             *
0488:             * @param destPt the position in destination image coordinates
0489:             * to map to source image coordinates.
0490:             *
0491:             * @return a <code>Point2D</code> of the same class as
0492:             * <code>destPt</code>.
0493:             *
0494:             * @throws IllegalArgumentException if <code>destPt</code> is
0495:             * <code>null</code>.
0496:             *
0497:             * @since JAI 1.1.2
0498:             */
0499:            public Point2D mapDestPoint(Point2D destPt) {
0500:                if (destPt == null) {
0501:                    throw new IllegalArgumentException(JaiI18N
0502:                            .getString("Generic0"));
0503:                }
0504:
0505:                Point2D pt = (Point2D) destPt.clone();
0506:
0507:                pt.setLocation(destPt.getX() * scaleX, destPt.getY() * scaleY);
0508:
0509:                return pt;
0510:            }
0511:
0512:            /**
0513:             * Computes the destination point corresponding to the supplied point.
0514:             *
0515:             * @param sourcePt the position in source image coordinates
0516:             * to map to destination image coordinates.
0517:             *
0518:             * @return a <code>Point2D</code> of the same class as
0519:             * <code>sourcePt</code>.
0520:             *
0521:             * @throws IllegalArgumentException if <code>sourcePt</code> is
0522:             * <code>null</code>.
0523:             *
0524:             * @since JAI 1.1.2
0525:             */
0526:            public Point2D mapSourcePoint(Point2D sourcePt) {
0527:                if (sourcePt == null) {
0528:                    throw new IllegalArgumentException(JaiI18N
0529:                            .getString("Generic0"));
0530:                }
0531:
0532:                Point2D pt = (Point2D) sourcePt.clone();
0533:
0534:                pt.setLocation(sourcePt.getX() / scaleX, sourcePt.getY()
0535:                        / scaleY);
0536:
0537:                return pt;
0538:            }
0539:
0540:            /**
0541:             * <p> Returns a conservative estimate of the destination region that
0542:             * can potentially be affected by the pixels of a rectangle of a
0543:             * given source.
0544:             *
0545:             * @param sourceRect The <code>Rectangle</code> in source coordinates.
0546:             * @param sourceIndex The index of the source image.
0547:             *
0548:             * @return a <code>Rectangle</code> indicating the potentially
0549:             *         affected destination region, or <code>null</code> if
0550:             *         the region is unknown.
0551:             *
0552:             * @throws IllegalArgumentException if <code>sourceIndex</code> is
0553:             *         negative or greater than the index of the last source.
0554:             * @throws NullPointerException if <code>sourceRect</code> is
0555:             *         <code>null</code>.
0556:             */
0557:            public Rectangle mapSourceRect(Rectangle sourceRect, int sourceIndex) {
0558:                if (sourceIndex != 0) { // this image only has one source
0559:                    throw new IllegalArgumentException(JaiI18N
0560:                            .getString("FilteredSubsample4"));
0561:                }
0562:
0563:                int xOffset = sourceRect.x + hKernel.length - hParity - scaleX
0564:                        / 2;
0565:                int yOffset = sourceRect.y + vKernel.length - vParity - scaleY
0566:                        / 2;
0567:                int rectWidth = sourceRect.width - 2 * hKernel.length + hParity
0568:                        + 1;
0569:                int rectHeight = sourceRect.height - 2 * vKernel.length
0570:                        + vParity + 1;
0571:                return forwardMapRect(xOffset, yOffset, rectWidth, rectHeight,
0572:                        scaleX, scaleY);
0573:
0574:            } // mapSourceRect
0575:
0576:            /** <p> Forward map a source Rectangle into destination space.
0577:             *
0578:             * @param x source frame coordinate.
0579:             * @param y source frame coordinate.
0580:             * @param w source frame width.
0581:             * @param h source frame height.
0582:             * @param scaleX downsample factor.
0583:             * @param scaleY downsample factor.
0584:             * @return a <code>Rectangle</code> indicating the destination region.
0585:             */
0586:            private static final Rectangle forwardMapRect(int x, int y, int w,
0587:                    int h, int scaleX, int scaleY) {
0588:                float sx = 1.0F / scaleX;
0589:                float sy = 1.0F / scaleY;
0590:
0591:                x = Math.round(x * sx);
0592:                y = Math.round(y * sy);
0593:
0594:                return new Rectangle(x, y, Math.round((x + w) * sx) - x, Math
0595:                        .round((y + h) * sy)
0596:                        - y);
0597:            } // forwardMapRect
0598:
0599:            /** <p> Forward map a source Rectangle into destination space.
0600:             *  Required by abstract GeometricOpImage
0601:             *
0602:             * @param srcRect a source Rectangle.
0603:             * @param srcIndex int source index (0 for this operator)
0604:             * @return a <code>Rectangle</code> indicating the destination region.
0605:             */
0606:            protected final Rectangle forwardMapRect(Rectangle srcRect,
0607:                    int srcIndex) {
0608:                int x = srcRect.x;
0609:                int y = srcRect.y;
0610:                int w = srcRect.width;
0611:                int h = srcRect.height;
0612:                float sx = 1.0F / scaleX;
0613:                float sy = 1.0F / scaleY;
0614:
0615:                x = Math.round(x * sx);
0616:                y = Math.round(y * sy);
0617:
0618:                return new Rectangle(x, y, Math.round((x + w) * sx) - x, Math
0619:                        .round((y + h) * sy)
0620:                        - y);
0621:            } // forwardMapRect
0622:
0623:            /** <p> Backward map a destination Rectangle into source space.
0624:             *
0625:             * @param destRect a destination Rectangle.
0626:             * @param srcIndex int source index (0 for this operator)
0627:             * @return a <code>Rectangle</code> indicating the source region.
0628:             */
0629:            protected final Rectangle backwardMapRect(Rectangle destRect,
0630:                    int srcIncex) {
0631:                int x = destRect.x;
0632:                int y = destRect.y;
0633:                int w = destRect.width;
0634:                int h = destRect.height;
0635:
0636:                return new Rectangle(x * scaleX, y * scaleY, (x + w) * scaleX
0637:                        - x, (y + h) * scaleY - y);
0638:            } // backwardMapRect
0639:
0640:            /**
0641:             * <p> Returns a conservative estimate of the region of a specified
0642:             * source that is required in order to compute the pixels of a
0643:             * given destination rectangle.
0644:             *
0645:             * @param destRect The <code>Rectangle</code> in destination coordinates.
0646:             * @param sourceIndex The index of the source image.
0647:             *
0648:             * @return a <code>Rectangle</code> indicating the required source region.
0649:             *
0650:             * @throws IllegalArgumentException if <code>sourceIndex</code> is
0651:             *         negative or greater than the index of the last source.
0652:             * @throws NullPointerException if <code>destRect</code> is
0653:             *         <code>null</code>.
0654:             */
0655:            public Rectangle mapDestRect(Rectangle destRect, int sourceIndex) {
0656:                if (sourceIndex != 0) { // this image only has one source
0657:                    throw new IllegalArgumentException(JaiI18N
0658:                            .getString("FilteredSubsample4"));
0659:                }
0660:                int xOffset = destRect.x * scaleX - hKernel.length + hParity
0661:                        + scaleX / 2;
0662:                int yOffset = destRect.y * scaleY - vKernel.length + vParity
0663:                        + scaleY / 2;
0664:                int rectWidth = destRect.width * scaleX + 2 * hKernel.length
0665:                        - hParity - 1;
0666:                int rectHeight = destRect.height * scaleY + 2 * vKernel.length
0667:                        - vParity - 1;
0668:                return new Rectangle(xOffset, yOffset, rectWidth, rectHeight);
0669:
0670:            } // mapDestRect
0671:
0672:            /**
0673:             * <p> Performs a combined subsample/filter operation on a specified rectangle.
0674:             * The sources are cobbled.
0675:             *
0676:             * @param sources  an array of source Rasters, guaranteed to provide all
0677:             *                 necessary source data for computing the output.
0678:             * @param dest     a WritableRaster  containing the area to be computed.
0679:             * @param destRect the rectangle within dest to be processed.
0680:             */
0681:            public void computeRect(Raster[] sources, WritableRaster dest,
0682:                    Rectangle destRect) {
0683:
0684:                // Get RasterAccessor tags (initialized in OpImage superclass).
0685:                RasterFormatTag[] formatTags = getFormatTags();
0686:
0687:                // Get destination accessor.
0688:                RasterAccessor dst = new RasterAccessor(dest, destRect,
0689:                        formatTags[1], getColorModel());
0690:
0691:                // Get source accessor.
0692:                RasterAccessor src = new RasterAccessor(sources[0],
0693:                        mapDestRect(destRect, 0), formatTags[0],
0694:                        getSourceImage(0).getColorModel());
0695:
0696:                switch (dst.getDataType()) {
0697:                case DataBuffer.TYPE_BYTE:
0698:                    computeRectByte(src, dst);
0699:                    break;
0700:                case DataBuffer.TYPE_USHORT:
0701:                    computeRectUShort(src, dst);
0702:                    break;
0703:                case DataBuffer.TYPE_SHORT:
0704:                    computeRectShort(src, dst);
0705:                    break;
0706:                case DataBuffer.TYPE_INT:
0707:                    computeRectInt(src, dst);
0708:                    break;
0709:                case DataBuffer.TYPE_FLOAT:
0710:                    computeRectFloat(src, dst);
0711:                    break;
0712:                case DataBuffer.TYPE_DOUBLE:
0713:                    computeRectDouble(src, dst);
0714:                    break;
0715:                default:
0716:                    throw new IllegalArgumentException(JaiI18N
0717:                            .getString("FilteredSubsample5"));
0718:                }
0719:
0720:                // If the RasterAccessor set up a temporary write buffer for the
0721:                // operator, tell it to copy that data to the destination Raster.
0722:                if (dst.isDataCopy()) {
0723:                    dst.clampDataArrays();
0724:                    dst.copyDataToRaster();
0725:                }
0726:
0727:            } // computeRect
0728:
0729:            /** <code>computeRectByte</code> filter subsamples byte pixel data.
0730:             *
0731:             * @param src RasterAccessor for source image.
0732:             * @param dst RasterAccessor for output image.
0733:             */
0734:            protected void computeRectByte(RasterAccessor src,
0735:                    RasterAccessor dst) {
0736:
0737:                // Get dimensions.
0738:                int dwidth = dst.getWidth();
0739:                int dheight = dst.getHeight();
0740:                int dnumBands = dst.getNumBands();
0741:
0742:                // Get destination data array references and strides.
0743:                byte dstDataArrays[][] = dst.getByteDataArrays();
0744:                int dstBandOffsets[] = dst.getBandOffsets();
0745:                int dstPixelStride = dst.getPixelStride();
0746:                int dstScanlineStride = dst.getScanlineStride();
0747:
0748:                // Get source data array references and strides.
0749:                byte srcDataArrays[][] = src.getByteDataArrays();
0750:                int srcBandOffsets[] = src.getBandOffsets();
0751:                int srcPixelStride = src.getPixelStride();
0752:                int srcScanlineStride = src.getScanlineStride();
0753:
0754:                // Compute reused numbers
0755:                int kernelNx = 2 * hKernel.length - hParity;
0756:                int kernelNy = 2 * vKernel.length - vParity;
0757:                int stepDown = (kernelNy - 1) * srcScanlineStride;
0758:                int stepRight = (kernelNx - 1) * srcPixelStride;
0759:
0760:                int upLeft, upRight, dnLeft, dnRight;
0761:                float kk;
0762:                float vCtr = vKernel[0];
0763:                float hCtr = hKernel[0];
0764:                int kInd, xLeft, xRight, xUp, xDown;
0765:
0766:                for (int band = 0; band < dnumBands; band++) {
0767:                    byte dstData[] = dstDataArrays[band];
0768:                    byte srcData[] = srcDataArrays[band];
0769:                    int srcScanlineOffset = srcBandOffsets[band];
0770:                    int dstScanlineOffset = dstBandOffsets[band];
0771:
0772:                    // Step over source raster coordinates
0773:                    for (int ySrc = 0; ySrc < scaleY * dheight; ySrc += scaleY) {
0774:                        int dInd = dstScanlineOffset;
0775:                        for (int xSrc = 0; xSrc < scaleX * dwidth; xSrc += scaleX) {
0776:
0777:                            int upLeft0 = xSrc * srcPixelStride + ySrc
0778:                                    * srcScanlineStride + srcScanlineOffset;
0779:                            int upRight0 = upLeft0 + stepRight;
0780:                            int dnLeft0 = upLeft0 + stepDown;
0781:                            int dnRight0 = upRight0 + stepDown;
0782:
0783:                            // Exploit 4-fold symmetry
0784:                            float sum = 0;
0785:
0786:                            // Make the rectangle squeeze in the vertical direction
0787:                            for (int iy = vKernel.length - 1; iy > vParity - 1; iy--) {
0788:                                upLeft = upLeft0;
0789:                                upRight = upRight0;
0790:                                dnLeft = dnLeft0;
0791:                                dnRight = dnRight0;
0792:
0793:                                // Make the rectangle squeeze in the horizontal direction
0794:                                for (int ix = hKernel.length - 1; ix > hParity - 1; ix--) {
0795:                                    kk = hKernel[ix] * vKernel[iy];
0796:                                    sum += kk
0797:                                            * ((int) (srcData[upLeft] & 0xff)
0798:                                                    + (int) (srcData[upRight] & 0xff)
0799:                                                    + (int) (srcData[dnLeft] & 0xff) + (int) (srcData[dnRight] & 0xff));
0800:                                    upLeft += srcPixelStride;
0801:                                    upRight -= srcPixelStride;
0802:                                    dnLeft += srcPixelStride;
0803:                                    dnRight -= srcPixelStride;
0804:                                } // ix
0805:                                upLeft0 += srcScanlineStride; // down a row
0806:                                upRight0 += srcScanlineStride;
0807:                                dnLeft0 -= srcScanlineStride; // up a row
0808:                                dnRight0 -= srcScanlineStride;
0809:                            } // iy
0810:
0811:                            // Compute the remaining 2-Fold symmetry portions (across and down as needed)
0812:
0813:                            // Loop down the center (hParity is odd)
0814:                            if (hParity == 1) {
0815:                                xUp = (xSrc + hKernel.length - 1)
0816:                                        * srcPixelStride + ySrc
0817:                                        * srcScanlineStride + srcScanlineOffset;
0818:                                xDown = xUp + stepDown;
0819:                                kInd = vKernel.length - 1;
0820:                                while (xUp < xDown) {
0821:                                    kk = hCtr * vKernel[kInd--];
0822:                                    sum += kk
0823:                                            * ((int) (srcData[xUp] & 0xff) + (int) (srcData[xDown] & 0xff));
0824:                                    xUp += srcScanlineStride;
0825:                                    xDown -= srcScanlineStride;
0826:                                }
0827:                            } // hParity
0828:
0829:                            // Loop across the center (vParity is odd), pick up the center if hParity was odd
0830:                            if (vParity == 1) {
0831:                                xLeft = xSrc * srcPixelStride
0832:                                        + (ySrc + vKernel.length - 1)
0833:                                        * srcScanlineStride + srcScanlineOffset;
0834:                                xRight = xLeft + stepRight;
0835:                                kInd = hKernel.length - 1;
0836:                                while (xLeft < xRight) {
0837:                                    kk = vCtr * hKernel[kInd--];
0838:                                    sum += kk
0839:                                            * ((int) (srcData[xLeft] & 0xff) + (int) (srcData[xRight] & 0xff));
0840:                                    xLeft += srcPixelStride;
0841:                                    xRight -= srcPixelStride;
0842:                                } // while xLeft
0843:
0844:                                // Grab the center pixel if hParity was odd also
0845:                                if (hParity == 1)
0846:                                    sum += vCtr * hCtr
0847:                                            * (int) (srcData[xLeft] & 0xff);
0848:
0849:                            } // if vParity
0850:
0851:                            // Convert the sum to an output pixel
0852:                            if (sum < 0.0)
0853:                                sum = 0;
0854:                            if (sum > 255.0)
0855:                                sum = 255;
0856:
0857:                            dstData[dInd] = (byte) (sum + 0.5);
0858:
0859:                            dInd += dstPixelStride;
0860:                        } // for xSrc
0861:
0862:                        dstScanlineOffset += dstScanlineStride;
0863:
0864:                    } // for ySrc
0865:
0866:                } // for band
0867:
0868:                return;
0869:
0870:            } // computeRectByte
0871:
0872:            /** <code>computeRectUShort</code> filter subsamples unsigned short pixel data.
0873:             *
0874:             * @param src RasterAccessor for source image.
0875:             * @param dst RasterAccessor for output image.
0876:             */
0877:            protected void computeRectUShort(RasterAccessor src,
0878:                    RasterAccessor dst) {
0879:
0880:                // Get dimensions.
0881:                int dwidth = dst.getWidth();
0882:                int dheight = dst.getHeight();
0883:                int dnumBands = dst.getNumBands();
0884:
0885:                // Get destination data array references and strides.
0886:                short dstDataArrays[][] = dst.getShortDataArrays();
0887:                int dstBandOffsets[] = dst.getBandOffsets();
0888:                int dstPixelStride = dst.getPixelStride();
0889:                int dstScanlineStride = dst.getScanlineStride();
0890:
0891:                // Get source data array references and strides.
0892:                short srcDataArrays[][] = src.getShortDataArrays();
0893:                int srcBandOffsets[] = src.getBandOffsets();
0894:                int srcPixelStride = src.getPixelStride();
0895:                int srcScanlineStride = src.getScanlineStride();
0896:
0897:                // Compute reused numbers
0898:                int kernelNx = 2 * hKernel.length - hParity;
0899:                int kernelNy = 2 * vKernel.length - vParity;
0900:                int stepDown = (kernelNy - 1) * srcScanlineStride;
0901:                int stepRight = (kernelNx - 1) * srcPixelStride;
0902:
0903:                int upLeft, upRight, dnLeft, dnRight;
0904:                float kk;
0905:                float vCtr = vKernel[0];
0906:                float hCtr = hKernel[0];
0907:                int kInd, xLeft, xRight, xUp, xDown;
0908:
0909:                for (int band = 0; band < dnumBands; band++) {
0910:                    short dstData[] = dstDataArrays[band];
0911:                    short srcData[] = srcDataArrays[band];
0912:                    int srcScanlineOffset = srcBandOffsets[band];
0913:                    int dstScanlineOffset = dstBandOffsets[band];
0914:
0915:                    // Step over source raster coordinates
0916:                    for (int ySrc = 0; ySrc < scaleY * dheight; ySrc += scaleY) {
0917:                        int dInd = dstScanlineOffset;
0918:                        for (int xSrc = 0; xSrc < scaleX * dwidth; xSrc += scaleX) {
0919:
0920:                            int upLeft0 = xSrc * srcPixelStride + ySrc
0921:                                    * srcScanlineStride + srcScanlineOffset;
0922:                            int upRight0 = upLeft0 + stepRight;
0923:                            int dnLeft0 = upLeft0 + stepDown;
0924:                            int dnRight0 = upRight0 + stepDown;
0925:
0926:                            // Exploit 4-fold symmetry
0927:                            float sum = 0;
0928:
0929:                            // Make the rectangle squeeze in the vertical direction
0930:                            for (int iy = vKernel.length - 1; iy > vParity - 1; iy--) {
0931:                                upLeft = upLeft0;
0932:                                upRight = upRight0;
0933:                                dnLeft = dnLeft0;
0934:                                dnRight = dnRight0;
0935:
0936:                                // Make the rectangle squeeze in the horizontal direction
0937:                                for (int ix = hKernel.length - 1; ix > hParity - 1; ix--) {
0938:                                    kk = hKernel[ix] * vKernel[iy];
0939:                                    sum += kk
0940:                                            * ((int) (srcData[upLeft] & 0xffff)
0941:                                                    + (int) (srcData[upRight] & 0xffff)
0942:                                                    + (int) (srcData[dnLeft] & 0xffff) + (int) (srcData[dnRight] & 0xffff));
0943:                                    upLeft += srcPixelStride;
0944:                                    upRight -= srcPixelStride;
0945:                                    dnLeft += srcPixelStride;
0946:                                    dnRight -= srcPixelStride;
0947:                                } // ix
0948:                                upLeft0 += srcScanlineStride; // down a row
0949:                                upRight0 += srcScanlineStride;
0950:                                dnLeft0 -= srcScanlineStride; // up a row
0951:                                dnRight0 -= srcScanlineStride;
0952:                            } // iy
0953:
0954:                            // Compute the remaining 2-Fold symmetry portions
0955:                            // (across and down as needed)
0956:
0957:                            // Loop down the center (hParity is odd)
0958:                            if (hParity == 1) {
0959:                                xUp = (xSrc + hKernel.length - 1)
0960:                                        * srcPixelStride + ySrc
0961:                                        * srcScanlineStride + srcScanlineOffset;
0962:                                xDown = xUp + stepDown;
0963:                                kInd = vKernel.length - 1;
0964:                                while (xUp < xDown) {
0965:                                    kk = hCtr * vKernel[kInd--];
0966:                                    sum += kk
0967:                                            * ((int) (srcData[xUp] & 0xffff) + (int) (srcData[xDown] & 0xffff));
0968:                                    xUp += srcScanlineStride;
0969:                                    xDown -= srcScanlineStride;
0970:                                }
0971:                            } // hParity
0972:
0973:                            // Loop across the center (vParity is odd), pick up the center if hParity was odd
0974:                            if (vParity == 1) {
0975:                                xLeft = xSrc * srcPixelStride
0976:                                        + (ySrc + vKernel.length - 1)
0977:                                        * srcScanlineStride + srcScanlineOffset;
0978:                                xRight = xLeft + stepRight;
0979:                                kInd = hKernel.length - 1;
0980:                                while (xLeft < xRight) {
0981:                                    kk = vCtr * hKernel[kInd--];
0982:                                    sum += kk
0983:                                            * ((int) (srcData[xLeft] & 0xffff) + (int) (srcData[xRight] & 0xffff));
0984:                                    xLeft += srcPixelStride;
0985:                                    xRight -= srcPixelStride;
0986:                                } // while xLeft
0987:
0988:                                // Grab the center pixel if hParity was odd also
0989:                                if (hParity == 1)
0990:                                    sum += vCtr * hCtr
0991:                                            * (int) (srcData[xLeft] & 0xffff);
0992:
0993:                            } // if vParity
0994:                            int val = (int) (sum + 0.5);
0995:                            dstData[dInd] = (short) (val > 0xffff ? 0xffff
0996:                                    : (val < 0 ? 0 : val));
0997:
0998:                            dInd += dstPixelStride;
0999:                        } // for xSrc
1000:
1001:                        dstScanlineOffset += dstScanlineStride;
1002:
1003:                    } // for ySrc
1004:
1005:                } // for band
1006:
1007:                return;
1008:
1009:            } // computeRectUShort
1010:
1011:            /** <code>computeRectShort</code> filter subsamples short pixel data.
1012:             *
1013:             * @param src RasterAccessor for source image.
1014:             * @param dst RasterAccessor for output image.
1015:             */
1016:            protected void computeRectShort(RasterAccessor src,
1017:                    RasterAccessor dst) {
1018:
1019:                // Get dimensions.
1020:                int dwidth = dst.getWidth();
1021:                int dheight = dst.getHeight();
1022:                int dnumBands = dst.getNumBands();
1023:
1024:                // Get destination data array references and strides.
1025:                short dstDataArrays[][] = dst.getShortDataArrays();
1026:                int dstBandOffsets[] = dst.getBandOffsets();
1027:                int dstPixelStride = dst.getPixelStride();
1028:                int dstScanlineStride = dst.getScanlineStride();
1029:
1030:                // Get source data array references and strides.
1031:                short srcDataArrays[][] = src.getShortDataArrays();
1032:                int srcBandOffsets[] = src.getBandOffsets();
1033:                int srcPixelStride = src.getPixelStride();
1034:                int srcScanlineStride = src.getScanlineStride();
1035:
1036:                // Compute reused numbers
1037:                int kernelNx = 2 * hKernel.length - hParity;
1038:                int kernelNy = 2 * vKernel.length - vParity;
1039:                int stepDown = (kernelNy - 1) * srcScanlineStride;
1040:                int stepRight = (kernelNx - 1) * srcPixelStride;
1041:
1042:                int upLeft, upRight, dnLeft, dnRight;
1043:                float kk;
1044:                float vCtr = vKernel[0];
1045:                float hCtr = hKernel[0];
1046:                int kInd, xLeft, xRight, xUp, xDown;
1047:
1048:                for (int band = 0; band < dnumBands; band++) {
1049:                    short dstData[] = dstDataArrays[band];
1050:                    short srcData[] = srcDataArrays[band];
1051:                    int srcScanlineOffset = srcBandOffsets[band];
1052:                    int dstScanlineOffset = dstBandOffsets[band];
1053:
1054:                    // Step over source raster coordinates
1055:                    for (int ySrc = 0; ySrc < scaleY * dheight; ySrc += scaleY) {
1056:                        int dInd = dstScanlineOffset;
1057:                        for (int xSrc = 0; xSrc < scaleX * dwidth; xSrc += scaleX) {
1058:
1059:                            int upLeft0 = xSrc * srcPixelStride + ySrc
1060:                                    * srcScanlineStride + srcScanlineOffset;
1061:                            int upRight0 = upLeft0 + stepRight;
1062:                            int dnLeft0 = upLeft0 + stepDown;
1063:                            int dnRight0 = upRight0 + stepDown;
1064:
1065:                            // Exploit 4-fold symmetry
1066:                            float sum = 0;
1067:
1068:                            // Make the rectangle squeeze in the vertical direction
1069:                            for (int iy = vKernel.length - 1; iy > vParity - 1; iy--) {
1070:                                upLeft = upLeft0;
1071:                                upRight = upRight0;
1072:                                dnLeft = dnLeft0;
1073:                                dnRight = dnRight0;
1074:
1075:                                // Make the rectangle squeeze in the horizontal direction
1076:                                for (int ix = hKernel.length - 1; ix > hParity - 1; ix--) {
1077:                                    kk = hKernel[ix] * vKernel[iy];
1078:                                    sum += kk
1079:                                            * ((int) (srcData[upLeft])
1080:                                                    + (int) (srcData[upRight])
1081:                                                    + (int) (srcData[dnLeft]) + (int) (srcData[dnRight]));
1082:                                    upLeft += srcPixelStride;
1083:                                    upRight -= srcPixelStride;
1084:                                    dnLeft += srcPixelStride;
1085:                                    dnRight -= srcPixelStride;
1086:                                } // ix
1087:                                upLeft0 += srcScanlineStride; // down a row
1088:                                upRight0 += srcScanlineStride;
1089:                                dnLeft0 -= srcScanlineStride; // up a row
1090:                                dnRight0 -= srcScanlineStride;
1091:                            } // iy
1092:
1093:                            // Compute the remaining 2-Fold symmetry portions
1094:                            // (across and down as needed)
1095:
1096:                            // Loop down the center (hParity is odd)
1097:                            if (hParity == 1) {
1098:                                xUp = (xSrc + hKernel.length - 1)
1099:                                        * srcPixelStride + ySrc
1100:                                        * srcScanlineStride + srcScanlineOffset;
1101:                                xDown = xUp + stepDown;
1102:                                kInd = vKernel.length - 1;
1103:                                while (xUp < xDown) {
1104:                                    kk = hCtr * vKernel[kInd--];
1105:                                    sum += kk
1106:                                            * ((int) (srcData[xUp]) + (int) (srcData[xDown]));
1107:                                    xUp += srcScanlineStride;
1108:                                    xDown -= srcScanlineStride;
1109:                                }
1110:                            } // hParity
1111:
1112:                            // Loop across the center (vParity is odd), pick up the center if hParity was odd
1113:                            if (vParity == 1) {
1114:                                xLeft = xSrc * srcPixelStride
1115:                                        + (ySrc + vKernel.length - 1)
1116:                                        * srcScanlineStride + srcScanlineOffset;
1117:                                xRight = xLeft + stepRight;
1118:                                kInd = hKernel.length - 1;
1119:                                while (xLeft < xRight) {
1120:                                    kk = vCtr * hKernel[kInd--];
1121:                                    sum += kk
1122:                                            * ((int) (srcData[xLeft]) + (int) (srcData[xRight]));
1123:                                    xLeft += srcPixelStride;
1124:                                    xRight -= srcPixelStride;
1125:                                } // while xLeft
1126:
1127:                                // Grab the center pixel if hParity was odd also
1128:                                if (hParity == 1)
1129:                                    sum += vCtr * hCtr * (int) (srcData[xLeft]);
1130:
1131:                            } // if vParity
1132:
1133:                            dstData[dInd] = ImageUtil
1134:                                    .clampShort((int) (sum + 0.5));
1135:                            dInd += dstPixelStride;
1136:
1137:                        } // for xSrc
1138:
1139:                        dstScanlineOffset += dstScanlineStride;
1140:
1141:                    } // for ySrc
1142:
1143:                } // for band
1144:
1145:                return;
1146:
1147:            } // computeRectShort
1148:
1149:            /** <code>computeRectInt</code> filter subsamples int pixel data.
1150:             *
1151:             * @param src RasterAccessor for source image.
1152:             * @param dst RasterAccessor for output image.
1153:             */
1154:            protected void computeRectInt(RasterAccessor src, RasterAccessor dst) {
1155:
1156:                // Get dimensions.
1157:                int dwidth = dst.getWidth();
1158:                int dheight = dst.getHeight();
1159:                int dnumBands = dst.getNumBands();
1160:
1161:                // Get destination data array references and strides.
1162:                int dstDataArrays[][] = dst.getIntDataArrays();
1163:                int dstBandOffsets[] = dst.getBandOffsets();
1164:                int dstPixelStride = dst.getPixelStride();
1165:                int dstScanlineStride = dst.getScanlineStride();
1166:
1167:                // Get source data array references and strides.
1168:                int srcDataArrays[][] = src.getIntDataArrays();
1169:                int srcBandOffsets[] = src.getBandOffsets();
1170:                int srcPixelStride = src.getPixelStride();
1171:                int srcScanlineStride = src.getScanlineStride();
1172:
1173:                // Compute reused numbers
1174:                int kernelNx = 2 * hKernel.length - hParity;
1175:                int kernelNy = 2 * vKernel.length - vParity;
1176:                int stepDown = (kernelNy - 1) * srcScanlineStride;
1177:                int stepRight = (kernelNx - 1) * srcPixelStride;
1178:
1179:                int upLeft, upRight, dnLeft, dnRight;
1180:                double kk;
1181:                double vCtr = (double) vKernel[0];
1182:                double hCtr = (double) hKernel[0];
1183:                int kInd, xLeft, xRight, xUp, xDown;
1184:
1185:                for (int band = 0; band < dnumBands; band++) {
1186:                    int dstData[] = dstDataArrays[band];
1187:                    int srcData[] = srcDataArrays[band];
1188:                    int srcScanlineOffset = srcBandOffsets[band];
1189:                    int dstScanlineOffset = dstBandOffsets[band];
1190:
1191:                    // Step over source raster coordinates
1192:                    for (int ySrc = 0; ySrc < scaleY * dheight; ySrc += scaleY) {
1193:                        int dInd = dstScanlineOffset;
1194:                        for (int xSrc = 0; xSrc < scaleX * dwidth; xSrc += scaleX) {
1195:
1196:                            int upLeft0 = xSrc * srcPixelStride + ySrc
1197:                                    * srcScanlineStride + srcScanlineOffset;
1198:                            int upRight0 = upLeft0 + stepRight;
1199:                            int dnLeft0 = upLeft0 + stepDown;
1200:                            int dnRight0 = upRight0 + stepDown;
1201:
1202:                            // Exploit 4-fold symmetry
1203:                            double sum = 0;
1204:
1205:                            // Make the rectangle squeeze in the vertical direction
1206:                            for (int iy = vKernel.length - 1; iy > vParity - 1; iy--) {
1207:                                upLeft = upLeft0;
1208:                                upRight = upRight0;
1209:                                dnLeft = dnLeft0;
1210:                                dnRight = dnRight0;
1211:
1212:                                // Make the rectangle squeeze in the horizontal direction
1213:                                for (int ix = hKernel.length - 1; ix > hParity - 1; ix--) {
1214:                                    kk = hKernel[ix] * vKernel[iy];
1215:                                    sum += kk
1216:                                            * ((long) srcData[upLeft]
1217:                                                    + (long) srcData[upRight]
1218:                                                    + (long) srcData[dnLeft] + (long) srcData[dnRight]);
1219:                                    upLeft += srcPixelStride;
1220:                                    upRight -= srcPixelStride;
1221:                                    dnLeft += srcPixelStride;
1222:                                    dnRight -= srcPixelStride;
1223:                                } // ix
1224:                                upLeft0 += srcScanlineStride; // down a row
1225:                                upRight0 += srcScanlineStride;
1226:                                dnLeft0 -= srcScanlineStride; // up a row
1227:                                dnRight0 -= srcScanlineStride;
1228:                            } // iy
1229:
1230:                            // Compute the remaining 2-Fold symmetry portions
1231:                            // (across and down as needed)
1232:
1233:                            // Loop down the center (hParity is odd)
1234:                            if (hParity == 1) {
1235:                                xUp = (xSrc + hKernel.length - 1)
1236:                                        * srcPixelStride + ySrc
1237:                                        * srcScanlineStride + srcScanlineOffset;
1238:                                xDown = xUp + stepDown;
1239:                                kInd = vKernel.length - 1;
1240:                                while (xUp < xDown) {
1241:                                    kk = hCtr * vKernel[kInd--];
1242:                                    sum += kk
1243:                                            * ((long) srcData[xUp] + (long) srcData[xDown]);
1244:                                    xUp += srcScanlineStride;
1245:                                    xDown -= srcScanlineStride;
1246:                                }
1247:                            } // hParity
1248:
1249:                            // Loop across the center (vParity is odd), pick up the center if hParity was odd
1250:                            if (vParity == 1) {
1251:                                xLeft = xSrc * srcPixelStride
1252:                                        + (ySrc + vKernel.length - 1)
1253:                                        * srcScanlineStride + srcScanlineOffset;
1254:                                xRight = xLeft + stepRight;
1255:                                kInd = hKernel.length - 1;
1256:                                while (xLeft < xRight) {
1257:                                    kk = vCtr * hKernel[kInd--];
1258:                                    sum += kk
1259:                                            * ((long) (srcData[xLeft]) + (long) (srcData[xRight]));
1260:                                    xLeft += srcPixelStride;
1261:                                    xRight -= srcPixelStride;
1262:                                } // while xLeft
1263:
1264:                                // Grab the center pixel if hParity was odd also
1265:                                if (hParity == 1)
1266:                                    sum += vCtr * hCtr
1267:                                            * ((long) srcData[xLeft]);
1268:
1269:                            } // if vParity
1270:
1271:                            dstData[dInd] = ImageUtil
1272:                                    .clampInt((int) (sum + 0.5));
1273:
1274:                            dInd += dstPixelStride;
1275:                        } // for xSrc
1276:
1277:                        dstScanlineOffset += dstScanlineStride;
1278:
1279:                    } // for ySrc
1280:
1281:                } // for band
1282:
1283:                return;
1284:
1285:            } // computeRectInt
1286:
1287:            /** <code>computeRectFloat</code> filter subsamples float pixel data.
1288:             *
1289:             * @param src RasterAccessor for source image.
1290:             * @param dst RasterAccessor for output image.
1291:             */
1292:            protected void computeRectFloat(RasterAccessor src,
1293:                    RasterAccessor dst) {
1294:
1295:                // Get dimensions.
1296:                int dwidth = dst.getWidth();
1297:                int dheight = dst.getHeight();
1298:                int dnumBands = dst.getNumBands();
1299:
1300:                // Get destination data array references and strides.
1301:                float dstDataArrays[][] = dst.getFloatDataArrays();
1302:                int dstBandOffsets[] = dst.getBandOffsets();
1303:                int dstPixelStride = dst.getPixelStride();
1304:                int dstScanlineStride = dst.getScanlineStride();
1305:
1306:                // Get source data array references and strides.
1307:                float srcDataArrays[][] = src.getFloatDataArrays();
1308:                int srcBandOffsets[] = src.getBandOffsets();
1309:                int srcPixelStride = src.getPixelStride();
1310:                int srcScanlineStride = src.getScanlineStride();
1311:
1312:                // Compute reused numbers
1313:                int kernelNx = 2 * hKernel.length - hParity;
1314:                int kernelNy = 2 * vKernel.length - vParity;
1315:                int stepDown = (kernelNy - 1) * srcScanlineStride;
1316:                int stepRight = (kernelNx - 1) * srcPixelStride;
1317:
1318:                int upLeft, upRight, dnLeft, dnRight;
1319:                double kk;
1320:                double vCtr = (double) vKernel[0];
1321:                double hCtr = (double) hKernel[0];
1322:                int kInd, xLeft, xRight, xUp, xDown;
1323:
1324:                for (int band = 0; band < dnumBands; band++) {
1325:                    float dstData[] = dstDataArrays[band];
1326:                    float srcData[] = srcDataArrays[band];
1327:                    int srcScanlineOffset = srcBandOffsets[band];
1328:                    int dstScanlineOffset = dstBandOffsets[band];
1329:
1330:                    // Step over source raster coordinates
1331:                    for (int ySrc = 0; ySrc < scaleY * dheight; ySrc += scaleY) {
1332:                        int dInd = dstScanlineOffset;
1333:                        for (int xSrc = 0; xSrc < scaleX * dwidth; xSrc += scaleX) {
1334:
1335:                            int upLeft0 = xSrc * srcPixelStride + ySrc
1336:                                    * srcScanlineStride + srcScanlineOffset;
1337:                            int upRight0 = upLeft0 + stepRight;
1338:                            int dnLeft0 = upLeft0 + stepDown;
1339:                            int dnRight0 = upRight0 + stepDown;
1340:
1341:                            // Exploit 4-fold symmetry
1342:                            double sum = 0;
1343:
1344:                            // Make the rectangle squeeze in the vertical direction
1345:                            for (int iy = vKernel.length - 1; iy > vParity - 1; iy--) {
1346:                                upLeft = upLeft0;
1347:                                upRight = upRight0;
1348:                                dnLeft = dnLeft0;
1349:                                dnRight = dnRight0;
1350:
1351:                                // Make the rectangle squeeze in the horizontal direction
1352:                                for (int ix = hKernel.length - 1; ix > hParity - 1; ix--) {
1353:                                    kk = hKernel[ix] * vKernel[iy];
1354:                                    sum += kk
1355:                                            * ((double) srcData[upLeft]
1356:                                                    + (double) srcData[upRight]
1357:                                                    + (double) srcData[dnLeft] + (double) srcData[dnRight]);
1358:                                    upLeft += srcPixelStride;
1359:                                    upRight -= srcPixelStride;
1360:                                    dnLeft += srcPixelStride;
1361:                                    dnRight -= srcPixelStride;
1362:                                } // ix
1363:                                upLeft0 += srcScanlineStride; // down a row
1364:                                upRight0 += srcScanlineStride;
1365:                                dnLeft0 -= srcScanlineStride; // up a row
1366:                                dnRight0 -= srcScanlineStride;
1367:                            } // iy
1368:
1369:                            // Compute the remaining 2-Fold symmetry portions
1370:                            // (across and down as needed)
1371:
1372:                            // Loop down the center (hParity is odd)
1373:                            if (hParity == 1) {
1374:                                xUp = (xSrc + hKernel.length - 1)
1375:                                        * srcPixelStride + ySrc
1376:                                        * srcScanlineStride + srcScanlineOffset;
1377:                                xDown = xUp + stepDown;
1378:                                kInd = vKernel.length - 1;
1379:                                while (xUp < xDown) {
1380:                                    kk = hCtr * vKernel[kInd--];
1381:                                    sum += kk
1382:                                            * ((double) srcData[xUp] + (double) srcData[xDown]);
1383:                                    xUp += srcScanlineStride;
1384:                                    xDown -= srcScanlineStride;
1385:                                }
1386:                            } // hParity
1387:
1388:                            // Loop across the center (vParity is odd), pick up the center if hParity was odd
1389:                            if (vParity == 1) {
1390:                                xLeft = xSrc * srcPixelStride
1391:                                        + (ySrc + vKernel.length - 1)
1392:                                        * srcScanlineStride + srcScanlineOffset;
1393:                                xRight = xLeft + stepRight;
1394:                                kInd = hKernel.length - 1;
1395:                                while (xLeft < xRight) {
1396:                                    kk = vCtr * hKernel[kInd--];
1397:                                    sum += kk
1398:                                            * ((double) (srcData[xLeft]) + (double) (srcData[xRight]));
1399:                                    xLeft += srcPixelStride;
1400:                                    xRight -= srcPixelStride;
1401:                                } // while xLeft
1402:
1403:                                // Grab the center pixel if hParity was odd also
1404:                                if (hParity == 1)
1405:                                    sum += vCtr * hCtr
1406:                                            * ((double) srcData[xLeft]);
1407:
1408:                            } // if vParity
1409:
1410:                            dstData[dInd] = ImageUtil.clampFloat(sum);
1411:
1412:                            dInd += dstPixelStride;
1413:                        } // for xSrc
1414:
1415:                        dstScanlineOffset += dstScanlineStride;
1416:
1417:                    } // for ySrc
1418:
1419:                } // for band
1420:
1421:                return;
1422:
1423:            } // computeRectFloat
1424:
1425:            /** <code>computeRectDouble</code> filter subsamples double pixel data.
1426:             *
1427:             * @param src RasterAccessor for source image.
1428:             * @param dst RasterAccessor for output image.
1429:             */
1430:            protected void computeRectDouble(RasterAccessor src,
1431:                    RasterAccessor dst) {
1432:
1433:                // Get dimensions.
1434:                int dwidth = dst.getWidth();
1435:                int dheight = dst.getHeight();
1436:                int dnumBands = dst.getNumBands();
1437:
1438:                // Get destination data array references and strides.
1439:                double dstDataArrays[][] = dst.getDoubleDataArrays();
1440:                int dstBandOffsets[] = dst.getBandOffsets();
1441:                int dstPixelStride = dst.getPixelStride();
1442:                int dstScanlineStride = dst.getScanlineStride();
1443:
1444:                // Get source data array references and strides.
1445:                double srcDataArrays[][] = src.getDoubleDataArrays();
1446:                int srcBandOffsets[] = src.getBandOffsets();
1447:                int srcPixelStride = src.getPixelStride();
1448:                int srcScanlineStride = src.getScanlineStride();
1449:
1450:                // Compute reused numbers
1451:                int kernelNx = 2 * hKernel.length - hParity;
1452:                int kernelNy = 2 * vKernel.length - vParity;
1453:                int stepDown = (kernelNy - 1) * srcScanlineStride;
1454:                int stepRight = (kernelNx - 1) * srcPixelStride;
1455:
1456:                int upLeft, upRight, dnLeft, dnRight;
1457:                double kk;
1458:                double vCtr = (double) vKernel[0];
1459:                double hCtr = (double) hKernel[0];
1460:                int kInd, xLeft, xRight, xUp, xDown;
1461:
1462:                for (int band = 0; band < dnumBands; band++) {
1463:                    double dstData[] = dstDataArrays[band];
1464:                    double srcData[] = srcDataArrays[band];
1465:                    int srcScanlineOffset = srcBandOffsets[band];
1466:                    int dstScanlineOffset = dstBandOffsets[band];
1467:
1468:                    // Step over source raster coordinates
1469:                    for (int ySrc = 0; ySrc < scaleY * dheight; ySrc += scaleY) {
1470:                        int dInd = dstScanlineOffset;
1471:                        for (int xSrc = 0; xSrc < scaleX * dwidth; xSrc += scaleX) {
1472:
1473:                            int upLeft0 = xSrc * srcPixelStride + ySrc
1474:                                    * srcScanlineStride + srcScanlineOffset;
1475:                            int upRight0 = upLeft0 + stepRight;
1476:                            int dnLeft0 = upLeft0 + stepDown;
1477:                            int dnRight0 = upRight0 + stepDown;
1478:
1479:                            // Exploit 4-fold symmetry
1480:                            double sum = 0;
1481:
1482:                            // Make the rectangle squeeze in the vertical direction
1483:                            for (int iy = vKernel.length - 1; iy > vParity - 1; iy--) {
1484:                                upLeft = upLeft0;
1485:                                upRight = upRight0;
1486:                                dnLeft = dnLeft0;
1487:                                dnRight = dnRight0;
1488:
1489:                                // Make the rectangle squeeze in the horizontal direction
1490:                                for (int ix = hKernel.length - 1; ix > hParity - 1; ix--) {
1491:                                    kk = hKernel[ix] * vKernel[iy];
1492:                                    sum += kk
1493:                                            * (srcData[upLeft]
1494:                                                    + srcData[upRight]
1495:                                                    + srcData[dnLeft] + srcData[dnRight]);
1496:                                    upLeft += srcPixelStride;
1497:                                    upRight -= srcPixelStride;
1498:                                    dnLeft += srcPixelStride;
1499:                                    dnRight -= srcPixelStride;
1500:                                } // ix
1501:                                upLeft0 += srcScanlineStride; // down a row
1502:                                upRight0 += srcScanlineStride;
1503:                                dnLeft0 -= srcScanlineStride; // up a row
1504:                                dnRight0 -= srcScanlineStride;
1505:                            } // iy
1506:
1507:                            // Compute the remaining 2-Fold symmetry portions
1508:                            // (across and down as needed)
1509:
1510:                            // Loop down the center (hParity is odd)
1511:                            if (hParity == 1) {
1512:                                xUp = (xSrc + hKernel.length - 1)
1513:                                        * srcPixelStride + ySrc
1514:                                        * srcScanlineStride + srcScanlineOffset;
1515:                                xDown = xUp + stepDown;
1516:                                kInd = vKernel.length - 1;
1517:                                while (xUp < xDown) {
1518:                                    kk = hCtr * vKernel[kInd--];
1519:                                    sum += kk * (srcData[xUp] + srcData[xDown]);
1520:                                    xUp += srcScanlineStride;
1521:                                    xDown -= srcScanlineStride;
1522:                                }
1523:                            } // hParity
1524:
1525:                            // Loop across the center (vParity is odd), pick up the center if hParity was odd
1526:                            if (vParity == 1) {
1527:                                xLeft = xSrc * srcPixelStride
1528:                                        + (ySrc + vKernel.length - 1)
1529:                                        * srcScanlineStride + srcScanlineOffset;
1530:                                xRight = xLeft + stepRight;
1531:                                kInd = hKernel.length - 1;
1532:                                while (xLeft < xRight) {
1533:                                    kk = vCtr * hKernel[kInd--];
1534:                                    sum += kk
1535:                                            * (srcData[xLeft] + srcData[xRight]);
1536:                                    xLeft += srcPixelStride;
1537:                                    xRight -= srcPixelStride;
1538:                                } // while xLeft
1539:
1540:                                // Grab the center pixel if hParity was odd also
1541:                                if (hParity == 1)
1542:                                    sum += vCtr * hCtr * srcData[xLeft];
1543:
1544:                            } // if vParity
1545:
1546:                            dstData[dInd] = sum;
1547:
1548:                            dInd += dstPixelStride;
1549:                        } // for xSrc
1550:
1551:                        dstScanlineOffset += dstScanlineStride;
1552:
1553:                    } // for ySrc
1554:
1555:                } // for band
1556:
1557:                return;
1558:
1559:            } // computeRectDouble
1560:
1561:        } // class FilteredSubsampleOpImage
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.