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