1 /*
2  * $RCSfile: MlibMosaicOpImage.java,v $
3  *
4  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
5  *
6  * Use is subject to license terms.
7  *
8  * $Revision: 1.1 $
9  * $Date: 2005/02/11 04:56:00 $
10  * $State: Exp $
11  */package com.lightcrafts.media.jai.mlib;
12 
13 import java.awt.Rectangle;
14 import java.awt.image.DataBuffer;
15 import java.awt.image.Raster;
16 import java.awt.image.WritableRaster;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Map;
20 import java.util.Vector;
21 import com.lightcrafts.mediax.jai.ImageLayout;
22 import com.lightcrafts.mediax.jai.PlanarImage;
23 import com.lightcrafts.mediax.jai.ROI;
24 import com.lightcrafts.mediax.jai.operator.MosaicDescriptor;
25 import com.lightcrafts.mediax.jai.operator.MosaicType;
26 import com.lightcrafts.media.jai.opimage.MosaicOpImage;
27 import com.sun.medialib.mlib.Image;
28 import com.sun.medialib.mlib.mediaLibImage;
29 
30 final class MlibMosaicOpImage extends MosaicOpImage {
31     /** The Integral lower bound for Thresh1. */
32     private int[] glow;
33 
34     /** The Integral upper bound for Thresh1. */
35     private int[] ghigh;
36 
37     /** The shift value for MulShift and DivShift. */
38     private int shift;
39 
MlibMosaicOpImage(Vector sources, ImageLayout layout, Map config, MosaicType mosaicType, PlanarImage[] sourceAlpha, ROI[] sourceROI, double[][] sourceThreshold, double[] backgroundValues)40     public MlibMosaicOpImage(Vector sources,
41                              ImageLayout layout,
42                              Map config,
43                              MosaicType mosaicType,
44                              PlanarImage[] sourceAlpha,
45                              ROI[] sourceROI,
46                              double[][] sourceThreshold,
47                              double[] backgroundValues) {
48         super(sources, layout, config,
49               mosaicType, sourceAlpha, sourceROI,
50               sourceThreshold, backgroundValues);
51 
52         int numSources = sources.size();
53 
54         int dataType = sampleModel.getDataType();
55         if(dataType == DataBuffer.TYPE_FLOAT ||
56            dataType == DataBuffer.TYPE_DOUBLE) {
57             throw new UnsupportedOperationException(JaiI18N.getString("MlibMosaicOpImage0"));
58         } else {
59             // Decrement integral source thresholds to account for Thresh1
60             // which uses ">" instead of ">=" as in the "mosaic" spec.
61             for(int i = 0; i < numSources; i++) {
62                 for(int j = 0; j < numBands; j++) {
63                     this.threshold[i][j]--;
64                 }
65             }
66 
67             // Set extrema and shift based on data type.
68             int minValue = -Integer.MAX_VALUE;
69             int maxValue = Integer.MAX_VALUE;
70             switch (dataType) {
71             case DataBuffer.TYPE_BYTE:
72                 minValue = 0;
73                 maxValue = 0xFF;
74                 shift = 8;
75                 break;
76             case DataBuffer.TYPE_USHORT:
77                 minValue = 0;
78                 maxValue = 0xFFFF;
79                 shift = 16;
80                 break;
81             case DataBuffer.TYPE_SHORT:
82                 minValue = Short.MIN_VALUE;
83                 maxValue = Short.MAX_VALUE;
84                 shift = 16;
85                 break;
86             case DataBuffer.TYPE_INT:
87                 minValue = Integer.MIN_VALUE;
88                 maxValue = Integer.MAX_VALUE;
89                 shift = 32;
90                 break;
91             default:
92             }
93 
94             // Initialize upper and lower integral bounds for Thresh1.
95             this.glow = new int[numBands];
96             Arrays.fill(this.glow, minValue);
97             this.ghigh = new int[numBands];
98             Arrays.fill(this.ghigh, maxValue);
99         }
100     }
101 
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect, Raster[] alphaRaster, Raster[] roiRaster)102     protected void computeRect(Raster[] sources,
103                                WritableRaster dest,
104                                Rectangle destRect,
105                                Raster[] alphaRaster,
106                                Raster[] roiRaster) {
107 
108         // Save the total number of sources.
109         int numSources = sources.length;
110 
111         // Put all non-null sources in a list.
112         ArrayList sourceList = new ArrayList(numSources);
113         for(int i = 0; i < numSources; i++) {
114             if(sources[i] != null) {
115                 sourceList.add(sources[i]);
116             }
117         }
118 
119         // Convert the non-null sources to an array.
120         int numNonNullSources = sourceList.size();
121         Raster[] nonNullSources = null;
122         if(numNonNullSources != 0) {
123             nonNullSources = new Raster[numNonNullSources];
124             sourceList.toArray((Raster[])nonNullSources);
125         }
126 
127         // Get the format tag.
128         int formatTag =
129             MediaLibAccessor.findCompatibleTag(nonNullSources, dest);
130 
131         // Get dest accessor and image.
132         MediaLibAccessor dstAccessor =
133             new MediaLibAccessor(dest, destRect, formatTag);
134         mediaLibImage[] dst  = dstAccessor.getMediaLibImages();
135 
136         // Re-order the background values as needed.
137         int[] mlibBackground = dstAccessor.getIntParameters(0, background);
138 
139         if(numNonNullSources == 0) {
140             // Fill the destination with the background value.
141             Image.Clear(dst[0], mlibBackground);
142             return;
143         }
144 
145         // Get source accessor(s).
146         MediaLibAccessor[] srcAccessor = new MediaLibAccessor[numSources];
147         for(int i = 0; i < numSources; i++) {
148             if(sources[i] != null) {
149                 srcAccessor[i] =
150                     new MediaLibAccessor(sources[i], destRect, formatTag);
151             }
152         }
153 
154         // Get source image(s).
155         int[][] mlibThreshold = new int[numSources][];
156         mediaLibImage[][] src = new mediaLibImage[numSources][];
157         for(int i = 0; i < numSources; i++) {
158             if(srcAccessor[i] != null) {
159                 src[i] = srcAccessor[i].getMediaLibImages();
160                 mlibThreshold[i] =
161                     srcAccessor[i].getIntParameters(0, threshold[i]);
162             }
163         }
164 
165         // Temporary images.
166         mediaLibImage tmpIm1 = null;
167         mediaLibImage tmpImN = null;
168         mediaLibImage[] tmpIm1Array = new mediaLibImage[] {tmpIm1};
169         mediaLibImage[] tmpImNArray = new mediaLibImage[] {tmpImN};
170 
171         if(mosaicType == MosaicDescriptor.MOSAIC_TYPE_OVERLAY) {
172             // Fill the destination with the background value.
173             Image.Clear(dst[0], mlibBackground);
174 
175             for(int i = numSources - 1; i >= 0; i--) {
176                 if(src[i] == null) {
177                     continue;
178                 }
179 
180                 mediaLibImage weight =
181                     getWeightImage(destRect, formatTag,
182                                    dst[0], src[i][0],
183                                    sourceAlpha != null &&
184                                    sourceAlpha[i] != null ?
185                                    alphaRaster[i] : null,
186                                    sourceROI != null &&
187                                    sourceROI[i] != null ?
188                                    roiRaster[i] : null,
189                                    mlibThreshold[i],
190                                    tmpIm1Array,
191                                    tmpImNArray);
192 
193                 Image.Blend2(dst[0], src[i][0], weight);
194             }
195         } else if(mosaicType == MosaicDescriptor.MOSAIC_TYPE_BLEND) {
196             tmpIm1 = new mediaLibImage(dst[0].getType(),
197                                        1,
198                                        dst[0].getWidth(),
199                                        dst[0].getHeight());
200             tmpImN = new mediaLibImage(dst[0].getType(),
201                                        dst[0].getChannels(),
202                                        dst[0].getWidth(),
203                                        dst[0].getHeight());
204 
205             mediaLibImage[] alphas = new mediaLibImage[numNonNullSources];
206             mediaLibImage[] srcs = new mediaLibImage[numNonNullSources];
207 
208             int sourceCount = 0;
209 
210             for(int i = 0; i < numSources; i++) {
211                 if(src[i] == null) {
212                     continue;
213                 }
214 
215                 srcs[sourceCount] = src[i][0];
216                 alphas[sourceCount] =
217                     getWeightImage(destRect, formatTag,
218                                    dst[0], src[i][0],
219                                    sourceAlpha != null &&
220                                    sourceAlpha[i] != null ?
221                                    alphaRaster[i] : null,
222                                    sourceROI != null &&
223                                    sourceROI[i] != null ?
224                                    roiRaster[i] : null,
225                                    mlibThreshold[i],
226                                    null,
227                                    null);
228                 sourceCount++;
229             }
230 
231             if(sourceCount != numNonNullSources) {
232                 mediaLibImage[] srcsNew = new mediaLibImage[sourceCount];
233                 System.arraycopy(srcs, 0, srcsNew, 0, sourceCount);
234                 srcs = srcsNew;
235                 mediaLibImage[] alphasNew = new mediaLibImage[sourceCount];
236                 System.arraycopy(alphas, 0, alphasNew, 0, sourceCount);
237                 alphas = alphasNew;
238             }
239 
240             Image.BlendMulti(dst[0], srcs, alphas, mlibBackground);
241         }
242 
243         if (dstAccessor.isDataCopy()) {
244             dstAccessor.clampDataArrays();
245             dstAccessor.copyDataToRaster();
246         }
247     }
248 
249     /**
250      * Compute the weight image.
251      */
getWeightImage(Rectangle destRect, int formatTag, mediaLibImage dst, mediaLibImage src, Raster alphaRaster, Raster roiRaster, int[] thresh, mediaLibImage[] tmpIm1, mediaLibImage[] tmpImN)252     private mediaLibImage getWeightImage(Rectangle destRect,
253                                          int formatTag,
254                                          mediaLibImage dst,
255                                          mediaLibImage src,
256                                          Raster alphaRaster,
257                                          Raster roiRaster,
258                                          int[] thresh,
259                                          mediaLibImage[] tmpIm1,
260                                          mediaLibImage[] tmpImN) {
261         mediaLibImage weight = null;
262 
263         if(alphaRaster != null) {
264             MediaLibAccessor alphaAccessor =
265                 new MediaLibAccessor(alphaRaster, destRect,
266                                      formatTag);
267             mediaLibImage[] alphaML = alphaAccessor.getMediaLibImages();
268 
269             if(isAlphaBitmask) {
270                 if(tmpIm1 == null) {
271                     tmpIm1 = new mediaLibImage[] {null};
272                 }
273                 if(tmpIm1[0] == null) {
274                     tmpIm1[0] = new mediaLibImage(src.getType(),
275                                                   1,
276                                                   src.getWidth(),
277                                                   src.getHeight());
278                 }
279 
280                 Image.Thresh1(tmpIm1[0], alphaML[0], new int[] {0},
281                               new int[] {ghigh[0]}, new int[] {glow[0]});
282                 weight = tmpIm1[0];
283             } else {
284                 weight = alphaML[0];
285             }
286         } else if(roiRaster != null) {
287             int roiFmtTag =
288                 MediaLibAccessor.findCompatibleTag(null, roiRaster);
289 
290             MediaLibAccessor roiAccessor =
291                 new MediaLibAccessor(roiRaster, destRect,
292                                      roiFmtTag, true);
293             mediaLibImage[] roi = roiAccessor.getMediaLibImages();
294 
295             if(tmpIm1 == null) {
296                 tmpIm1 = new mediaLibImage[] {null};
297             }
298             if(tmpIm1[0] == null) {
299                 tmpIm1[0] = new mediaLibImage(src.getType(),
300                                               1,
301                                               src.getWidth(),
302                                               src.getHeight());
303             }
304 
305             if(tmpIm1[0].getType() != roi[0].getType()) {
306                 if(tmpIm1[0] == null) {
307                     tmpIm1[0] = new mediaLibImage(src.getType(),
308                                                   1,
309                                                   src.getWidth(),
310                                                   src.getHeight());
311                 }
312                 Image.DataTypeConvert(tmpIm1[0], roi[0]);
313             } else {
314                 // This is safe because the ROI image is bilevel
315                 // so the accessor must have copied the data.
316                 tmpIm1[0] = roi[0];
317             }
318 
319             Image.Thresh1(tmpIm1[0], new int[] {0},
320                           new int[] {ghigh[0]}, new int[] {glow[0]});
321 
322             weight = tmpIm1[0];
323         } else {
324             if(tmpImN == null) {
325                 tmpImN = new mediaLibImage[] {null};
326             }
327             if(tmpImN[0] == null) {
328                 tmpImN[0] = dst.createCompatibleImage();
329             }
330             weight = tmpImN[0];
331             Image.Thresh1(weight, src, thresh, ghigh, glow);
332         }
333 
334         return weight;
335     }
336 }
337