5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.java2d.cmm.lcms; 27 28 import java.awt.Graphics2D; 29 import java.awt.image.BufferedImage; 30 import java.awt.image.ComponentColorModel; 31 import java.awt.image.Raster; 32 import java.awt.image.WritableRaster; 33 import java.awt.image.SinglePixelPackedSampleModel; 34 import java.awt.image.ComponentSampleModel; 35 import java.awt.image.DataBuffer; 36 import java.awt.image.DataBufferByte; 37 import java.awt.image.DataBufferUShort; 38 import java.awt.image.DataBufferInt; 39 import java.awt.image.ColorModel; 40 import sun.awt.image.ByteComponentRaster; 41 import sun.awt.image.ShortComponentRaster; 42 import sun.awt.image.IntegerComponentRaster; 43 44 45 class LCMSImageLayout { 46 47 public static int BYTES_SH(int x) { 48 return x; 49 } 50 51 public static int EXTRA_SH(int x) { 52 return x<<7; 53 } 54 55 public static int CHANNELS_SH(int x) { 56 return x<<3; 57 } 58 59 public static final int SWAPFIRST = 1<<14; 60 61 public static final int DOSWAP = 1<<10; 62 63 public static final int PT_RGB_8 = 64 CHANNELS_SH(3) | BYTES_SH(1); 65 66 public static final int PT_GRAY_8 = 67 CHANNELS_SH(1) | BYTES_SH(1); 68 69 public static final int PT_GRAY_16 = 70 CHANNELS_SH(1) | BYTES_SH(2); 71 72 public static final int PT_RGBA_8 = 73 EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); 74 75 public static final int PT_ARGB_8 = 76 EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST; 77 78 public static final int PT_BGR_8 = 79 DOSWAP | CHANNELS_SH(3) | BYTES_SH(1); 80 81 public static final int PT_ABGR_8 = 82 DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); 83 84 public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3) | 85 BYTES_SH(1) | DOSWAP | SWAPFIRST; 86 87 public static final int DT_BYTE = 0; 88 public static final int DT_SHORT = 1; 89 public static final int DT_INT = 2; 90 public static final int DT_DOUBLE = 3; 91 92 93 boolean isIntPacked = false; 94 int pixelType; 95 int dataType; 96 int width; 97 int height; 98 int nextRowOffset; 99 int offset; 100 101 Object dataArray; 102 private LCMSImageLayout(int np, int pixelType, int pixelSize) { 103 this.pixelType = pixelType; 104 width = np; 105 height = 1; 106 nextRowOffset = np*pixelSize; 107 offset = 0; 108 } 109 110 private LCMSImageLayout(int width, int height, int pixelType, 111 int pixelSize) { 112 this.pixelType = pixelType; 113 this.width = width; 114 this.height = height; 115 nextRowOffset = width*pixelSize; 116 offset = 0; 117 } 118 119 120 public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) { 121 this(np, pixelType, pixelSize); 122 dataType = DT_BYTE; 123 dataArray = data; 124 } 125 126 public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) { 127 this(np, pixelType, pixelSize); 128 dataType = DT_SHORT; 129 dataArray = data; 130 } 131 132 public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) { 133 this(np, pixelType, pixelSize); 134 dataType = DT_INT; 135 dataArray = data; 136 } 137 138 public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) 139 { 140 this(np, pixelType, pixelSize); 141 dataType = DT_DOUBLE; 142 dataArray = data; 143 } 144 145 public LCMSImageLayout(BufferedImage image) { 146 ShortComponentRaster shortRaster; 147 IntegerComponentRaster intRaster; 148 ByteComponentRaster byteRaster; 149 switch (image.getType()) { 150 case BufferedImage.TYPE_INT_RGB: 151 pixelType = PT_ARGB_8; 152 isIntPacked = true; 153 break; 154 case BufferedImage.TYPE_INT_ARGB: 155 pixelType = PT_ARGB_8; 156 isIntPacked = true; 157 break; 158 case BufferedImage.TYPE_INT_BGR: 159 pixelType = PT_ABGR_8; 160 isIntPacked = true; 161 break; 162 case BufferedImage.TYPE_3BYTE_BGR: 163 pixelType = PT_BGR_8; 164 break; 165 case BufferedImage.TYPE_4BYTE_ABGR: 166 pixelType = PT_ABGR_8; 167 break; 168 case BufferedImage.TYPE_BYTE_GRAY: 169 pixelType = PT_GRAY_8; 170 break; 171 case BufferedImage.TYPE_USHORT_GRAY: 172 pixelType = PT_GRAY_16; 173 break; 174 default: 175 // TODO: Add support for some images having 176 // SinglePixelPackedModel and ComponentSampleModel 177 throw new IllegalArgumentException( 178 "CMMImageLayout - bad image type passed to constructor"); 179 } 180 181 width = image.getWidth(); 182 height = image.getHeight(); 183 184 switch (image.getType()) { 185 case BufferedImage.TYPE_INT_RGB: 186 case BufferedImage.TYPE_INT_ARGB: 187 case BufferedImage.TYPE_INT_BGR: 188 intRaster = (IntegerComponentRaster)image.getRaster(); 189 nextRowOffset = intRaster.getScanlineStride()*4; 190 offset = intRaster.getDataOffset(0)*4; 191 dataArray = intRaster.getDataStorage(); 192 dataType = DT_INT; 193 break; 194 195 case BufferedImage.TYPE_3BYTE_BGR: 196 case BufferedImage.TYPE_4BYTE_ABGR: 197 byteRaster = (ByteComponentRaster)image.getRaster(); 198 nextRowOffset = byteRaster.getScanlineStride(); 199 int firstBand = image.getSampleModel().getNumBands() - 1; 200 offset = byteRaster.getDataOffset(firstBand); 201 dataArray = byteRaster.getDataStorage(); 202 dataType = DT_BYTE; 203 break; 204 205 case BufferedImage.TYPE_BYTE_GRAY: 206 byteRaster = (ByteComponentRaster)image.getRaster(); 207 nextRowOffset = byteRaster.getScanlineStride(); 208 offset = byteRaster.getDataOffset(0); 209 dataArray = byteRaster.getDataStorage(); 210 dataType = DT_BYTE; 211 break; 212 213 case BufferedImage.TYPE_USHORT_GRAY: 214 shortRaster = (ShortComponentRaster)image.getRaster(); 215 nextRowOffset = shortRaster.getScanlineStride()*2; 216 offset = shortRaster.getDataOffset(0) * 2; 217 dataArray = shortRaster.getDataStorage(); 218 dataType = DT_SHORT; 219 break; 220 } 221 } 222 223 public static boolean isSupported(BufferedImage image) { 224 switch (image.getType()) { 225 case BufferedImage.TYPE_INT_RGB: 226 case BufferedImage.TYPE_INT_ARGB: 227 case BufferedImage.TYPE_INT_BGR: 228 case BufferedImage.TYPE_3BYTE_BGR: 229 case BufferedImage.TYPE_4BYTE_ABGR: 230 case BufferedImage.TYPE_BYTE_GRAY: 231 case BufferedImage.TYPE_USHORT_GRAY: 232 return true; 233 } 234 return false; 235 } 236 } | 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package sun.java2d.cmm.lcms; 26 27 import java.awt.image.BufferedImage; 28 import java.awt.image.ComponentColorModel; 29 import java.awt.image.ComponentSampleModel; 30 import java.awt.image.DataBuffer; 31 import java.awt.image.ColorModel; 32 import java.awt.image.Raster; 33 import java.awt.image.SampleModel; 34 import sun.awt.image.ByteComponentRaster; 35 import sun.awt.image.ShortComponentRaster; 36 import sun.awt.image.IntegerComponentRaster; 37 38 class LCMSImageLayout { 39 40 public static int BYTES_SH(int x) { 41 return x; 42 } 43 44 public static int EXTRA_SH(int x) { 45 return x << 7; 46 } 47 48 public static int CHANNELS_SH(int x) { 49 return x << 3; 50 } 51 public static final int SWAPFIRST = 1 << 14; 52 public static final int DOSWAP = 1 << 10; 53 public static final int PT_RGB_8 = 54 CHANNELS_SH(3) | BYTES_SH(1); 55 public static final int PT_GRAY_8 = 56 CHANNELS_SH(1) | BYTES_SH(1); 57 public static final int PT_GRAY_16 = 58 CHANNELS_SH(1) | BYTES_SH(2); 59 public static final int PT_RGBA_8 = 60 EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); 61 public static final int PT_ARGB_8 = 62 EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST; 63 public static final int PT_BGR_8 = 64 DOSWAP | CHANNELS_SH(3) | BYTES_SH(1); 65 public static final int PT_ABGR_8 = 66 DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); 67 public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3) 68 | BYTES_SH(1) | DOSWAP | SWAPFIRST; 69 public static final int DT_BYTE = 0; 70 public static final int DT_SHORT = 1; 71 public static final int DT_INT = 2; 72 public static final int DT_DOUBLE = 3; 73 boolean isIntPacked = false; 74 int pixelType; 75 int dataType; 76 int width; 77 int height; 78 int nextRowOffset; 79 int offset; 80 81 /* This flag indicates whether the image can be processed 82 * at once by doTransfrom() native call. Otherwise, the 83 * image is processed scan by scan. 84 */ 85 private boolean imageAtOnce = false; 86 Object dataArray; 87 88 private LCMSImageLayout(int np, int pixelType, int pixelSize) { 89 this.pixelType = pixelType; 90 width = np; 91 height = 1; 92 nextRowOffset = np * pixelSize; 93 offset = 0; 94 } 95 96 private LCMSImageLayout(int width, int height, int pixelType, 97 int pixelSize) { 98 this.pixelType = pixelType; 99 this.width = width; 100 this.height = height; 101 nextRowOffset = width * pixelSize; 102 offset = 0; 103 } 104 105 public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) { 106 this(np, pixelType, pixelSize); 107 dataType = DT_BYTE; 108 dataArray = data; 109 } 110 111 public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) { 112 this(np, pixelType, pixelSize); 113 dataType = DT_SHORT; 114 dataArray = data; 115 } 116 117 public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) { 118 this(np, pixelType, pixelSize); 119 dataType = DT_INT; 120 dataArray = data; 121 } 122 123 public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) { 124 this(np, pixelType, pixelSize); 125 dataType = DT_DOUBLE; 126 dataArray = data; 127 } 128 129 private LCMSImageLayout() { 130 } 131 132 /* This method creates a layout object for given image. 133 * Returns null if the image is not supported by current implementation. 134 */ 135 public static LCMSImageLayout createImageLayout(BufferedImage image) { 136 LCMSImageLayout l = new LCMSImageLayout(); 137 138 switch (image.getType()) { 139 case BufferedImage.TYPE_INT_RGB: 140 l.pixelType = PT_ARGB_8; 141 l.isIntPacked = true; 142 break; 143 case BufferedImage.TYPE_INT_ARGB: 144 l.pixelType = PT_ARGB_8; 145 l.isIntPacked = true; 146 break; 147 case BufferedImage.TYPE_INT_BGR: 148 l.pixelType = PT_ABGR_8; 149 l.isIntPacked = true; 150 break; 151 case BufferedImage.TYPE_3BYTE_BGR: 152 l.pixelType = PT_BGR_8; 153 break; 154 case BufferedImage.TYPE_4BYTE_ABGR: 155 l.pixelType = PT_ABGR_8; 156 break; 157 case BufferedImage.TYPE_BYTE_GRAY: 158 l.pixelType = PT_GRAY_8; 159 break; 160 case BufferedImage.TYPE_USHORT_GRAY: 161 l.pixelType = PT_GRAY_16; 162 break; 163 default: 164 /* ColorConvertOp creates component images as 165 * default destination, so this kind of images 166 * has to be supported. 167 */ 168 ColorModel cm = image.getColorModel(); 169 if (cm instanceof ComponentColorModel) { 170 ComponentColorModel ccm = (ComponentColorModel) cm; 171 172 // verify whether the component size is fine 173 int[] cs = ccm.getComponentSize(); 174 for (int s : cs) { 175 if (s != 8) { 176 return null; 177 } 178 } 179 180 return createImageLayout(image.getRaster()); 181 182 } 183 return null; 184 } 185 186 l.width = image.getWidth(); 187 l.height = image.getHeight(); 188 189 switch (image.getType()) { 190 case BufferedImage.TYPE_INT_RGB: 191 case BufferedImage.TYPE_INT_ARGB: 192 case BufferedImage.TYPE_INT_BGR: 193 do { 194 IntegerComponentRaster intRaster = (IntegerComponentRaster) 195 image.getRaster(); 196 l.nextRowOffset = intRaster.getScanlineStride() * 4; 197 l.offset = intRaster.getDataOffset(0) * 4; 198 l.dataArray = intRaster.getDataStorage(); 199 l.dataType = DT_INT; 200 201 if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) { 202 l.imageAtOnce = true; 203 } 204 } while (false); 205 break; 206 207 case BufferedImage.TYPE_3BYTE_BGR: 208 case BufferedImage.TYPE_4BYTE_ABGR: 209 do { 210 ByteComponentRaster byteRaster = (ByteComponentRaster) 211 image.getRaster(); 212 l.nextRowOffset = byteRaster.getScanlineStride(); 213 int firstBand = image.getSampleModel().getNumBands() - 1; 214 l.offset = byteRaster.getDataOffset(firstBand); 215 l.dataArray = byteRaster.getDataStorage(); 216 l.dataType = DT_BYTE; 217 if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) { 218 l.imageAtOnce = true; 219 } 220 } while (false); 221 break; 222 223 case BufferedImage.TYPE_BYTE_GRAY: 224 do { 225 ByteComponentRaster byteRaster = (ByteComponentRaster) 226 image.getRaster(); 227 l.nextRowOffset = byteRaster.getScanlineStride(); 228 l.offset = byteRaster.getDataOffset(0); 229 l.dataArray = byteRaster.getDataStorage(); 230 l.dataType = DT_BYTE; 231 232 if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) { 233 l.imageAtOnce = true; 234 } 235 } while (false); 236 break; 237 238 case BufferedImage.TYPE_USHORT_GRAY: 239 do { 240 ShortComponentRaster shortRaster = (ShortComponentRaster) 241 image.getRaster(); 242 l.nextRowOffset = shortRaster.getScanlineStride() * 2; 243 l.offset = shortRaster.getDataOffset(0) * 2; 244 l.dataArray = shortRaster.getDataStorage(); 245 l.dataType = DT_SHORT; 246 247 if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) { 248 l.imageAtOnce = true; 249 } 250 } while (false); 251 break; 252 default: 253 return null; 254 } 255 return l; 256 } 257 258 private static enum BandOrder { 259 DIRECT, 260 INVERTED, 261 ARBITRARY, 262 UNKNOWN; 263 264 public static BandOrder getBandOrder(int[] bandOffsets) { 265 BandOrder order = UNKNOWN; 266 267 int numBands = bandOffsets.length; 268 269 for (int i = 0; (order != ARBITRARY) && (i < bandOffsets.length); i++) { 270 switch (order) { 271 case UNKNOWN: 272 if (bandOffsets[i] == i) { 273 order = DIRECT; 274 } else if (bandOffsets[i] == (numBands - 1 - i)) { 275 order = INVERTED; 276 } else { 277 order = ARBITRARY; 278 } 279 break; 280 case DIRECT: 281 if (bandOffsets[i] != i) { 282 order = ARBITRARY; 283 } 284 break; 285 case INVERTED: 286 if (bandOffsets[i] != (numBands - 1 - i)) { 287 order = ARBITRARY; 288 } 289 break; 290 } 291 } 292 return order; 293 } 294 } 295 296 public static LCMSImageLayout createImageLayout(Raster r) { 297 LCMSImageLayout l = new LCMSImageLayout(); 298 if (r instanceof ByteComponentRaster) { 299 ByteComponentRaster br = (ByteComponentRaster)r; 300 301 ComponentSampleModel csm = (ComponentSampleModel)r.getSampleModel(); 302 303 l.pixelType = CHANNELS_SH(br.getNumBands()) | BYTES_SH(1); 304 305 int[] bandOffsets = csm.getBandOffsets(); 306 BandOrder order = BandOrder.getBandOrder(bandOffsets); 307 308 int firstBand = 0; 309 switch (order) { 310 case INVERTED: 311 l.pixelType |= DOSWAP; 312 firstBand = csm.getNumBands() - 1; 313 break; 314 case DIRECT: 315 // do nothing 316 break; 317 default: 318 // unable to create the image layout; 319 return null; 320 } 321 322 l.nextRowOffset = br.getScanlineStride(); 323 l.offset = br.getDataOffset(firstBand); 324 l.dataArray = br.getDataStorage(); 325 l.dataType = DT_BYTE; 326 327 l.width = br.getWidth(); 328 l.height = br.getHeight(); 329 330 if (l.nextRowOffset == l.width * br.getPixelStride()) { 331 l.imageAtOnce = true; 332 } 333 return l; 334 } 335 return null; 336 } 337 } |