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