1 /* 2 * $RCSfile: JDKWorkarounds.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:57:00 $ 10 * $State: Exp $ 11 */ 12 package com.lightcrafts.media.jai.util; 13 import java.awt.*; 14 import java.awt.image.*; 15 16 // Workaround Repository for JDK bugs. 17 18 public final class JDKWorkarounds { 19 JDKWorkarounds()20 private JDKWorkarounds() {} 21 22 /** 23 * Faster implementation of setRect for bilevel Rasters 24 * with a SinglePixelPackedSampleModel and DataBufferByte. 25 * Based on sun.awt.image.BytePackedRaster.setDataElements 26 * (JDK1.3 beta version), with improvements. 27 */ setRectBilevel(WritableRaster dstRaster, Raster srcRaster, int dx, int dy)28 private static boolean setRectBilevel(WritableRaster dstRaster, 29 Raster srcRaster, 30 int dx, int dy) { 31 int width = srcRaster.getWidth(); 32 int height = srcRaster.getHeight(); 33 int srcOffX = srcRaster.getMinX(); 34 int srcOffY = srcRaster.getMinY(); 35 int dstOffX = dx+srcOffX; 36 int dstOffY = dy+srcOffY; 37 38 int dminX = dstRaster.getMinX(); 39 int dminY = dstRaster.getMinY(); 40 int dwidth = dstRaster.getWidth(); 41 int dheight = dstRaster.getHeight(); 42 43 // Clip to dstRaster 44 if (dstOffX + width > dminX + dwidth) { 45 width = dminX + dwidth - dstOffX; 46 } 47 if (dstOffY + height > dminY + dheight) { 48 height = dminY + dheight - dstOffY; 49 } 50 51 // 52 // This implementation works but is not as efficient as the one 53 // below which is commented out. In terms of performance, cobbling 54 // a 1728x2376 bit image with 128x144 tiles took the following 55 // amount of time for four cases: 56 // 57 // WritableRaster.setRect() 19756 58 // Aligned optimal case 5645 59 // Unaligned optimal case 6644 60 // Case using ImageUtil 7500 61 // 62 // So this case gives intermediate speed performance closer to the 63 // optimal case than to the JDK. It will likely use more memory 64 // however. On the other hand this approach covers all data types. 65 // 66 Rectangle rect = new Rectangle(dstOffX, dstOffY, width, height); 67 byte[] binaryData = ImageUtil.getPackedBinaryData(srcRaster, rect); 68 ImageUtil.setPackedBinaryData(binaryData, dstRaster, rect); 69 70 /* XXX BEGIN: Commented out as it gives vertical lines in cobbling 71 data. This gives optimal performance for the case of byte-to-byte 72 data. For non-byte data the sub-optimal solution above (using 73 the ImageUtil packed routines) should be used. Note that this 74 commented out section includes a few bug fixes compared with the 75 original code in the previous SCCS version. bpb 6/21/2000 76 MultiPixelPackedSampleModel srcMPPSM = 77 (MultiPixelPackedSampleModel)srcRaster.getSampleModel(); 78 MultiPixelPackedSampleModel dstMPPSM = 79 (MultiPixelPackedSampleModel)dstRaster.getSampleModel(); 80 81 DataBufferByte srcDBB = (DataBufferByte)srcRaster.getDataBuffer(); 82 DataBufferByte dstDBB = (DataBufferByte)dstRaster.getDataBuffer(); 83 84 byte[] srcData = srcDBB.getData(); 85 byte[] dstData = dstDBB.getData(); 86 87 int srcTransX = srcRaster.getSampleModelTranslateX(); 88 int srcTransY = srcRaster.getSampleModelTranslateY(); 89 int srcDataBitOffset = srcMPPSM.getDataBitOffset(); 90 int srcScanlineStride = srcMPPSM.getScanlineStride(); 91 92 int srcYOffset = (srcOffY - srcTransY)*srcScanlineStride; 93 int srcXOffset = srcDataBitOffset + (srcOffX - srcTransX); 94 95 int dstTransX = dstRaster.getSampleModelTranslateX(); 96 int dstTransY = dstRaster.getSampleModelTranslateY(); 97 int dstDataBitOffset = dstMPPSM.getDataBitOffset(); 98 int dstScanlineStride = dstMPPSM.getScanlineStride(); 99 100 int dstYOffset = (dstOffY - dstTransY)*dstScanlineStride; 101 int dstXOffset = dstDataBitOffset + (dstOffX - dstTransX); 102 103 int inbit = srcYOffset*8 + srcXOffset; 104 int outbit = dstYOffset*8 + dstXOffset; 105 106 if ((inbit & 7) == (outbit & 7)) { 107 // Aligned case 108 int copybits = width; 109 int bits = inbit & 7; 110 if (bits != 0) { 111 // Copy partial bytes on left 112 int inbyte = inbit >> 3; 113 int outbyte = outbit >> 3; 114 int mask = 0xff >> bits; 115 bits = 8 - bits; 116 if (copybits < bits) { 117 mask &= (mask << (8 - copybits)); 118 bits = copybits; 119 } 120 for (int j = 0; j < height; j++) { 121 int element = dstData[outbyte]; 122 element &= ~mask; 123 element |= (srcData[inbyte] & mask); 124 dstData[outbyte] = (byte) element; 125 inbyte += srcScanlineStride; 126 outbyte += dstScanlineStride; 127 } 128 inbit += bits; 129 outbit += bits; 130 copybits -= bits; 131 } 132 if (copybits >= 8) { 133 // Copy whole bytes 134 int inbyte = inbit >> 3; 135 int outbyte = outbit >> 3; 136 int copybytes = copybits >> 3; 137 138 if (copybytes == srcScanlineStride && 139 srcScanlineStride == dstScanlineStride) { 140 System.arraycopy(srcData, inbyte, 141 dstData, outbyte, 142 srcScanlineStride*height); 143 } else { 144 for (int j = 0; j < height; j++) { 145 System.arraycopy(srcData, inbyte, 146 dstData, outbyte, 147 copybytes); 148 inbyte += srcScanlineStride; 149 outbyte += dstScanlineStride; 150 } 151 } 152 bits = copybytes * 8; 153 inbit += bits; 154 outbit += bits; 155 copybits -= bits; 156 } 157 if (copybits > 0) { 158 // Copy partial bytes on right 159 int inbyte = inbit >> 3; 160 int outbyte = outbit >> 3; 161 int mask = (0xff00 >> copybits) & 0xff; 162 for (int j = 0; j < height; j++) { 163 int element = dstData[outbyte]; 164 element &= ~mask; 165 element |= (srcData[inbyte] & mask); 166 dstData[outbyte] = (byte) element; 167 inbyte += srcScanlineStride; 168 outbyte += dstScanlineStride; 169 } 170 } 171 } else { 172 // Unaligned case 173 for (int j = 0; j < height; j++) { 174 int save_inbit = inbit; 175 int save_outbit = outbit; 176 int copybits = width; 177 178 int inbyte, outbyte; 179 int mask; 180 181 int bits = outbit & 7; 182 if (bits > 0) { 183 inbyte = inbit >> 8; 184 outbyte = outbit >> 8; 185 mask = 0xff >> bits; 186 187 if (copybits < bits) { 188 mask &= mask << (8 - copybits); 189 bits = copybits; 190 } 191 int element = dstData[outbyte]; 192 element &= ~mask; 193 element |= (srcData[inbyte] & mask); 194 dstData[outbyte] = (byte) element; 195 196 inbit += bits; 197 outbit += bits; 198 copybits -= bits; 199 } 200 201 if (copybits == 0) { 202 continue; 203 } 204 205 int shift0 = inbit & 7; 206 int shift1 = 7 - shift0; 207 int mask1 = 0xff >>> shift1; 208 209 inbyte = inbit >> 3; 210 outbyte = outbit >> 3; 211 212 int srcData0 = srcData[inbyte]; 213 int lastIndex = srcData.length - 1; 214 while (copybits >= 8 && inbyte < lastIndex) { 215 int srcData1 = srcData[inbyte + 1]; 216 int val = (srcData0 << shift0) | 217 ((srcData1 >>> shift1) & mask1); 218 srcData0 = srcData1; 219 dstData[outbyte] = (byte)val; 220 221 ++inbyte; 222 ++outbyte; 223 inbit += 8; 224 outbit += 8; 225 copybits -= 8; 226 } 227 228 if (copybits > 0) { 229 mask = (0xff00 >> copybits) & 0xff; 230 231 int element = dstData[outbyte]; 232 element &= ~mask; 233 element |= ((srcData[inbyte] << shift0) & mask); 234 dstData[outbyte] = (byte)(element & 0xFF); 235 } 236 237 inbit = save_inbit + 8*srcScanlineStride; 238 outbit = save_outbit + 8*dstScanlineStride; 239 } 240 } 241 XXX END */ 242 243 return true; 244 } 245 246 // Workarounds for WritableRaster.setRect bug (4250270) in JDK 1.2. 247 // Also filed as bug 4250273 against JAI. 248 setRect(WritableRaster dstRaster, Raster srcRaster)249 public static void setRect(WritableRaster dstRaster, Raster srcRaster) { 250 setRect(dstRaster, srcRaster, 0, 0); 251 } 252 setRect(WritableRaster dstRaster, Raster srcRaster, int dx, int dy)253 public static void setRect(WritableRaster dstRaster, Raster srcRaster, 254 int dx, int dy) { 255 // Special case for bilevel Rasters 256 SampleModel srcSampleModel = srcRaster.getSampleModel(); 257 SampleModel dstSampleModel = dstRaster.getSampleModel(); 258 if (srcSampleModel instanceof MultiPixelPackedSampleModel && 259 dstSampleModel instanceof MultiPixelPackedSampleModel) { 260 MultiPixelPackedSampleModel srcMPPSM = 261 (MultiPixelPackedSampleModel)srcSampleModel; 262 MultiPixelPackedSampleModel dstMPPSM = 263 (MultiPixelPackedSampleModel)dstSampleModel; 264 265 DataBuffer srcDB = srcRaster.getDataBuffer(); 266 DataBuffer dstDB = srcRaster.getDataBuffer(); 267 268 if (srcDB instanceof DataBufferByte && 269 dstDB instanceof DataBufferByte && 270 srcMPPSM.getPixelBitStride() == 1 && 271 dstMPPSM.getPixelBitStride() == 1) { 272 if (setRectBilevel(dstRaster, srcRaster, dx, dy)) { 273 return; 274 } 275 } 276 } 277 278 // Use the regular JDK routines for everything else except 279 // float and double images. 280 int dataType = dstRaster.getSampleModel().getDataType(); 281 if (dataType != DataBuffer.TYPE_FLOAT && 282 dataType != DataBuffer.TYPE_DOUBLE) { 283 dstRaster.setRect(dx, dy, srcRaster); 284 return; 285 } 286 287 int width = srcRaster.getWidth(); 288 int height = srcRaster.getHeight(); 289 int srcOffX = srcRaster.getMinX(); 290 int srcOffY = srcRaster.getMinY(); 291 int dstOffX = dx+srcOffX; 292 int dstOffY = dy+srcOffY; 293 294 int dminX = dstRaster.getMinX(); 295 int dminY = dstRaster.getMinY(); 296 int dwidth = dstRaster.getWidth(); 297 int dheight = dstRaster.getHeight(); 298 299 // Clip to dstRaster 300 if (dstOffX + width > dminX + dwidth) { 301 width = dminX + dwidth - dstOffX; 302 } 303 if (dstOffY + height > dminY + dheight) { 304 height = dminY + dheight - dstOffY; 305 } 306 307 switch (srcRaster.getSampleModel().getDataType()) { 308 case DataBuffer.TYPE_BYTE: 309 case DataBuffer.TYPE_SHORT: 310 case DataBuffer.TYPE_USHORT: 311 case DataBuffer.TYPE_INT: 312 int[] iData = null; 313 for (int startY=0; startY < height; startY++) { 314 // Grab one scanline at a time 315 iData = 316 srcRaster.getPixels(srcOffX, srcOffY+startY, width, 1, 317 iData); 318 dstRaster.setPixels(dstOffX, dstOffY+startY, width, 1, iData); 319 } 320 break; 321 322 case DataBuffer.TYPE_FLOAT: 323 float[] fData = null; 324 for (int startY=0; startY < height; startY++) { 325 fData = 326 srcRaster.getPixels(srcOffX, srcOffY+startY, width, 1, 327 fData); 328 dstRaster.setPixels(dstOffX, dstOffY+startY, width, 1, fData); 329 } 330 break; 331 332 case DataBuffer.TYPE_DOUBLE: 333 double[] dData = null; 334 for (int startY=0; startY < height; startY++) { 335 // Grab one scanline at a time 336 dData = 337 srcRaster.getPixels(srcOffX, srcOffY+startY, width, 1, 338 dData); 339 dstRaster.setPixels(dstOffX, dstOffY+startY, width, 1, dData); 340 } 341 break; 342 } 343 } 344 345 /** 346 * Workaround for JDK 1.3 bug 4326636 (bpb 30 March 2000). 347 * 348 * Check whether the given SampleModel and ColorModel are compatible. 349 * 350 * This is required because in JDK 1.3 the ComponentColorModel 351 * implementation of isCompatibleSampleModel() only checks whether 352 * the SampleModel is a ComponentSampleModel with the same transferType 353 * as the ColorModel. No check of the number of components or bit 354 * depth is effected. 355 * 356 * @throws IllegalArgumentException if either parameter is null. 357 */ areCompatibleDataModels(SampleModel sm, ColorModel cm)358 public static boolean areCompatibleDataModels(SampleModel sm, 359 ColorModel cm) { 360 if(sm == null || cm == null) { 361 throw new 362 IllegalArgumentException(JaiI18N.getString("JDKWorkarounds0")); 363 } 364 365 // Call the method we should be using instead of this workaround. 366 // This checks the compatibility of the transferType and possibly 367 // other quantities. 368 if(!cm.isCompatibleSampleModel(sm)) { 369 return false; 370 } 371 372 // This if-block adds the tests performed in 373 // ComponentColorModel.isCompatibleRaster() but not in 374 // ComponentColorModel.isCompatibleSampleModel(). 375 // These tests might duplicate the implementation of some 376 // subclasses of ComponentColorModel. 377 if(cm instanceof ComponentColorModel) { 378 // Check the number of samples per pixel. 379 int numBands = sm.getNumBands(); 380 if (numBands != cm.getNumComponents()) { 381 return false; 382 } 383 384 // Check adequate depth. This should work for 385 // FloatDoubleColorModel as well because 386 // SampleModel.getSampleSize() should return 32 or 64 as 387 // it gets the size from the DataBuffer object and 388 // ColorModel.getComponentSize() returns the number of bits 389 // which are set to 32 or 64 as a function of the transferType. 390 for (int b = 0; b < numBands; b++) { 391 if (sm.getSampleSize(b) < cm.getComponentSize(b)) { 392 return false; 393 } 394 } 395 } 396 397 // Got this far so return true. 398 return true; 399 } 400 } 401