001: /*
002: * $RCSfile: ScaleBilinearBinaryOpImage.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.DataBufferByte;
017: import java.awt.image.DataBufferInt;
018: import java.awt.image.DataBufferUShort;
019: import java.awt.image.IndexColorModel;
020: import java.awt.image.MultiPixelPackedSampleModel;
021: import java.awt.image.Raster;
022: import java.awt.image.RenderedImage;
023: import java.awt.image.WritableRaster;
024: import java.awt.image.renderable.ParameterBlock;
025: import javax.media.jai.Interpolation;
026: import javax.media.jai.InterpolationNearest;
027: import javax.media.jai.ImageLayout;
028: import javax.media.jai.OpImage;
029: import javax.media.jai.PlanarImage;
030: import javax.media.jai.RasterAccessor;
031: import javax.media.jai.RasterFormatTag;
032: import javax.media.jai.ScaleOpImage;
033: import javax.media.jai.TileCache;
034: import javax.media.jai.BorderExtender;
035: import com.sun.media.jai.util.Rational;
036: import java.util.Map;
037:
038: /**
039: * An OpImage subclass that performs bilinear scaling
040: * for binary images with a MultiPixelPackedSampleModel
041: * and byte, short, or int DataBuffers.
042: *
043: */
044:
045: final public class ScaleBilinearBinaryOpImage extends ScaleOpImage {
046:
047: /* The number of SubsampleBits */
048: private int subsampleBits;
049:
050: /* Subsampling related variables */
051: int one, shift2, round2;
052:
053: long invScaleXInt, invScaleXFrac;
054: long invScaleYInt, invScaleYFrac;
055:
056: /**
057: * Constructs a ScaleBilinearBinaryOpImage from a RenderedImage source,
058: *
059: * @param source a RenderedImage.
060: * @param layout an ImageLayout optionally containing the tile grid layout,
061: * SampleModel, and ColorModel, or null.
062: * @param xScale scale factor along x axis.
063: * @param yScale scale factor along y axis.
064: * @param xTrans translation factor along x axis.
065: * @param yTrans translation factor along y axis.
066: * @param interp an Interpolation object to use for resampling.
067: */
068:
069: public ScaleBilinearBinaryOpImage(RenderedImage source,
070: BorderExtender extender, Map config, ImageLayout layout,
071: float xScale, float yScale, float xTrans, float yTrans,
072: Interpolation interp) {
073: super (source, layout, config, true, extender, interp, xScale,
074: yScale, xTrans, yTrans);
075:
076: subsampleBits = interp.getSubsampleBitsH();
077:
078: // Numnber of subsampling positions
079: one = 1 << subsampleBits;
080:
081: //Subsampling related variables
082: shift2 = 2 * subsampleBits;
083: round2 = 1 << (shift2 - 1);
084:
085: // Propagate source's ColorModel
086: if (layout != null) {
087: colorModel = layout.getColorModel(source);
088: } else {
089: colorModel = source.getColorModel();
090: }
091:
092: sampleModel = source.getSampleModel()
093: .createCompatibleSampleModel(tileWidth, tileHeight);
094:
095: if (invScaleXRational.num > invScaleXRational.denom) {
096: invScaleXInt = invScaleXRational.num
097: / invScaleXRational.denom;
098: invScaleXFrac = invScaleXRational.num
099: % invScaleXRational.denom;
100: } else {
101: invScaleXInt = 0;
102: invScaleXFrac = invScaleXRational.num;
103: }
104:
105: if (invScaleYRational.num > invScaleYRational.denom) {
106: invScaleYInt = invScaleYRational.num
107: / invScaleYRational.denom;
108: invScaleYFrac = invScaleYRational.num
109: % invScaleYRational.denom;
110: } else {
111: invScaleYInt = 0;
112: invScaleYFrac = invScaleYRational.num;
113: }
114: }
115:
116: /**
117: * Performs a scale operation on a specified rectangle. The sources are
118: * cobbled.
119: *
120: * @param sources an array of source Rasters, guaranteed to provide all
121: * necessary source data for computing the output.
122: * @param dest a WritableRaster containing the area to be computed.
123: * @param destRect the rectangle within dest to be processed.
124: */
125:
126: protected void computeRect(Raster[] sources, WritableRaster dest,
127: Rectangle destRect) {
128: Raster source = sources[0];
129:
130: // Get the source rectangle
131: Rectangle srcRect = source.getBounds();
132:
133: int srcRectX = srcRect.x;
134: int srcRectY = srcRect.y;
135:
136: // Destination rectangle dimensions.
137: int dx = destRect.x;
138: int dy = destRect.y;
139:
140: int dwidth = destRect.width;
141: int dheight = destRect.height;
142:
143: // Precalculate the x positions and store them in an array.
144: int[] xvalues = new int[dwidth];
145: int[] yvalues = new int[dheight];
146:
147: int[] xfracvalues = new int[dwidth];
148: int[] yfracvalues = new int[dheight];
149:
150: long sxNum = dx, sxDenom = 1;
151: long syNum = dy, syDenom = 1;
152:
153: // Subtract the X translation factor sx -= transX
154: sxNum = sxNum * transXRationalDenom - transXRationalNum
155: * sxDenom;
156: sxDenom *= transXRationalDenom;
157:
158: syNum = syNum * transYRationalDenom - transYRationalNum
159: * syDenom;
160: syDenom *= transYRationalDenom;
161:
162: // Add 0.5
163: sxNum = 2 * sxNum + sxDenom;
164: sxDenom *= 2;
165:
166: syNum = 2 * syNum + syDenom;
167: syDenom *= 2;
168:
169: // Multply by invScaleX & Y
170:
171: sxNum *= invScaleXRationalNum;
172: sxDenom *= invScaleXRationalDenom;
173:
174: syNum *= invScaleYRationalNum;
175: syDenom *= invScaleYRationalDenom;
176:
177: // Subtract 0.5
178: // jxz
179: sxNum = 2 * sxNum - sxDenom;
180: sxDenom *= 2;
181:
182: syNum = 2 * syNum - syDenom;
183: syDenom *= 2;
184:
185: // Separate the x source coordinate into integer and fractional part
186:
187: int srcXInt = Rational.floor(sxNum, sxDenom);
188: long srcXFrac = sxNum % sxDenom;
189: if (srcXInt < 0) {
190: srcXFrac = sxDenom + srcXFrac;
191: }
192:
193: int srcYInt = Rational.floor(syNum, syDenom);
194: long srcYFrac = syNum % syDenom;
195: if (srcYInt < 0) {
196: srcYFrac = syDenom + srcYFrac;
197: }
198:
199: // Normalize - Get a common denominator for the fracs of
200: // src and invScaleX
201: long commonXDenom = sxDenom * invScaleXRationalDenom;
202: srcXFrac *= invScaleXRationalDenom;
203: long newInvScaleXFrac = invScaleXFrac * sxDenom;
204:
205: long commonYDenom = syDenom * invScaleYRationalDenom;
206: srcYFrac *= invScaleYRationalDenom;
207: long newInvScaleYFrac = invScaleYFrac * syDenom;
208:
209: for (int i = 0; i < dwidth; i++) {
210: // Calculate the position
211: // xfracvalues is the fractional part of x position in terms
212: // of the nuber of subpixel points
213:
214: xvalues[i] = srcXInt;
215:
216: // added by jxz; for the case frac is less then 1/2,
217: // the previous location is used
218: // e.g. 24.25 is between the two half points 23.5 and 24.5
219: // thus 23rd and 24th are the pixel rows
220: // XXX watch for side effects associated with sfracvalues
221:
222: //if(2 * srcXFrac < commonXDenom && xvalues[i] > 0){
223: //--xvalues[i];
224: //}
225:
226: xfracvalues[i] = (int) (((float) srcXFrac / (float) commonXDenom) * one);
227:
228: // Move onto the next source pixel.
229:
230: // Add the integral part of invScaleX to the integral part
231: // of srcX
232: srcXInt += invScaleXInt;
233:
234: // Add the fractional part of invScaleX to the fractional part
235: // of srcX
236: srcXFrac += newInvScaleXFrac;
237:
238: // If the fractional part is now greater than equal to the
239: // denominator, divide so as to reduce the numerator to be less
240: // than the denominator and add the overflow to the integral part.
241: if (srcXFrac >= commonXDenom) {
242: srcXInt += 1;
243: srcXFrac -= commonXDenom;
244: }
245: }
246:
247: // Precalculate the y positions and store them in an array.
248:
249: for (int i = 0; i < dheight; i++) {
250: // Calculate the position
251: yvalues[i] = srcYInt;
252: yfracvalues[i] = (int) (((float) srcYFrac / (float) commonYDenom) * one);
253:
254: // added by jxz; for the case frac is less then 1/2,
255: // the previous location is used
256: // e.g. 24.25 is between the two half points 23.5 and 24.5
257: // thus 23rd and 24th are the pixel rows
258: // XXX watch for side effects associated with yfracvalues
259:
260: // if(2 * srcYFrac < commonYDenom && yvalues[i] > 0){
261: // --yvalues[i];
262: // }
263:
264: // Move onto the next source pixel.
265:
266: // Add the integral part of invScaleY to the integral part
267: // of srcY
268: srcYInt += invScaleYInt;
269:
270: // Add the fractional part of invScaleY to the fractional part
271: // of srcY
272: srcYFrac += newInvScaleYFrac;
273:
274: // If the fractional part is now greater than equal to the
275: // denominator, divide so as to reduce the numerator to be less
276: // than the denominator and add the overflow to the integral part.
277: if (srcYFrac >= commonYDenom) {
278: srcYInt += 1;
279: srcYFrac -= commonYDenom;
280: }
281: }
282:
283: switch (source.getSampleModel().getDataType()) {
284: case DataBuffer.TYPE_BYTE:
285: byteLoop(source, dest, dx, dy, dwidth, dheight, xvalues,
286: yvalues, xfracvalues, yfracvalues);
287: break;
288:
289: case DataBuffer.TYPE_SHORT:
290: case DataBuffer.TYPE_USHORT:
291: shortLoop(source, dest, dx, dy, dwidth, dheight, xvalues,
292: yvalues, xfracvalues, yfracvalues);
293: break;
294:
295: case DataBuffer.TYPE_INT:
296: intLoop(source, dest, dx, dy, dwidth, dheight, xvalues,
297: yvalues, xfracvalues, yfracvalues);
298: break;
299:
300: default:
301: throw new RuntimeException(JaiI18N
302: .getString("OrderedDitherOpImage0"));
303: }
304: }
305:
306: private void byteLoop(Raster source, WritableRaster dest, int dx,
307: int dy, int dwidth, int dheight, int[] xvalues,
308: int[] yvalues, int[] xfracvalues, int[] yfracvalues) {
309: MultiPixelPackedSampleModel sourceSM = (MultiPixelPackedSampleModel) source
310: .getSampleModel();
311: DataBufferByte sourceDB = (DataBufferByte) source
312: .getDataBuffer();
313: int sourceTransX = source.getSampleModelTranslateX();
314: int sourceTransY = source.getSampleModelTranslateY();
315: int sourceDataBitOffset = sourceSM.getDataBitOffset();
316: int sourceScanlineStride = sourceSM.getScanlineStride();
317:
318: MultiPixelPackedSampleModel destSM = (MultiPixelPackedSampleModel) dest
319: .getSampleModel();
320: DataBufferByte destDB = (DataBufferByte) dest.getDataBuffer();
321: int destMinX = dest.getMinX();
322: int destMinY = dest.getMinY();
323: int destTransX = dest.getSampleModelTranslateX();
324: int destTransY = dest.getSampleModelTranslateY();
325: int destDataBitOffset = destSM.getDataBitOffset();
326: int destScanlineStride = destSM.getScanlineStride();
327:
328: byte[] sourceData = sourceDB.getData();
329: int sourceDBOffset = sourceDB.getOffset();
330:
331: byte[] destData = destDB.getData();
332: int destDBOffset = destDB.getOffset();
333:
334: int[] sbytenum = new int[dwidth];
335: int[] sshift = new int[dwidth];
336:
337: // Since the source data is MultiPixel packed
338: // precalculate the byte no and the and the shift
339: // after masking required to extract a single pixel
340: // sample from a byte
341:
342: for (int i = 0; i < dwidth; i++) {
343: int x = xvalues[i];
344: int sbitnum = sourceDataBitOffset + (x - sourceTransX);
345: sbytenum[i] = sbitnum >> 3;
346: sshift[i] = 7 - (sbitnum & 7);
347: }
348:
349: int sourceYOffset;
350:
351: int s00, s01, s10, s11, s0, s1, s;
352: int x = 0, y = 0;
353: int yfrac, xfrac;
354:
355: int xNextBitNo;
356: int xNextByteNo;
357: int xNextShiftNo;
358:
359: int destYOffset = (dy - destTransY) * destScanlineStride
360: + destDBOffset;
361: int dbitnum = destDataBitOffset + (dx - destTransX);
362:
363: int destByteNum;
364: int destBitShift;
365:
366: int i = 0, j = 0;
367:
368: // Loop through height of image
369: for (j = 0; j < dheight; j++) {
370:
371: y = yvalues[j];
372: yfrac = yfracvalues[j];
373:
374: sourceYOffset = (y - sourceTransY) * sourceScanlineStride
375: + sourceDBOffset;
376: dbitnum = destDataBitOffset + (dx - destTransX);
377:
378: // loop through one scan line
379: for (i = 0; i < dwidth; i++) {
380: xfrac = xfracvalues[i];
381: x = xvalues[i];
382: xNextBitNo = sourceDataBitOffset
383: + (x + 1 - sourceTransX);
384: xNextByteNo = xNextBitNo >> 3;
385: xNextShiftNo = 7 - (xNextBitNo & 7);
386:
387: /* Four surrounding pixels are needed for Bilinear interpolation.
388: * If the dest pixel to be calculated is at (dx, dy) then the
389: * actual source pixel (sx, sy) required is (dx/scaleX, dy/scaleY).
390: * The four pixels that surround it are at the positions:
391: * s00 = src(sxlow, sylow)
392: * s01 = src(sxhigh, sylow)
393: * s10 = src(sxlow, syhigh)
394: * s11 = src(sxhigh, syhigh)
395: * where sxlow = Math.floor(sx), sxhigh = Math.ceil(sx)
396: * and sylow = Math.floor(sy), syhigh = Math.ceil(sy)
397: *
398: * The value of the destination pixel can now be calculated as:
399: * s0 = (s01 - s00)*xfrac + s00;
400: * s1 = (s11 - s10)*xfrac + s10;
401: * dst(x,y) = (s1 - s0)*yfrac + s0;
402: */
403:
404: //Obtain sample values for 4 adjacent pixels in the source
405: s00 = (sourceData[sourceYOffset + sbytenum[i]] >> sshift[i]) & 0x01;
406: s01 = (sourceData[sourceYOffset + xNextByteNo] >> xNextShiftNo) & 0x01;
407: s10 = (sourceData[sourceYOffset + sourceScanlineStride
408: + sbytenum[i]] >> sshift[i]) & 0x01;
409: s11 = (sourceData[sourceYOffset + sourceScanlineStride
410: + xNextByteNo] >> xNextShiftNo) & 0x01;
411:
412: // perform the bilinear interpolation
413: s0 = (s01 - s00) * xfrac + (s00 << subsampleBits);
414: s1 = (s11 - s10) * xfrac + (s10 << subsampleBits);
415:
416: // The bilinear intrerpolated value
417: s = ((s1 - s0) * yfrac + ((s0 << subsampleBits) + round2)) >> shift2;
418:
419: destByteNum = dbitnum >> 3;
420: destBitShift = 7 - (dbitnum & 7);
421:
422: if (s == 1) {
423: //the destBit must be set
424: destData[destYOffset + destByteNum] |= (0x01 << destBitShift);
425: } else {
426: //the destBit must be cleared
427: destData[destYOffset + destByteNum] &= (0xff - (0x01 << destBitShift));
428: }
429: dbitnum++;
430: }
431: destYOffset += destScanlineStride;
432: }
433: }
434:
435: private void shortLoop(Raster source, WritableRaster dest, int dx,
436: int dy, int dwidth, int dheight, int[] xvalues,
437: int[] yvalues, int[] xfracvalues, int[] yfracvalues) {
438: MultiPixelPackedSampleModel sourceSM = (MultiPixelPackedSampleModel) source
439: .getSampleModel();
440: int sourceTransX = source.getSampleModelTranslateX();
441: int sourceTransY = source.getSampleModelTranslateY();
442: int sourceDataBitOffset = sourceSM.getDataBitOffset();
443: int sourceScanlineStride = sourceSM.getScanlineStride();
444:
445: MultiPixelPackedSampleModel destSM = (MultiPixelPackedSampleModel) dest
446: .getSampleModel();
447: int destMinX = dest.getMinX();
448: int destMinY = dest.getMinY();
449: int destTransX = dest.getSampleModelTranslateX();
450: int destTransY = dest.getSampleModelTranslateY();
451: int destDataBitOffset = destSM.getDataBitOffset();
452: int destScanlineStride = destSM.getScanlineStride();
453:
454: DataBufferUShort sourceDB = (DataBufferUShort) source
455: .getDataBuffer();
456: short[] sourceData = sourceDB.getData();
457: int sourceDBOffset = sourceDB.getOffset();
458:
459: DataBufferUShort destDB = (DataBufferUShort) dest
460: .getDataBuffer();
461: short[] destData = destDB.getData();
462: int destDBOffset = destDB.getOffset();
463:
464: int[] sshortnum = new int[dwidth];
465: int[] sshift = new int[dwidth];
466:
467: for (int i = 0; i < dwidth; i++) {
468: int x = xvalues[i];
469: int sbitnum = sourceDataBitOffset + (x - sourceTransX);
470: sshortnum[i] = sbitnum >> 4;
471: sshift[i] = 15 - (sbitnum & 15);
472: }
473:
474: int sourceYOffset;
475:
476: int s00, s01, s10, s11, s0, s1, s;
477:
478: int x, y;
479: int yfrac, xfrac;
480:
481: int xNextBitNo;
482: int xNextShortNo;
483: int xNextShiftNo;
484:
485: int destYOffset = (dy - destTransY) * destScanlineStride
486: + destDBOffset;
487: int dbitnum = destDataBitOffset + (dx - destTransX);
488:
489: int destShortNum;
490: int destBitShift;
491:
492: for (int j = 0; j < dheight; j++) {
493: y = yvalues[j];
494: yfrac = yfracvalues[j];
495:
496: sourceYOffset = (y - sourceTransY) * sourceScanlineStride
497: + sourceDBOffset;
498: dbitnum = destDataBitOffset + (dx - destTransX);
499:
500: for (int i = 0; i < dwidth; i++) {
501: xfrac = xfracvalues[i];
502: x = xvalues[i];
503: xNextBitNo = sourceDataBitOffset
504: + (x + 1 - sourceTransX);
505: xNextShortNo = xNextBitNo >> 4;
506: xNextShiftNo = 15 - (xNextBitNo & 15);
507:
508: s00 = (sourceData[sourceYOffset + sshortnum[i]] >> sshift[i]) & 0x01;
509: s01 = (sourceData[sourceYOffset + xNextShortNo] >> xNextShiftNo) & 0x01;
510: s10 = (sourceData[sourceYOffset + sourceScanlineStride
511: + sshortnum[i]] >> sshift[i]) & 0x01;
512: s11 = (sourceData[sourceYOffset + sourceScanlineStride
513: + xNextShortNo] >> xNextShiftNo) & 0x01;
514:
515: s0 = (s01 - s00) * xfrac + (s00 << subsampleBits);
516: s1 = (s11 - s10) * xfrac + (s10 << subsampleBits);
517: s = ((s1 - s0) * yfrac + (s0 << subsampleBits) + round2) >> shift2;
518:
519: destShortNum = dbitnum >> 4;
520: destBitShift = 15 - (dbitnum & 15);
521:
522: if (s == 1) {
523: destData[destYOffset + destShortNum] |= (0x01 << destBitShift);
524: } else {
525: destData[destYOffset + destShortNum] &= (0xffff - (0x01 << destBitShift));
526: }
527: dbitnum++;
528: }
529: destYOffset += destScanlineStride;
530: }
531: }
532:
533: private void intLoop(Raster source, WritableRaster dest, int dx,
534: int dy, int dwidth, int dheight, int[] xvalues,
535: int[] yvalues, int[] xfracvalues, int[] yfracvalues) {
536: MultiPixelPackedSampleModel sourceSM = (MultiPixelPackedSampleModel) source
537: .getSampleModel();
538: DataBufferInt sourceDB = (DataBufferInt) source.getDataBuffer();
539: int sourceTransX = source.getSampleModelTranslateX();
540: int sourceTransY = source.getSampleModelTranslateY();
541: int sourceDataBitOffset = sourceSM.getDataBitOffset();
542: int sourceScanlineStride = sourceSM.getScanlineStride();
543:
544: MultiPixelPackedSampleModel destSM = (MultiPixelPackedSampleModel) dest
545: .getSampleModel();
546: DataBufferInt destDB = (DataBufferInt) dest.getDataBuffer();
547: int destMinX = dest.getMinX();
548: int destMinY = dest.getMinY();
549: int destTransX = dest.getSampleModelTranslateX();
550: int destTransY = dest.getSampleModelTranslateY();
551: int destDataBitOffset = destSM.getDataBitOffset();
552: int destScanlineStride = destSM.getScanlineStride();
553:
554: int[] sourceData = sourceDB.getData();
555: int sourceDBOffset = sourceDB.getOffset();
556:
557: int[] destData = destDB.getData();
558: int destDBOffset = destDB.getOffset();
559:
560: int[] sintnum = new int[dwidth];
561: int[] sshift = new int[dwidth];
562:
563: for (int i = 0; i < dwidth; i++) {
564: int x = xvalues[i];
565: int sbitnum = sourceDataBitOffset + (x - sourceTransX);
566: sintnum[i] = sbitnum >> 5;
567: sshift[i] = 31 - (sbitnum & 31);
568: }
569:
570: int sourceYOffset;
571:
572: int s00, s01, s10, s11, s0, s1, s;
573: int x, y;
574: int yfrac, xfrac;
575:
576: int xNextBitNo;
577: int xNextIntNo;
578: int xNextShiftNo;
579:
580: int destYOffset = (dy - destTransY) * destScanlineStride
581: + destDBOffset;
582: int dbitnum = destDataBitOffset + (dx - destTransX);
583:
584: int destIntNum;
585: int destBitShift;
586:
587: for (int j = 0; j < dheight; j++) {
588: y = yvalues[j];
589: yfrac = yfracvalues[j];
590:
591: sourceYOffset = (y - sourceTransY) * sourceScanlineStride
592: + sourceDBOffset;
593: dbitnum = destDataBitOffset + (dx - destTransX);
594:
595: for (int i = 0; i < dwidth; i++) {
596: xfrac = xfracvalues[i];
597: x = xvalues[i];
598:
599: xNextBitNo = sourceDataBitOffset
600: + (x + 1 - sourceTransX);
601: xNextIntNo = xNextBitNo >> 5;
602: xNextShiftNo = 31 - (xNextBitNo & 31);
603:
604: s00 = (sourceData[sourceYOffset + sintnum[i]] >> sshift[i]) & 0x01;
605: s01 = (sourceData[sourceYOffset + xNextIntNo] >> xNextShiftNo) & 0x01;
606: s10 = (sourceData[sourceYOffset + sourceScanlineStride
607: + sintnum[i]] >> sshift[i]) & 0x01;
608: s11 = (sourceData[sourceYOffset + sourceScanlineStride
609: + xNextIntNo] >> xNextShiftNo) & 0x01;
610:
611: s0 = (s01 - s00) * xfrac + (s00 << subsampleBits);
612: s1 = (s11 - s10) * xfrac + (s10 << subsampleBits);
613: s = ((s1 - s0) * yfrac + (s0 << subsampleBits) + round2) >> shift2;
614:
615: destIntNum = dbitnum >> 5;
616: destBitShift = 31 - (dbitnum & 31);
617:
618: if (s == 1) {
619: //Is above the threshold, the destBit must be set
620: destData[destYOffset + destIntNum] |= (0x01 << destBitShift);
621: } else {
622: destData[destYOffset + destIntNum] &= (0xff - (0x01 << destBitShift));
623: }
624: dbitnum++;
625: }
626: destYOffset += destScanlineStride;
627: }
628:
629: }
630: }
|