001: /*
002: * $RCSfile: ScaleBilinearOpImage.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:56:42 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.Rectangle;
015: import java.awt.image.DataBuffer;
016: import java.awt.image.Raster;
017: import java.awt.image.RenderedImage;
018: import java.awt.image.WritableRaster;
019: import java.awt.image.renderable.ParameterBlock;
020: import javax.media.jai.BorderExtender;
021: import javax.media.jai.ImageLayout;
022: import javax.media.jai.Interpolation;
023: import javax.media.jai.InterpolationBilinear;
024: import javax.media.jai.OpImage;
025: import javax.media.jai.PlanarImage;
026: import javax.media.jai.RasterAccessor;
027: import javax.media.jai.RasterFormatTag;
028: import javax.media.jai.ScaleOpImage;
029: import java.util.Map;
030: import com.sun.media.jai.util.Rational;
031:
032: // import com.sun.media.jai.test.OpImageTester;
033:
034: /**
035: * An <code>OpImage</code> that performs bilinear interpolation scaling.
036: *
037: */
038: final class ScaleBilinearOpImage extends ScaleOpImage {
039:
040: /** The number of SubsampleBits */
041: private int subsampleBits;
042:
043: /** Subsampling related variables */
044: int one, shift2, round2;
045:
046: Rational half = new Rational(1, 2);
047: long invScaleYInt, invScaleYFrac;
048: long invScaleXInt, invScaleXFrac;
049:
050: /**
051: * Constructs a ScaleBilinearOpImage from a RenderedImage source,
052: *
053: * @param source a RenderedImage.
054: * @param extender a BorderExtender, or null.
055: * @param layout an ImageLayout optionally containing the tile grid layout,
056: * SampleModel, and ColorModel, or null.
057: * @param xScale scale factor along x axis.
058: * @param yScale scale factor along y axis.
059: * @param xTrans translation factor along x axis.
060: * @param yTrans translation factor along y axis.
061: * @param interp a Interpolation object to use for resampling.
062: */
063: public ScaleBilinearOpImage(RenderedImage source,
064: BorderExtender extender, Map config, ImageLayout layout,
065: float xScale, float yScale, float xTrans, float yTrans,
066: Interpolation interp) {
067: super (source, layout, config, true, extender, interp, xScale,
068: yScale, xTrans, yTrans);
069:
070: subsampleBits = interp.getSubsampleBitsH();
071:
072: // Number of subsampling positions
073: one = 1 << subsampleBits;
074:
075: // Subsampling related variables
076: shift2 = 2 * subsampleBits;
077: round2 = 1 << (shift2 - 1);
078:
079: if (invScaleYRational.num > invScaleYRational.denom) {
080: invScaleYInt = invScaleYRational.num
081: / invScaleYRational.denom;
082: invScaleYFrac = invScaleYRational.num
083: % invScaleYRational.denom;
084: } else {
085: invScaleYInt = 0;
086: invScaleYFrac = invScaleYRational.num;
087: }
088:
089: if (invScaleXRational.num > invScaleXRational.denom) {
090: invScaleXInt = invScaleXRational.num
091: / invScaleXRational.denom;
092: invScaleXFrac = invScaleXRational.num
093: % invScaleXRational.denom;
094: } else {
095: invScaleXInt = 0;
096: invScaleXFrac = invScaleXRational.num;
097: }
098: }
099:
100: /**
101: * Performs scale operation on a specified rectangle. The sources are
102: * cobbled.
103: *
104: * @param sources an array of source Rasters, guaranteed to provide all
105: * necessary source data for computing the output.
106: * @param dest a WritableRaster tile containing the area to be computed.
107: * @param destRect the rectangle within dest to be processed.
108: */
109: protected void computeRect(Raster[] sources, WritableRaster dest,
110: Rectangle destRect) {
111: // Retrieve format tags.
112: RasterFormatTag[] formatTags = getFormatTags();
113:
114: Raster source = sources[0];
115: // Get the source rectangle
116: Rectangle srcRect = source.getBounds();
117:
118: RasterAccessor srcAccessor = new RasterAccessor(source,
119: srcRect, formatTags[0], getSource(0).getColorModel());
120:
121: RasterAccessor dstAccessor = new RasterAccessor(dest, destRect,
122: formatTags[1], getColorModel());
123:
124: int dwidth = destRect.width;
125: int dheight = destRect.height;
126: int srcPixelStride = srcAccessor.getPixelStride();
127: int srcScanlineStride = srcAccessor.getScanlineStride();
128:
129: int[] ypos = new int[dheight];
130: int[] xpos = new int[dwidth];
131:
132: int xfracvalues[] = null, yfracvalues[] = null;
133: float xfracvaluesFloat[] = null, yfracvaluesFloat[] = null;
134:
135: switch (dstAccessor.getDataType()) {
136: case DataBuffer.TYPE_BYTE:
137: case DataBuffer.TYPE_SHORT:
138: case DataBuffer.TYPE_USHORT:
139: case DataBuffer.TYPE_INT:
140: yfracvalues = new int[dheight];
141: xfracvalues = new int[dwidth];
142: preComputePositionsInt(destRect, srcRect.x, srcRect.y,
143: srcPixelStride, srcScanlineStride, xpos, ypos,
144: xfracvalues, yfracvalues);
145: break;
146:
147: case DataBuffer.TYPE_FLOAT:
148: case DataBuffer.TYPE_DOUBLE:
149: yfracvaluesFloat = new float[dheight];
150: xfracvaluesFloat = new float[dwidth];
151: preComputePositionsFloat(destRect, srcRect.x, srcRect.y,
152: srcPixelStride, srcScanlineStride, xpos, ypos,
153: xfracvaluesFloat, yfracvaluesFloat);
154: break;
155:
156: default:
157: throw new RuntimeException(JaiI18N
158: .getString("OrderedDitherOpImage0"));
159: }
160:
161: switch (dstAccessor.getDataType()) {
162: case DataBuffer.TYPE_BYTE:
163: byteLoop(srcAccessor, destRect, dstAccessor, xpos, ypos,
164: xfracvalues, yfracvalues);
165: break;
166:
167: case DataBuffer.TYPE_SHORT:
168: shortLoop(srcAccessor, destRect, dstAccessor, xpos, ypos,
169: xfracvalues, yfracvalues);
170: break;
171:
172: case DataBuffer.TYPE_USHORT:
173: ushortLoop(srcAccessor, destRect, dstAccessor, xpos, ypos,
174: xfracvalues, yfracvalues);
175: break;
176:
177: case DataBuffer.TYPE_INT:
178: intLoop(srcAccessor, destRect, dstAccessor, xpos, ypos,
179: xfracvalues, yfracvalues);
180: break;
181:
182: case DataBuffer.TYPE_FLOAT:
183: floatLoop(srcAccessor, destRect, dstAccessor, xpos, ypos,
184: xfracvaluesFloat, yfracvaluesFloat);
185: break;
186:
187: case DataBuffer.TYPE_DOUBLE:
188: doubleLoop(srcAccessor, destRect, dstAccessor, xpos, ypos,
189: xfracvaluesFloat, yfracvaluesFloat);
190: break;
191: }
192:
193: // If the RasterAccessor object set up a temporary buffer for the
194: // op to write to, tell the RasterAccessor to write that data
195: // to the raster no that we're done with it.
196: if (dstAccessor.isDataCopy()) {
197: dstAccessor.clampDataArrays();
198: dstAccessor.copyDataToRaster();
199: }
200: }
201:
202: private void preComputePositionsInt(Rectangle destRect,
203: int srcRectX, int srcRectY, int srcPixelStride,
204: int srcScanlineStride, int xpos[], int ypos[],
205: int xfracvalues[], int yfracvalues[]) {
206:
207: int dwidth = destRect.width;
208: int dheight = destRect.height;
209:
210: // Loop variables based on the destination rectangle to be calculated.
211: int dx = destRect.x;
212: int dy = destRect.y;
213:
214: long syNum = dy, syDenom = 1;
215:
216: // Subtract the X translation factor sy -= transY
217: syNum = syNum * transYRationalDenom - transYRationalNum
218: * syDenom;
219: syDenom *= transYRationalDenom;
220:
221: // Add 0.5
222: syNum = 2 * syNum + syDenom;
223: syDenom *= 2;
224:
225: // Multply by invScaleX
226: syNum *= invScaleYRationalNum;
227: syDenom *= invScaleYRationalDenom;
228:
229: // Subtract 0.5
230: syNum = 2 * syNum - syDenom;
231: syDenom *= 2;
232:
233: // Separate the x source coordinate into integer and fractional part
234: int srcYInt = Rational.floor(syNum, syDenom);
235: long srcYFrac = syNum % syDenom;
236: if (srcYInt < 0) {
237: srcYFrac = syDenom + srcYFrac;
238: }
239:
240: // Normalize - Get a common denominator for the fracs of
241: // src and invScaleY
242: long commonYDenom = syDenom * invScaleYRationalDenom;
243: srcYFrac *= invScaleYRationalDenom;
244: long newInvScaleYFrac = invScaleYFrac * syDenom;
245:
246: // Precalculate the x positions and store them in an array.
247: long sxNum = dx, sxDenom = 1;
248:
249: // Subtract the X translation factor sx -= transX
250: sxNum = sxNum * transXRationalDenom - transXRationalNum
251: * sxDenom;
252: sxDenom *= transXRationalDenom;
253:
254: // Add 0.5
255: sxNum = 2 * sxNum + sxDenom;
256: sxDenom *= 2;
257:
258: // Multply by invScaleX
259: sxNum *= invScaleXRationalNum;
260: sxDenom *= invScaleXRationalDenom;
261:
262: // Subtract 0.5
263: sxNum = 2 * sxNum - sxDenom;
264: sxDenom *= 2;
265:
266: // Separate the x source coordinate into integer and fractional part
267: int srcXInt = Rational.floor(sxNum, sxDenom);
268: long srcXFrac = sxNum % sxDenom;
269: if (srcXInt < 0) {
270: srcXFrac = sxDenom + srcXFrac;
271: }
272:
273: // Normalize - Get a common denominator for the fracs of
274: // src and invScaleX
275: long commonXDenom = sxDenom * invScaleXRationalDenom;
276: srcXFrac *= invScaleXRationalDenom;
277: long newInvScaleXFrac = invScaleXFrac * sxDenom;
278:
279: for (int i = 0; i < dwidth; i++) {
280: xpos[i] = (srcXInt - srcRectX) * srcPixelStride;
281: xfracvalues[i] = (int) (((float) srcXFrac / (float) commonXDenom) * one);
282:
283: // Move onto the next source pixel.
284:
285: // Add the integral part of invScaleX to the integral part
286: // of srcX
287: srcXInt += invScaleXInt;
288:
289: // Add the fractional part of invScaleX to the fractional part
290: // of srcX
291: srcXFrac += newInvScaleXFrac;
292:
293: // If the fractional part is now greater than equal to the
294: // denominator, divide so as to reduce the numerator to be less
295: // than the denominator and add the overflow to the integral part.
296: if (srcXFrac >= commonXDenom) {
297: srcXInt += 1;
298: srcXFrac -= commonXDenom;
299: }
300: }
301:
302: for (int i = 0; i < dheight; i++) {
303:
304: // Calculate the source position in the source data array.
305: ypos[i] = (srcYInt - srcRectY) * srcScanlineStride;
306:
307: // Calculate the yfrac value
308: yfracvalues[i] = (int) (((float) srcYFrac / (float) commonYDenom) * one);
309:
310: // Move onto the next source pixel.
311:
312: // Add the integral part of invScaleY to the integral part
313: // of srcY
314: srcYInt += invScaleYInt;
315:
316: // Add the fractional part of invScaleY to the fractional part
317: // of srcY
318: srcYFrac += newInvScaleYFrac;
319:
320: // If the fractional part is now greater than equal to the
321: // denominator, divide so as to reduce the numerator to be less
322: // than the denominator and add the overflow to the integral part.
323: if (srcYFrac >= commonYDenom) {
324: srcYInt += 1;
325: srcYFrac -= commonYDenom;
326: }
327: }
328: }
329:
330: private void preComputePositionsFloat(Rectangle destRect,
331: int srcRectX, int srcRectY, int srcPixelStride,
332: int srcScanlineStride, int xpos[], int ypos[],
333: float xfracvaluesFloat[], float yfracvaluesFloat[]) {
334:
335: int dwidth = destRect.width;
336: int dheight = destRect.height;
337:
338: // Loop variables based on the destination rectangle to be calculated.
339: int dx = destRect.x;
340: int dy = destRect.y;
341:
342: long syNum = dy, syDenom = 1;
343:
344: // Subtract the X translation factor sy -= transY
345: syNum = syNum * transYRationalDenom - transYRationalNum
346: * syDenom;
347: syDenom *= transYRationalDenom;
348:
349: // Add 0.5
350: syNum = 2 * syNum + syDenom;
351: syDenom *= 2;
352:
353: // Multply by invScaleX
354: syNum *= invScaleYRationalNum;
355: syDenom *= invScaleYRationalDenom;
356:
357: // Subtract 0.5
358: syNum = 2 * syNum - syDenom;
359: syDenom *= 2;
360:
361: // Separate the x source coordinate into integer and fractional part
362: int srcYInt = Rational.floor(syNum, syDenom);
363: long srcYFrac = syNum % syDenom;
364: if (srcYInt < 0) {
365: srcYFrac = syDenom + srcYFrac;
366: }
367:
368: // Normalize - Get a common denominator for the fracs of
369: // src and invScaleY
370: long commonYDenom = syDenom * invScaleYRationalDenom;
371: srcYFrac *= invScaleYRationalDenom;
372: long newInvScaleYFrac = invScaleYFrac * syDenom;
373:
374: // Precalculate the x positions and store them in an array.
375: long sxNum = dx, sxDenom = 1;
376:
377: // Subtract the X translation factor sx -= transX
378: sxNum = sxNum * transXRationalDenom - transXRationalNum
379: * sxDenom;
380: sxDenom *= transXRationalDenom;
381:
382: // Add 0.5
383: sxNum = 2 * sxNum + sxDenom;
384: sxDenom *= 2;
385:
386: // Multply by invScaleX
387: sxNum *= invScaleXRationalNum;
388: sxDenom *= invScaleXRationalDenom;
389:
390: // Subtract 0.5
391: sxNum = 2 * sxNum - sxDenom;
392: sxDenom *= 2;
393:
394: // Separate the x source coordinate into integer and fractional part
395: int srcXInt = Rational.floor(sxNum, sxDenom);
396: long srcXFrac = sxNum % sxDenom;
397: if (srcXInt < 0) {
398: srcXFrac = sxDenom + srcXFrac;
399: }
400:
401: // Normalize - Get a common denominator for the fracs of
402: // src and invScaleX
403: long commonXDenom = sxDenom * invScaleXRationalDenom;
404: srcXFrac *= invScaleXRationalDenom;
405: long newInvScaleXFrac = invScaleXFrac * sxDenom;
406:
407: for (int i = 0; i < dwidth; i++) {
408:
409: xpos[i] = (srcXInt - srcRectX) * srcPixelStride;
410: xfracvaluesFloat[i] = (float) srcXFrac
411: / (float) commonXDenom;
412:
413: // Move onto the next source pixel.
414:
415: // Add the integral part of invScaleX to the integral part
416: // of srcX
417: srcXInt += invScaleXInt;
418:
419: // Add the fractional part of invScaleX to the fractional part
420: // of srcX
421: srcXFrac += newInvScaleXFrac;
422:
423: // If the fractional part is now greater than equal to the
424: // denominator, divide so as to reduce the numerator to be less
425: // than the denominator and add the overflow to the integral part.
426: if (srcXFrac >= commonXDenom) {
427: srcXInt += 1;
428: srcXFrac -= commonXDenom;
429: }
430: }
431:
432: for (int i = 0; i < dheight; i++) {
433:
434: // Calculate the source position in the source data array.
435: ypos[i] = (srcYInt - srcRectY) * srcScanlineStride;
436:
437: // Calculate the yfrac value
438: yfracvaluesFloat[i] = (float) srcYFrac
439: / (float) commonYDenom;
440:
441: // Move onto the next source pixel.
442:
443: // Add the integral part of invScaleY to the integral part
444: // of srcY
445: srcYInt += invScaleYInt;
446:
447: // Add the fractional part of invScaleY to the fractional part
448: // of srcY
449: srcYFrac += newInvScaleYFrac;
450:
451: // If the fractional part is now greater than equal to the
452: // denominator, divide so as to reduce the numerator to be less
453: // than the denominator and add the overflow to the integral part.
454: if (srcYFrac >= commonYDenom) {
455: srcYInt += 1;
456: srcYFrac -= commonYDenom;
457: }
458: }
459:
460: }
461:
462: private void byteLoop(RasterAccessor src, Rectangle dstRect,
463: RasterAccessor dst, int xpos[], int ypos[],
464: int xfracvalues[], int yfracvalues[]) {
465:
466: int srcPixelStride = src.getPixelStride();
467: int srcScanlineStride = src.getScanlineStride();
468: int srcLastXDataPos = (src.getWidth() - 1) * srcPixelStride;
469:
470: int dwidth = dstRect.width;
471: int dheight = dstRect.height;
472: int dnumBands = dst.getNumBands();
473: byte dstDataArrays[][] = dst.getByteDataArrays();
474: int dstBandOffsets[] = dst.getBandOffsets();
475: int dstPixelStride = dst.getPixelStride();
476: int dstScanlineStride = dst.getScanlineStride();
477:
478: byte srcDataArrays[][] = src.getByteDataArrays();
479: int bandOffsets[] = src.getBandOffsets();
480:
481: int dstOffset = 0;
482:
483: /* Four surrounding pixels are needed for Bilinear interpolation.
484: * If the dest pixel to be calculated is at (dx, dy) then the
485: * actual source pixel (sx, sy) required is (dx/scaleX, dy/scaleY).
486: * The four pixels that surround it are at the positions:
487: * s00 = src(sxlow, sylow)
488: * s01 = src(sxhigh, sylow)
489: * s10 = src(sxlow, syhigh)
490: * s11 = src(sxhigh, syhigh)
491: * where sxlow = Math.floor(sx), sxhigh = Math.ceil(sx)
492: * and sylow = Math.floor(sy), syhigh = Math.ceil(sy)
493: *
494: * The value of the destination pixel can now be calculated as:
495: * s0 = (s01 - s00)*xfrac + s00;
496: * s1 = (s11 - s10)*xfrac + s10;
497: * dst(x,y) = (s1 - s0)*yfrac + s0;
498: */
499:
500: int posylow, posyhigh, posxlow, posxhigh;
501: int s00, s01, s10, s11;
502:
503: // Precalculate the y positions and store them in an array.
504: int xfrac, yfrac;
505: int s, s0, s1;
506:
507: // Putting band loop outside
508: for (int k = 0; k < dnumBands; k++) {
509: byte dstData[] = dstDataArrays[k];
510: byte srcData[] = srcDataArrays[k];
511: int dstScanlineOffset = dstBandOffsets[k];
512: int bandOffset = bandOffsets[k];
513: for (int j = 0; j < dheight; j++) {
514:
515: int dstPixelOffset = dstScanlineOffset;
516: yfrac = yfracvalues[j];
517: posylow = ypos[j] + bandOffset;
518: posyhigh = posylow + srcScanlineStride;
519:
520: for (int i = 0; i < dwidth; i++) {
521: xfrac = xfracvalues[i];
522: posxlow = xpos[i];
523: posxhigh = posxlow + srcPixelStride;
524:
525: // Get the four surrounding pixel values
526: s00 = srcData[posxlow + posylow] & 0xff;
527: s01 = srcData[posxhigh + posylow] & 0xff;
528: s10 = srcData[posxlow + posyhigh] & 0xff;
529: s11 = srcData[posxhigh + posyhigh] & 0xff;
530:
531: // Perform the bilinear interpolation
532: s0 = (s01 - s00) * xfrac + (s00 << subsampleBits);
533: s1 = (s11 - s10) * xfrac + (s10 << subsampleBits);
534: s = ((s1 - s0) * yfrac + (s0 << subsampleBits) + round2) >> shift2;
535:
536: dstData[dstPixelOffset] = (byte) (s & 0xff);
537: dstPixelOffset += dstPixelStride;
538: }
539: dstScanlineOffset += dstScanlineStride;
540:
541: }
542: }
543: }
544:
545: private void shortLoop(RasterAccessor src, Rectangle dstRect,
546: RasterAccessor dst, int xpos[], int ypos[],
547: int xfracvalues[], int yfracvalues[]) {
548:
549: int srcPixelStride = src.getPixelStride();
550: int srcScanlineStride = src.getScanlineStride();
551: int srcLastXDataPos = (src.getWidth() - 1) * srcPixelStride;
552:
553: int dwidth = dstRect.width;
554: int dheight = dstRect.height;
555: int dnumBands = dst.getNumBands();
556: short dstDataArrays[][] = dst.getShortDataArrays();
557: int dstBandOffsets[] = dst.getBandOffsets();
558: int dstPixelStride = dst.getPixelStride();
559: int dstScanlineStride = dst.getScanlineStride();
560:
561: short srcDataArrays[][] = src.getShortDataArrays();
562: int bandOffsets[] = src.getBandOffsets();
563:
564: int dstOffset = 0;
565: int posylow, posyhigh, posxlow, posxhigh;
566: int s00, s01, s10, s11, s0, s1, s;
567: int xfrac, yfrac;
568:
569: // Putting band loop outside
570: for (int k = 0; k < dnumBands; k++) {
571: short dstData[] = dstDataArrays[k];
572: short srcData[] = srcDataArrays[k];
573: int dstScanlineOffset = dstBandOffsets[k];
574: int bandOffset = bandOffsets[k];
575: for (int j = 0; j < dheight; j++) {
576: int dstPixelOffset = dstScanlineOffset;
577: yfrac = yfracvalues[j];
578: posylow = ypos[j] + bandOffset;
579: posyhigh = posylow + srcScanlineStride;
580:
581: for (int i = 0; i < dwidth; i++) {
582: xfrac = xfracvalues[i];
583: posxlow = xpos[i];
584: posxhigh = posxlow + srcPixelStride;
585:
586: // Get the four surrounding pixel values
587: s00 = srcData[posxlow + posylow];
588: s01 = srcData[posxhigh + posylow];
589: s10 = srcData[posxlow + posyhigh];
590: s11 = srcData[posxhigh + posyhigh];
591:
592: // Perform the bilinear interpolation
593: s0 = (s01 - s00) * xfrac + (s00 << subsampleBits);
594: s1 = (s11 - s10) * xfrac + (s10 << subsampleBits);
595: s = ((s1 - s0) * yfrac + (s0 << subsampleBits) + round2) >> shift2;
596:
597: dstData[dstPixelOffset] = (short) s;
598: dstPixelOffset += dstPixelStride;
599: }
600: dstScanlineOffset += dstScanlineStride;
601: }
602: }
603: }
604:
605: private void ushortLoop(RasterAccessor src, Rectangle dstRect,
606: RasterAccessor dst, int xpos[], int ypos[],
607: int xfracvalues[], int yfracvalues[]) {
608:
609: int srcPixelStride = src.getPixelStride();
610: int srcScanlineStride = src.getScanlineStride();
611: int srcLastXDataPos = (src.getWidth() - 1) * srcPixelStride;
612:
613: int dwidth = dstRect.width;
614: int dheight = dstRect.height;
615: int dnumBands = dst.getNumBands();
616: short dstDataArrays[][] = dst.getShortDataArrays();
617: int dstBandOffsets[] = dst.getBandOffsets();
618: int dstPixelStride = dst.getPixelStride();
619: int dstScanlineStride = dst.getScanlineStride();
620:
621: short srcDataArrays[][] = src.getShortDataArrays();
622: int bandOffsets[] = src.getBandOffsets();
623:
624: int dstOffset = 0;
625: int posylow, posyhigh, posxlow, posxhigh;
626: int s00, s01, s10, s11, s0, s1, s;
627: int xfrac, yfrac;
628:
629: // Putting band loop outside
630: for (int k = 0; k < dnumBands; k++) {
631: short dstData[] = dstDataArrays[k];
632: short srcData[] = srcDataArrays[k];
633: int dstScanlineOffset = dstBandOffsets[k];
634: int bandOffset = bandOffsets[k];
635: for (int j = 0; j < dheight; j++) {
636: int dstPixelOffset = dstScanlineOffset;
637: yfrac = yfracvalues[j];
638: posylow = ypos[j] + bandOffset;
639: posyhigh = posylow + srcScanlineStride;
640:
641: for (int i = 0; i < dwidth; i++) {
642: xfrac = xfracvalues[i];
643: posxlow = xpos[i];
644: posxhigh = posxlow + srcPixelStride;
645:
646: // Get the four surrounding pixel values
647: s00 = srcData[posxlow + posylow] & 0xffff;
648: s01 = srcData[posxhigh + posylow] & 0xffff;
649: s10 = srcData[posxlow + posyhigh] & 0xffff;
650: s11 = srcData[posxhigh + posyhigh] & 0xffff;
651:
652: // Perform the bilinear interpolation
653: s0 = (s01 - s00) * xfrac + (s00 << subsampleBits);
654: s1 = (s11 - s10) * xfrac + (s10 << subsampleBits);
655: s = ((s1 - s0) * yfrac + (s0 << subsampleBits) + round2) >> shift2;
656:
657: dstData[dstPixelOffset] = (short) (s & 0xffff);
658: dstPixelOffset += dstPixelStride;
659: }
660: dstScanlineOffset += dstScanlineStride;
661: }
662: }
663: }
664:
665: // identical to byteLoops, except datatypes have changed. clumsy,
666: // but there's no other way in Java
667: private void intLoop(RasterAccessor src, Rectangle dstRect,
668: RasterAccessor dst, int xpos[], int ypos[],
669: int xfracvalues[], int yfracvalues[]) {
670:
671: int srcPixelStride = src.getPixelStride();
672: int srcScanlineStride = src.getScanlineStride();
673: int srcLastXDataPos = (src.getWidth() - 1) * srcPixelStride;
674:
675: int dwidth = dstRect.width;
676: int dheight = dstRect.height;
677: int dnumBands = dst.getNumBands();
678: int dstDataArrays[][] = dst.getIntDataArrays();
679: int dstBandOffsets[] = dst.getBandOffsets();
680: int dstPixelStride = dst.getPixelStride();
681: int dstScanlineStride = dst.getScanlineStride();
682:
683: int srcDataArrays[][] = src.getIntDataArrays();
684: int bandOffsets[] = src.getBandOffsets();
685:
686: int dstOffset = 0;
687: int posylow, posyhigh, posxlow, posxhigh;
688: int s00, s10, s01, s11;
689: long s0, s1;
690: int xfrac, yfrac;
691: int shift = 29 - subsampleBits;
692:
693: // Putting band loop outside
694: for (int k = 0; k < dnumBands; k++) {
695: int dstData[] = dstDataArrays[k];
696: int srcData[] = srcDataArrays[k];
697: int dstScanlineOffset = dstBandOffsets[k];
698: int bandOffset = bandOffsets[k];
699: for (int j = 0; j < dheight; j++) {
700: int dstPixelOffset = dstScanlineOffset;
701: yfrac = yfracvalues[j];
702: posylow = ypos[j] + bandOffset;
703: posyhigh = posylow + srcScanlineStride;
704:
705: for (int i = 0; i < dwidth; i++) {
706: xfrac = xfracvalues[i];
707: posxlow = xpos[i];
708: posxhigh = posxlow + srcPixelStride;
709:
710: // Get the four surrounding pixel values
711: s00 = srcData[posxlow + posylow];
712: s01 = srcData[posxhigh + posylow];
713: s10 = srcData[posxlow + posyhigh];
714: s11 = srcData[posxhigh + posyhigh];
715:
716: // Perform the bilinear interpolation
717: if ((s00 | s10) >>> shift == 0) {
718: if ((s01 | s11) >>> shift == 0) {
719: s0 = (s01 - s00) * xfrac
720: + (s00 << subsampleBits);
721: s1 = (s11 - s10) * xfrac
722: + (s10 << subsampleBits);
723: } else {
724: s0 = ((long) s01 - s00) * xfrac
725: + (s00 << subsampleBits);
726: s1 = ((long) s11 - s10) * xfrac
727: + (s10 << subsampleBits);
728: }
729: } else {
730: s0 = ((long) s01 - s00) * xfrac
731: + ((long) s00 << subsampleBits);
732: s1 = ((long) s11 - s10) * xfrac
733: + ((long) s10 << subsampleBits);
734: }
735:
736: dstData[dstPixelOffset] = (int) (((s1 - s0) * yfrac
737: + (s0 << subsampleBits) + round2) >> shift2);
738:
739: dstPixelOffset += dstPixelStride;
740: }
741: dstScanlineOffset += dstScanlineStride;
742: }
743: }
744: }
745:
746: // Interpolation for floating point samples done as specified by the
747: // following formula:
748: // float s0 = (s01 - s00)*xfrac + s00;
749: // float s1 = (s11 - s10)*xfrac + s10;
750: // return (s1 - s0)*yfrac + s0;
751: // Note that xfrac, yfrac are in the range [0.0F, 1.0F)
752:
753: private void floatLoop(RasterAccessor src, Rectangle dstRect,
754: RasterAccessor dst, int xpos[], int ypos[],
755: float xfracvaluesFloat[], float yfracvaluesFloat[]) {
756:
757: int srcPixelStride = src.getPixelStride();
758: int srcScanlineStride = src.getScanlineStride();
759: int srcLastXDataPos = (src.getWidth() - 1) * srcPixelStride;
760:
761: int dwidth = dstRect.width;
762: int dheight = dstRect.height;
763: int dnumBands = dst.getNumBands();
764: float dstDataArrays[][] = dst.getFloatDataArrays();
765: int dstBandOffsets[] = dst.getBandOffsets();
766: int dstPixelStride = dst.getPixelStride();
767: int dstScanlineStride = dst.getScanlineStride();
768:
769: float srcDataArrays[][] = src.getFloatDataArrays();
770: int bandOffsets[] = src.getBandOffsets();
771:
772: float s00, s01, s10, s11;
773: float s0, s1;
774: float xfrac, yfrac;
775: int dstOffset = 0;
776: int posylow, posyhigh, posxlow, posxhigh;
777:
778: // Putting band loop outside
779: for (int k = 0; k < dnumBands; k++) {
780: float dstData[] = dstDataArrays[k];
781: float srcData[] = srcDataArrays[k];
782: int dstScanlineOffset = dstBandOffsets[k];
783: int bandOffset = bandOffsets[k];
784: for (int j = 0; j < dheight; j++) {
785: int dstPixelOffset = dstScanlineOffset;
786: yfrac = yfracvaluesFloat[j];
787: posylow = ypos[j] + bandOffset;
788: posyhigh = posylow + srcScanlineStride;
789:
790: for (int i = 0; i < dwidth; i++) {
791: xfrac = xfracvaluesFloat[i];
792: posxlow = xpos[i];
793: posxhigh = posxlow + srcPixelStride;
794:
795: // Get the four surrounding pixel values
796: s00 = srcData[posxlow + posylow];
797: s01 = srcData[posxhigh + posylow];
798: s10 = srcData[posxlow + posyhigh];
799: s11 = srcData[posxhigh + posyhigh];
800:
801: // Perform the bilinear interpolation
802: s0 = (s01 - s00) * xfrac + s00;
803: s1 = (s11 - s10) * xfrac + s10;
804:
805: dstData[dstPixelOffset] = (s1 - s0) * yfrac + s0;
806:
807: dstPixelOffset += dstPixelStride;
808: }
809: dstScanlineOffset += dstScanlineStride;
810: }
811: }
812: }
813:
814: private void doubleLoop(RasterAccessor src, Rectangle dstRect,
815: RasterAccessor dst, int xpos[], int ypos[],
816: float xfracvaluesFloat[], float yfracvaluesFloat[]) {
817:
818: int srcPixelStride = src.getPixelStride();
819: int srcScanlineStride = src.getScanlineStride();
820: int srcLastXDataPos = (src.getWidth() - 1) * srcPixelStride;
821:
822: int dwidth = dstRect.width;
823: int dheight = dstRect.height;
824: int dnumBands = dst.getNumBands();
825: double dstDataArrays[][] = dst.getDoubleDataArrays();
826: int dstBandOffsets[] = dst.getBandOffsets();
827: int dstPixelStride = dst.getPixelStride();
828: int dstScanlineStride = dst.getScanlineStride();
829:
830: double srcDataArrays[][] = src.getDoubleDataArrays();
831: int bandOffsets[] = src.getBandOffsets();
832:
833: double s00, s01, s10, s11;
834: double s0, s1;
835: double xfrac, yfrac;
836: int dstOffset = 0;
837: int posylow, posyhigh, posxlow, posxhigh;
838:
839: // Putting band loop outside
840: for (int k = 0; k < dnumBands; k++) {
841: double dstData[] = dstDataArrays[k];
842: double srcData[] = srcDataArrays[k];
843: int dstScanlineOffset = dstBandOffsets[k];
844: int bandOffset = bandOffsets[k];
845: for (int j = 0; j < dheight; j++) {
846: int dstPixelOffset = dstScanlineOffset;
847: yfrac = yfracvaluesFloat[j];
848: posylow = ypos[j] + bandOffset;
849: posyhigh = posylow + srcScanlineStride;
850:
851: for (int i = 0; i < dwidth; i++) {
852: xfrac = xfracvaluesFloat[i];
853: posxlow = xpos[i];
854: posxhigh = posxlow + srcPixelStride;
855:
856: // Get the four surrounding pixel values
857: s00 = srcData[posxlow + posylow];
858: s01 = srcData[posxhigh + posylow];
859: s10 = srcData[posxlow + posyhigh];
860: s11 = srcData[posxhigh + posyhigh];
861:
862: // Perform the bilinear interpolation
863: s0 = (s01 - s00) * xfrac + s00;
864: s1 = (s11 - s10) * xfrac + s10;
865:
866: dstData[dstPixelOffset] = (s1 - s0) * yfrac + s0;
867:
868: dstPixelOffset += dstPixelStride;
869: }
870: dstScanlineOffset += dstScanlineStride;
871: }
872: }
873: }
874:
875: // public static OpImage createTestImage(OpImageTester oit) {
876: // Interpolation interp =
877: // Interpolation.getInstance(Interpolation.INTERP_BILINEAR);
878: // return new ScaleBilinearOpImage(oit.getSource(), null, null,
879: // new ImageLayout(oit.getSource()),
880: // 2.5F, 2.5F, 0.0F, 0.0F,
881: // interp);
882: // }
883:
884: // public static void main(String args[]) {
885: // String classname = "com.sun.media.jai.opimage.ScaleBilinearOpImage";
886: // OpImageTester.performDiagnostics(classname,args);
887: // System.exit(1);
888:
889: // System.out.println("ScaleOpImage Test");
890: // ImageLayout layout;
891: // OpImage src, dst;
892: // Rectangle rect = new Rectangle(0, 0, 5, 5);
893:
894: // InterpolationBilinear interp = new InterpolationBilinear();
895:
896: // System.out.println("1. PixelInterleaved short 3-band");
897: // layout = OpImageTester.createImageLayout(
898: // 0, 0, 200, 200, 0, 0, 64, 64, DataBuffer.TYPE_SHORT, 3, false);
899: // src = OpImageTester.createRandomOpImage(layout);
900: // dst = new ScaleBilinearOpImage(src, null, null, null,
901: // 2.0F, 2.0F, 0.0F, 0.0F, interp);
902: // OpImageTester.testOpImage(dst, rect);
903: // OpImageTester.timeOpImage(dst, 10);
904:
905: // System.out.println("2. PixelInterleaved ushort 3-band");
906: // layout = OpImageTester.createImageLayout(
907: // 0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_USHORT, 3, false);
908: // src = OpImageTester.createRandomOpImage(layout);
909: // dst = new ScaleBilinearOpImage(src, null, null, null,
910: // 2.0F, 2.0F, 0.0F, 0.0F, interp);
911: // OpImageTester.testOpImage(dst, rect);
912: // OpImageTester.timeOpImage(dst, 10);
913:
914: // System.out.println("3. PixelInterleaved float 3-band");
915: // layout = OpImageTester.createImageLayout(0, 0, 512, 512, 0, 0, 200, 200,
916: // DataBuffer.TYPE_FLOAT, 3,
917: // false);
918: // src = OpImageTester.createRandomOpImage(layout);
919: // dst = new ScaleBilinearOpImage(src, null, null, null,
920: // 2.0F, 2.0F, 0.0F, 0.0F, interp);
921: // OpImageTester.testOpImage(dst, rect);
922: // OpImageTester.timeOpImage(dst, 10);
923:
924: // System.out.println("4. PixelInterleaved double 3-band");
925: // layout = OpImageTester.createImageLayout(0, 0, 512, 512,
926: // 0, 0, 200, 200,
927: // DataBuffer.TYPE_DOUBLE, 3,
928: // false);
929: // src = OpImageTester.createRandomOpImage(layout);
930: // dst = new ScaleBilinearOpImage(src, null, null, null,
931: // 2.0F, 2.0F, 0.0F, 0.0F, interp);
932: // OpImageTester.testOpImage(dst, rect);
933: // OpImageTester.timeOpImage(dst, 10);
934: // }
935: }
|