001: /*
002: * $RCSfile: MlibMosaicOpImage.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:00 $
010: * $State: Exp $
011: */package com.sun.media.jai.mlib;
012:
013: import java.awt.Rectangle;
014: import java.awt.image.DataBuffer;
015: import java.awt.image.Raster;
016: import java.awt.image.RenderedImage;
017: import java.awt.image.WritableRaster;
018: import java.util.ArrayList;
019: import java.util.Arrays;
020: import java.util.Map;
021: import java.util.Vector;
022: import javax.media.jai.ImageLayout;
023: import javax.media.jai.PlanarImage;
024: import javax.media.jai.ROI;
025: import javax.media.jai.operator.MosaicDescriptor;
026: import javax.media.jai.operator.MosaicType;
027: import com.sun.media.jai.opimage.MosaicOpImage;
028: import com.sun.medialib.mlib.Image;
029: import com.sun.medialib.mlib.mediaLibImage;
030:
031: final class MlibMosaicOpImage extends MosaicOpImage {
032: /** The Integral lower bound for Thresh1. */
033: private int[] glow;
034:
035: /** The Integral upper bound for Thresh1. */
036: private int[] ghigh;
037:
038: /** The shift value for MulShift and DivShift. */
039: private int shift;
040:
041: public MlibMosaicOpImage(Vector sources, ImageLayout layout,
042: Map config, MosaicType mosaicType,
043: PlanarImage[] sourceAlpha, ROI[] sourceROI,
044: double[][] sourceThreshold, double[] backgroundValues) {
045: super (sources, layout, config, mosaicType, sourceAlpha,
046: sourceROI, sourceThreshold, backgroundValues);
047:
048: int numSources = sources.size();
049:
050: int dataType = sampleModel.getDataType();
051: if (dataType == DataBuffer.TYPE_FLOAT
052: || dataType == DataBuffer.TYPE_DOUBLE) {
053: throw new UnsupportedOperationException(JaiI18N
054: .getString("MlibMosaicOpImage0"));
055: } else {
056: // Decrement integral source thresholds to account for Thresh1
057: // which uses ">" instead of ">=" as in the "mosaic" spec.
058: for (int i = 0; i < numSources; i++) {
059: for (int j = 0; j < numBands; j++) {
060: this .threshold[i][j]--;
061: }
062: }
063:
064: // Set extrema and shift based on data type.
065: int minValue = -Integer.MAX_VALUE;
066: int maxValue = Integer.MAX_VALUE;
067: switch (dataType) {
068: case DataBuffer.TYPE_BYTE:
069: minValue = 0;
070: maxValue = 0xFF;
071: shift = 8;
072: break;
073: case DataBuffer.TYPE_USHORT:
074: minValue = 0;
075: maxValue = 0xFFFF;
076: shift = 16;
077: break;
078: case DataBuffer.TYPE_SHORT:
079: minValue = Short.MIN_VALUE;
080: maxValue = Short.MAX_VALUE;
081: shift = 16;
082: break;
083: case DataBuffer.TYPE_INT:
084: minValue = Integer.MIN_VALUE;
085: maxValue = Integer.MAX_VALUE;
086: shift = 32;
087: break;
088: default:
089: }
090:
091: // Initialize upper and lower integral bounds for Thresh1.
092: this .glow = new int[numBands];
093: Arrays.fill(this .glow, minValue);
094: this .ghigh = new int[numBands];
095: Arrays.fill(this .ghigh, maxValue);
096: }
097: }
098:
099: protected void computeRect(Raster[] sources, WritableRaster dest,
100: Rectangle destRect, Raster[] alphaRaster, Raster[] roiRaster) {
101:
102: // Save the total number of sources.
103: int numSources = sources.length;
104:
105: // Put all non-null sources in a list.
106: ArrayList sourceList = new ArrayList(numSources);
107: for (int i = 0; i < numSources; i++) {
108: if (sources[i] != null) {
109: sourceList.add(sources[i]);
110: }
111: }
112:
113: // Convert the non-null sources to an array.
114: int numNonNullSources = sourceList.size();
115: Raster[] nonNullSources = null;
116: if (numNonNullSources != 0) {
117: nonNullSources = new Raster[numNonNullSources];
118: sourceList.toArray((Raster[]) nonNullSources);
119: }
120:
121: // Get the format tag.
122: int formatTag = MediaLibAccessor.findCompatibleTag(
123: nonNullSources, dest);
124:
125: // Get dest accessor and image.
126: MediaLibAccessor dstAccessor = new MediaLibAccessor(dest,
127: destRect, formatTag);
128: mediaLibImage[] dst = dstAccessor.getMediaLibImages();
129:
130: // Re-order the background values as needed.
131: int[] mlibBackground = dstAccessor.getIntParameters(0,
132: background);
133:
134: if (numNonNullSources == 0) {
135: // Fill the destination with the background value.
136: Image.Clear(dst[0], mlibBackground);
137: return;
138: }
139:
140: // Get source accessor(s).
141: MediaLibAccessor[] srcAccessor = new MediaLibAccessor[numSources];
142: for (int i = 0; i < numSources; i++) {
143: if (sources[i] != null) {
144: srcAccessor[i] = new MediaLibAccessor(sources[i],
145: destRect, formatTag);
146: }
147: }
148:
149: // Get source image(s).
150: int[][] mlibThreshold = new int[numSources][];
151: mediaLibImage[][] src = new mediaLibImage[numSources][];
152: for (int i = 0; i < numSources; i++) {
153: if (srcAccessor[i] != null) {
154: src[i] = srcAccessor[i].getMediaLibImages();
155: mlibThreshold[i] = srcAccessor[i].getIntParameters(0,
156: threshold[i]);
157: }
158: }
159:
160: // Temporary images.
161: mediaLibImage tmpIm1 = null;
162: mediaLibImage tmpImN = null;
163: mediaLibImage[] tmpIm1Array = new mediaLibImage[] { tmpIm1 };
164: mediaLibImage[] tmpImNArray = new mediaLibImage[] { tmpImN };
165:
166: if (mosaicType == MosaicDescriptor.MOSAIC_TYPE_OVERLAY) {
167: // Fill the destination with the background value.
168: Image.Clear(dst[0], mlibBackground);
169:
170: for (int i = numSources - 1; i >= 0; i--) {
171: if (src[i] == null) {
172: continue;
173: }
174:
175: mediaLibImage weight = getWeightImage(
176: destRect,
177: formatTag,
178: dst[0],
179: src[i][0],
180: sourceAlpha != null && sourceAlpha[i] != null ? alphaRaster[i]
181: : null, sourceROI != null
182: && sourceROI[i] != null ? roiRaster[i]
183: : null, mlibThreshold[i], tmpIm1Array,
184: tmpImNArray);
185:
186: Image.Blend2(dst[0], src[i][0], weight);
187: }
188: } else if (mosaicType == MosaicDescriptor.MOSAIC_TYPE_BLEND) {
189: tmpIm1 = new mediaLibImage(dst[0].getType(), 1, dst[0]
190: .getWidth(), dst[0].getHeight());
191: tmpImN = new mediaLibImage(dst[0].getType(), dst[0]
192: .getChannels(), dst[0].getWidth(), dst[0]
193: .getHeight());
194:
195: mediaLibImage[] alphas = new mediaLibImage[numNonNullSources];
196: mediaLibImage[] srcs = new mediaLibImage[numNonNullSources];
197:
198: int sourceCount = 0;
199:
200: for (int i = 0; i < numSources; i++) {
201: if (src[i] == null) {
202: continue;
203: }
204:
205: srcs[sourceCount] = src[i][0];
206: alphas[sourceCount] = getWeightImage(
207: destRect,
208: formatTag,
209: dst[0],
210: src[i][0],
211: sourceAlpha != null && sourceAlpha[i] != null ? alphaRaster[i]
212: : null, sourceROI != null
213: && sourceROI[i] != null ? roiRaster[i]
214: : null, mlibThreshold[i], null, null);
215: sourceCount++;
216: }
217:
218: if (sourceCount != numNonNullSources) {
219: mediaLibImage[] srcsNew = new mediaLibImage[sourceCount];
220: System.arraycopy(srcs, 0, srcsNew, 0, sourceCount);
221: srcs = srcsNew;
222: mediaLibImage[] alphasNew = new mediaLibImage[sourceCount];
223: System.arraycopy(alphas, 0, alphasNew, 0, sourceCount);
224: alphas = alphasNew;
225: }
226:
227: Image.BlendMulti(dst[0], srcs, alphas, mlibBackground);
228: }
229:
230: if (dstAccessor.isDataCopy()) {
231: dstAccessor.clampDataArrays();
232: dstAccessor.copyDataToRaster();
233: }
234: }
235:
236: /**
237: * Compute the weight image.
238: */
239: private mediaLibImage getWeightImage(Rectangle destRect,
240: int formatTag, mediaLibImage dst, mediaLibImage src,
241: Raster alphaRaster, Raster roiRaster, int[] thresh,
242: mediaLibImage[] tmpIm1, mediaLibImage[] tmpImN) {
243: mediaLibImage weight = null;
244:
245: if (alphaRaster != null) {
246: MediaLibAccessor alphaAccessor = new MediaLibAccessor(
247: alphaRaster, destRect, formatTag);
248: mediaLibImage[] alphaML = alphaAccessor.getMediaLibImages();
249:
250: if (isAlphaBitmask) {
251: if (tmpIm1 == null) {
252: tmpIm1 = new mediaLibImage[] { null };
253: }
254: if (tmpIm1[0] == null) {
255: tmpIm1[0] = new mediaLibImage(src.getType(), 1, src
256: .getWidth(), src.getHeight());
257: }
258:
259: Image.Thresh1(tmpIm1[0], alphaML[0], new int[] { 0 },
260: new int[] { ghigh[0] }, new int[] { glow[0] });
261: weight = tmpIm1[0];
262: } else {
263: weight = alphaML[0];
264: }
265: } else if (roiRaster != null) {
266: int roiFmtTag = MediaLibAccessor.findCompatibleTag(null,
267: roiRaster);
268:
269: MediaLibAccessor roiAccessor = new MediaLibAccessor(
270: roiRaster, destRect, roiFmtTag, true);
271: mediaLibImage[] roi = roiAccessor.getMediaLibImages();
272:
273: if (tmpIm1 == null) {
274: tmpIm1 = new mediaLibImage[] { null };
275: }
276: if (tmpIm1[0] == null) {
277: tmpIm1[0] = new mediaLibImage(src.getType(), 1, src
278: .getWidth(), src.getHeight());
279: }
280:
281: if (tmpIm1[0].getType() != roi[0].getType()) {
282: if (tmpIm1[0] == null) {
283: tmpIm1[0] = new mediaLibImage(src.getType(), 1, src
284: .getWidth(), src.getHeight());
285: }
286: Image.DataTypeConvert(tmpIm1[0], roi[0]);
287: } else {
288: // This is safe because the ROI image is bilevel
289: // so the accessor must have copied the data.
290: tmpIm1[0] = roi[0];
291: }
292:
293: Image.Thresh1(tmpIm1[0], new int[] { 0 },
294: new int[] { ghigh[0] }, new int[] { glow[0] });
295:
296: weight = tmpIm1[0];
297: } else {
298: if (tmpImN == null) {
299: tmpImN = new mediaLibImage[] { null };
300: }
301: if (tmpImN[0] == null) {
302: tmpImN[0] = dst.createCompatibleImage();
303: }
304: weight = tmpImN[0];
305: Image.Thresh1(weight, src, thresh, ghigh, glow);
306: }
307:
308: return weight;
309: }
310: }
|