Showing the changes to java/pkg/java/awt/image (123 of 18352 files). Show all
Unified · Split
Binary file not shown.
| @@ -0,0 +1,560 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.geom.AffineTransform; | ||
| 29 | import java.awt.geom.NoninvertibleTransformException; | ||
| 30 | import java.awt.geom.Rectangle2D; | ||
| 31 | import java.awt.geom.Point2D; | ||
| 32 | import java.awt.AlphaComposite; | ||
| 33 | import java.awt.GraphicsEnvironment; | ||
| 34 | import java.awt.Rectangle; | ||
| 35 | import java.awt.RenderingHints; | ||
| 36 | import java.awt.Transparency; | ||
| 37 | import sun.awt.image.ImagingLib; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * This class uses an affine transform to perform a linear mapping from | ||
| 41 | * 2D coordinates in the source image or <CODE>Raster</CODE> to 2D coordinates | ||
| 42 | * in the destination image or <CODE>Raster</CODE>. | ||
| 43 | * The type of interpolation that is used is specified through a constructor, | ||
| 44 | * either by a <CODE>RenderingHints</CODE> object or by one of the integer | ||
| 45 | * interpolation types defined in this class. | ||
| 46 | * <p> | ||
| 47 | * If a <CODE>RenderingHints</CODE> object is specified in the constructor, the | ||
| 48 | * interpolation hint and the rendering quality hint are used to set | ||
| 49 | * the interpolation type for this operation. The color rendering hint | ||
| 50 | * and the dithering hint can be used when color conversion is required. | ||
| 51 | * <p> | ||
| 52 | * Note that the following constraints have to be met: | ||
| 53 | * <ul> | ||
| 54 | * <li>The source and destination must be different. | ||
| 55 | * <li>For <CODE>Raster</CODE> objects, the number of bands in the source must | ||
| 56 | * be equal to the number of bands in the destination. | ||
| 57 | * </ul> | ||
| 58 | * @see AffineTransform | ||
| 59 | * @see BufferedImageFilter | ||
| 60 | * @see java.awt.RenderingHints#KEY_INTERPOLATION | ||
| 61 | * @see java.awt.RenderingHints#KEY_RENDERING | ||
| 62 | * @see java.awt.RenderingHints#KEY_COLOR_RENDERING | ||
| 63 | * @see java.awt.RenderingHints#KEY_DITHERING | ||
| 64 | */ | ||
| 65 | public class AffineTransformOp implements BufferedImageOp, RasterOp { | ||
| 66 | private AffineTransform xform; | ||
| 67 | RenderingHints hints; | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Nearest-neighbor interpolation type. | ||
| 71 | */ | ||
| 72 | public static final int TYPE_NEAREST_NEIGHBOR = 1; | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Bilinear interpolation type. | ||
| 76 | */ | ||
| 77 | public static final int TYPE_BILINEAR = 2; | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Bicubic interpolation type. | ||
| 81 | */ | ||
| 82 | public static final int TYPE_BICUBIC = 3; | ||
| 83 | |||
| 84 | int interpolationType = TYPE_NEAREST_NEIGHBOR; | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Constructs an <CODE>AffineTransformOp</CODE> given an affine transform. | ||
| 88 | * The interpolation type is determined from the | ||
| 89 | * <CODE>RenderingHints</CODE> object. If the interpolation hint is | ||
| 90 | * defined, it will be used. Otherwise, if the rendering quality hint is | ||
| 91 | * defined, the interpolation type is determined from its value. If no | ||
| 92 | * hints are specified (<CODE>hints</CODE> is null), | ||
| 93 | * the interpolation type is {@link #TYPE_NEAREST_NEIGHBOR | ||
| 94 | * TYPE_NEAREST_NEIGHBOR}. | ||
| 95 | * | ||
| 96 | * @param xform The <CODE>AffineTransform</CODE> to use for the | ||
| 97 | * operation. | ||
| 98 | * | ||
| 99 | * @param hints The <CODE>RenderingHints</CODE> object used to specify | ||
| 100 | * the interpolation type for the operation. | ||
| 101 | * | ||
| 102 | * @throws ImagingOpException if the transform is non-invertible. | ||
| 103 | * @see java.awt.RenderingHints#KEY_INTERPOLATION | ||
| 104 | * @see java.awt.RenderingHints#KEY_RENDERING | ||
| 105 | */ | ||
| 106 | public AffineTransformOp(AffineTransform xform, RenderingHints hints){ | ||
| 107 | validateTransform(xform); | ||
| 108 | this.xform = (AffineTransform) xform.clone(); | ||
| 109 | this.hints = hints; | ||
| 110 | |||
| 111 | if (hints != null) { | ||
| 112 | Object value = hints.get(hints.KEY_INTERPOLATION); | ||
| 113 | if (value == null) { | ||
| 114 | value = hints.get(hints.KEY_RENDERING); | ||
| 115 | if (value == hints.VALUE_RENDER_SPEED) { | ||
| 116 | interpolationType = TYPE_NEAREST_NEIGHBOR; | ||
| 117 | } | ||
| 118 | else if (value == hints.VALUE_RENDER_QUALITY) { | ||
| 119 | interpolationType = TYPE_BILINEAR; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | else if (value == hints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR) { | ||
| 123 | interpolationType = TYPE_NEAREST_NEIGHBOR; | ||
| 124 | } | ||
| 125 | else if (value == hints.VALUE_INTERPOLATION_BILINEAR) { | ||
| 126 | interpolationType = TYPE_BILINEAR; | ||
| 127 | } | ||
| 128 | else if (value == hints.VALUE_INTERPOLATION_BICUBIC) { | ||
| 129 | interpolationType = TYPE_BICUBIC; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | else { | ||
| 133 | interpolationType = TYPE_NEAREST_NEIGHBOR; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | /** | ||
| 138 | * Constructs an <CODE>AffineTransformOp</CODE> given an affine transform | ||
| 139 | * and the interpolation type. | ||
| 140 | * | ||
| 141 | * @param xform The <CODE>AffineTransform</CODE> to use for the operation. | ||
| 142 | * @param interpolationType One of the integer | ||
| 143 | * interpolation type constants defined by this class: | ||
| 144 | * {@link #TYPE_NEAREST_NEIGHBOR TYPE_NEAREST_NEIGHBOR}, | ||
| 145 | * {@link #TYPE_BILINEAR TYPE_BILINEAR}, | ||
| 146 | * {@link #TYPE_BICUBIC TYPE_BICUBIC}. | ||
| 147 | * @throws ImagingOpException if the transform is non-invertible. | ||
| 148 | */ | ||
| 149 | public AffineTransformOp(AffineTransform xform, int interpolationType) { | ||
| 150 | validateTransform(xform); | ||
| 151 | this.xform = (AffineTransform)xform.clone(); | ||
| 152 | switch(interpolationType) { | ||
| 153 | case TYPE_NEAREST_NEIGHBOR: | ||
| 154 | case TYPE_BILINEAR: | ||
| 155 | case TYPE_BICUBIC: | ||
| 156 | break; | ||
| 157 | default: | ||
| 158 | throw new IllegalArgumentException("Unknown interpolation type: "+ | ||
| 159 | interpolationType); | ||
| 160 | } | ||
| 161 | this.interpolationType = interpolationType; | ||
| 162 | } | ||
| 163 | |||
| 164 | /** | ||
| 165 | * Returns the interpolation type used by this op. | ||
| 166 | * @return the interpolation type. | ||
| 167 | * @see #TYPE_NEAREST_NEIGHBOR | ||
| 168 | * @see #TYPE_BILINEAR | ||
| 169 | * @see #TYPE_BICUBIC | ||
| 170 | */ | ||
| 171 | public final int getInterpolationType() { | ||
| 172 | return interpolationType; | ||
| 173 | } | ||
| 174 | |||
| 175 | /** | ||
| 176 | * Transforms the source <CODE>BufferedImage</CODE> and stores the results | ||
| 177 | * in the destination <CODE>BufferedImage</CODE>. | ||
| 178 | * If the color models for the two images do not match, a color | ||
| 179 | * conversion into the destination color model is performed. | ||
| 180 | * If the destination image is null, | ||
| 181 | * a <CODE>BufferedImage</CODE> is created with the source | ||
| 182 | * <CODE>ColorModel</CODE>. | ||
| 183 | * <p> | ||
| 184 | * The coordinates of the rectangle returned by | ||
| 185 | * <code>getBounds2D(BufferedImage)</code> | ||
| 186 | * are not necessarily the same as the coordinates of the | ||
| 187 | * <code>BufferedImage</code> returned by this method. If the | ||
| 188 | * upper-left corner coordinates of the rectangle are | ||
| 189 | * negative then this part of the rectangle is not drawn. If the | ||
| 190 | * upper-left corner coordinates of the rectangle are positive | ||
| 191 | * then the filtered image is drawn at that position in the | ||
| 192 | * destination <code>BufferedImage</code>. | ||
| 193 | * <p> | ||
| 194 | * An <CODE>IllegalArgumentException</CODE> is thrown if the source is | ||
| 195 | * the same as the destination. | ||
| 196 | * | ||
| 197 | * @param src The <CODE>BufferedImage</CODE> to transform. | ||
| 198 | * @param dst The <CODE>BufferedImage</CODE> in which to store the results | ||
| 199 | * of the transformation. | ||
| 200 | * | ||
| 201 | * @return The filtered <CODE>BufferedImage</CODE>. | ||
| 202 | * @throws IllegalArgumentException if <code>src</code> and | ||
| 203 | * <code>dst</code> are the same | ||
| 204 | * @throws ImagingOpException if the image cannot be transformed | ||
| 205 | * because of a data-processing error that might be | ||
| 206 | * caused by an invalid image format, tile format, or | ||
| 207 | * image-processing operation, or any other unsupported | ||
| 208 | * operation. | ||
| 209 | */ | ||
| 210 | public final BufferedImage filter(BufferedImage src, BufferedImage dst) { | ||
| 211 | |||
| 212 | if (src == null) { | ||
| 213 | throw new NullPointerException("src image is null"); | ||
| 214 | } | ||
| 215 | if (src == dst) { | ||
| 216 | throw new IllegalArgumentException("src image cannot be the "+ | ||
| 217 | "same as the dst image"); | ||
| 218 | } | ||
| 219 | |||
| 220 | boolean needToConvert = false; | ||
| 221 | ColorModel srcCM = src.getColorModel(); | ||
| 222 | ColorModel dstCM; | ||
| 223 | BufferedImage origDst = dst; | ||
| 224 | |||
| 225 | if (dst == null) { | ||
| 226 | dst = createCompatibleDestImage(src, null); | ||
| 227 | dstCM = srcCM; | ||
| 228 | origDst = dst; | ||
| 229 | } | ||
| 230 | else { | ||
| 231 | dstCM = dst.getColorModel(); | ||
| 232 | if (srcCM.getColorSpace().getType() != | ||
| 233 | dstCM.getColorSpace().getType()) | ||
| 234 | { | ||
| 235 | int type = xform.getType(); | ||
| 236 | boolean needTrans = ((type& | ||
| 237 | (xform.TYPE_MASK_ROTATION| | ||
| 238 | xform.TYPE_GENERAL_TRANSFORM)) | ||
| 239 | != 0); | ||
| 240 | if (! needTrans && type != xform.TYPE_TRANSLATION && type != xform.TYPE_IDENTITY) | ||
| 241 | { | ||
| 242 | double[] mtx = new double[4]; | ||
| 243 | xform.getMatrix(mtx); | ||
| 244 | // Check out the matrix. A non-integral scale will force ARGB | ||
| 245 | // since the edge conditions can't be guaranteed. | ||
| 246 | needTrans = (mtx[0] != (int)mtx[0] || mtx[3] != (int)mtx[3]); | ||
| 247 | } | ||
| 248 | |||
| 249 | if (needTrans && | ||
| 250 | srcCM.getTransparency() == Transparency.OPAQUE) | ||
| 251 | { | ||
| 252 | // Need to convert first | ||
| 253 | ColorConvertOp ccop = new ColorConvertOp(hints); | ||
| 254 | BufferedImage tmpSrc = null; | ||
| 255 | int sw = src.getWidth(); | ||
| 256 | int sh = src.getHeight(); | ||
| 257 | if (dstCM.getTransparency() == Transparency.OPAQUE) { | ||
| 258 | tmpSrc = new BufferedImage(sw, sh, | ||
| 259 | BufferedImage.TYPE_INT_ARGB); | ||
| 260 | } | ||
| 261 | else { | ||
| 262 | WritableRaster r = | ||
| 263 | dstCM.createCompatibleWritableRaster(sw, sh); | ||
| 264 | tmpSrc = new BufferedImage(dstCM, r, | ||
| 265 | dstCM.isAlphaPremultiplied(), | ||
| 266 | null); | ||
| 267 | } | ||
| 268 | src = ccop.filter(src, tmpSrc); | ||
| 269 | } | ||
| 270 | else { | ||
| 271 | needToConvert = true; | ||
| 272 | dst = createCompatibleDestImage(src, null); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | } | ||
| 277 | |||
| 278 | if (interpolationType != TYPE_NEAREST_NEIGHBOR && | ||
| 279 | dst.getColorModel() instanceof IndexColorModel) { | ||
| 280 | dst = new BufferedImage(dst.getWidth(), dst.getHeight(), | ||
| 281 | BufferedImage.TYPE_INT_ARGB); | ||
| 282 | } | ||
| 283 | if (ImagingLib.filter(this, src, dst) == null) { | ||
| 284 | throw new ImagingOpException ("Unable to transform src image"); | ||
| 285 | } | ||
| 286 | |||
| 287 | if (needToConvert) { | ||
| 288 | ColorConvertOp ccop = new ColorConvertOp(hints); | ||
| 289 | ccop.filter(dst, origDst); | ||
| 290 | } | ||
| 291 | else if (origDst != dst) { | ||
| 292 | java.awt.Graphics2D g = origDst.createGraphics(); | ||
| 293 | try { | ||
| 294 | g.setComposite(AlphaComposite.Src); | ||
| 295 | g.drawImage(dst, 0, 0, null); | ||
| 296 | } finally { | ||
| 297 | g.dispose(); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | return origDst; | ||
| 302 | } | ||
| 303 | |||
| 304 | /** | ||
| 305 | * Transforms the source <CODE>Raster</CODE> and stores the results in | ||
| 306 | * the destination <CODE>Raster</CODE>. This operation performs the | ||
| 307 | * transform band by band. | ||
| 308 | * <p> | ||
| 309 | * If the destination <CODE>Raster</CODE> is null, a new | ||
| 310 | * <CODE>Raster</CODE> is created. | ||
| 311 | * An <CODE>IllegalArgumentException</CODE> may be thrown if the source is | ||
| 312 | * the same as the destination or if the number of bands in | ||
| 313 | * the source is not equal to the number of bands in the | ||
| 314 | * destination. | ||
| 315 | * <p> | ||
| 316 | * The coordinates of the rectangle returned by | ||
| 317 | * <code>getBounds2D(Raster)</code> | ||
| 318 | * are not necessarily the same as the coordinates of the | ||
| 319 | * <code>WritableRaster</code> returned by this method. If the | ||
| 320 | * upper-left corner coordinates of rectangle are negative then | ||
| 321 | * this part of the rectangle is not drawn. If the coordinates | ||
| 322 | * of the rectangle are positive then the filtered image is drawn at | ||
| 323 | * that position in the destination <code>Raster</code>. | ||
| 324 | * <p> | ||
| 325 | * @param src The <CODE>Raster</CODE> to transform. | ||
| 326 | * @param dst The <CODE>Raster</CODE> in which to store the results of the | ||
| 327 | * transformation. | ||
| 328 | * | ||
| 329 | * @return The transformed <CODE>Raster</CODE>. | ||
| 330 | * | ||
| 331 | * @throws ImagingOpException if the raster cannot be transformed | ||
| 332 | * because of a data-processing error that might be | ||
| 333 | * caused by an invalid image format, tile format, or | ||
| 334 | * image-processing operation, or any other unsupported | ||
| 335 | * operation. | ||
| 336 | */ | ||
| 337 | public final WritableRaster filter(Raster src, WritableRaster dst) { | ||
| 338 | if (src == null) { | ||
| 339 | throw new NullPointerException("src image is null"); | ||
| 340 | } | ||
| 341 | if (dst == null) { | ||
| 342 | dst = createCompatibleDestRaster(src); | ||
| 343 | } | ||
| 344 | if (src == dst) { | ||
| 345 | throw new IllegalArgumentException("src image cannot be the "+ | ||
| 346 | "same as the dst image"); | ||
| 347 | } | ||
| 348 | if (src.getNumBands() != dst.getNumBands()) { | ||
| 349 | throw new IllegalArgumentException("Number of src bands ("+ | ||
| 350 | src.getNumBands()+ | ||
| 351 | ") does not match number of "+ | ||
| 352 | " dst bands ("+ | ||
| 353 | dst.getNumBands()+")"); | ||
| 354 | } | ||
| 355 | |||
| 356 | if (ImagingLib.filter(this, src, dst) == null) { | ||
| 357 | throw new ImagingOpException ("Unable to transform src image"); | ||
| 358 | } | ||
| 359 | return dst; | ||
| 360 | } | ||
| 361 | |||
| 362 | /** | ||
| 363 | * Returns the bounding box of the transformed destination. The | ||
| 364 | * rectangle returned is the actual bounding box of the | ||
| 365 | * transformed points. The coordinates of the upper-left corner | ||
| 366 | * of the returned rectangle might not be (0, 0). | ||
| 367 | * | ||
| 368 | * @param src The <CODE>BufferedImage</CODE> to be transformed. | ||
| 369 | * | ||
| 370 | * @return The <CODE>Rectangle2D</CODE> representing the destination's | ||
| 371 | * bounding box. | ||
| 372 | */ | ||
| 373 | public final Rectangle2D getBounds2D (BufferedImage src) { | ||
| 374 | return getBounds2D(src.getRaster()); | ||
| 375 | } | ||
| 376 | |||
| 377 | /** | ||
| 378 | * Returns the bounding box of the transformed destination. The | ||
| 379 | * rectangle returned will be the actual bounding box of the | ||
| 380 | * transformed points. The coordinates of the upper-left corner | ||
| 381 | * of the returned rectangle might not be (0, 0). | ||
| 382 | * | ||
| 383 | * @param src The <CODE>Raster</CODE> to be transformed. | ||
| 384 | * | ||
| 385 | * @return The <CODE>Rectangle2D</CODE> representing the destination's | ||
| 386 | * bounding box. | ||
| 387 | */ | ||
| 388 | public final Rectangle2D getBounds2D (Raster src) { | ||
| 389 | int w = src.getWidth(); | ||
| 390 | int h = src.getHeight(); | ||
| 391 | |||
| 392 | // Get the bounding box of the src and transform the corners | ||
| 393 | float[] pts = {0, 0, w, 0, w, h, 0, h}; | ||
| 394 | xform.transform(pts, 0, pts, 0, 4); | ||
| 395 | |||
| 396 | // Get the min, max of the dst | ||
| 397 | float fmaxX = pts[0]; | ||
| 398 | float fmaxY = pts[1]; | ||
| 399 | float fminX = pts[0]; | ||
| 400 | float fminY = pts[1]; | ||
| 401 | for (int i=2; i < 8; i+=2) { | ||
| 402 | if (pts[i] > fmaxX) { | ||
| 403 | fmaxX = pts[i]; | ||
| 404 | } | ||
| 405 | else if (pts[i] < fminX) { | ||
| 406 | fminX = pts[i]; | ||
| 407 | } | ||
| 408 | if (pts[i+1] > fmaxY) { | ||
| 409 | fmaxY = pts[i+1]; | ||
| 410 | } | ||
| 411 | else if (pts[i+1] < fminY) { | ||
| 412 | fminY = pts[i+1]; | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | return new Rectangle2D.Float(fminX, fminY, fmaxX-fminX, fmaxY-fminY); | ||
| 417 | } | ||
| 418 | |||
| 419 | /** | ||
| 420 | * Creates a zeroed destination image with the correct size and number of | ||
| 421 | * bands. A <CODE>RasterFormatException</CODE> may be thrown if the | ||
| 422 | * transformed width or height is equal to 0. | ||
| 423 | * <p> | ||
| 424 | * If <CODE>destCM</CODE> is null, | ||
| 425 | * an appropriate <CODE>ColorModel</CODE> is used; this | ||
| 426 | * <CODE>ColorModel</CODE> may have | ||
| 427 | * an alpha channel even if the source <CODE>ColorModel</CODE> is opaque. | ||
| 428 | * | ||
| 429 | * @param src The <CODE>BufferedImage</CODE> to be transformed. | ||
| 430 | * @param destCM <CODE>ColorModel</CODE> of the destination. If null, | ||
| 431 | * an appropriate <CODE>ColorModel</CODE> is used. | ||
| 432 | * | ||
| 433 | * @return The zeroed destination image. | ||
| 434 | */ | ||
| 435 | public BufferedImage createCompatibleDestImage (BufferedImage src, | ||
| 436 | ColorModel destCM) { | ||
| 437 | BufferedImage image; | ||
| 438 | Rectangle r = getBounds2D(src).getBounds(); | ||
| 439 | |||
| 440 | // If r.x (or r.y) is < 0, then we want to only create an image | ||
| 441 | // that is in the positive range. | ||
| 442 | // If r.x (or r.y) is > 0, then we need to create an image that | ||
| 443 | // includes the translation. | ||
| 444 | int w = r.x + r.width; | ||
| 445 | int h = r.y + r.height; | ||
| 446 | if (w <= 0) { | ||
| 447 | throw new RasterFormatException("Transformed width ("+w+ | ||
| 448 | ") is less than or equal to 0."); | ||
| 449 | } | ||
| 450 | if (h <= 0) { | ||
| 451 | throw new RasterFormatException("Transformed height ("+h+ | ||
| 452 | ") is less than or equal to 0."); | ||
| 453 | } | ||
| 454 | |||
| 455 | if (destCM == null) { | ||
| 456 | ColorModel cm = src.getColorModel(); | ||
| 457 | if (interpolationType != TYPE_NEAREST_NEIGHBOR && | ||
| 458 | (cm instanceof IndexColorModel || | ||
| 459 | cm.getTransparency() == Transparency.OPAQUE)) | ||
| 460 | { | ||
| 461 | image = new BufferedImage(w, h, | ||
| 462 | BufferedImage.TYPE_INT_ARGB); | ||
| 463 | } | ||
| 464 | else { | ||
| 465 | image = new BufferedImage(cm, | ||
| 466 | src.getRaster().createCompatibleWritableRaster(w,h), | ||
| 467 | cm.isAlphaPremultiplied(), null); | ||
| 468 | } | ||
| 469 | } | ||
| 470 | else { | ||
| 471 | image = new BufferedImage(destCM, | ||
| 472 | destCM.createCompatibleWritableRaster(w,h), | ||
| 473 | destCM.isAlphaPremultiplied(), null); | ||
| 474 | } | ||
| 475 | |||
| 476 | return image; | ||
| 477 | } | ||
| 478 | |||
| 479 | /** | ||
| 480 | * Creates a zeroed destination <CODE>Raster</CODE> with the correct size | ||
| 481 | * and number of bands. A <CODE>RasterFormatException</CODE> may be thrown | ||
| 482 | * if the transformed width or height is equal to 0. | ||
| 483 | * | ||
| 484 | * @param src The <CODE>Raster</CODE> to be transformed. | ||
| 485 | * | ||
| 486 | * @return The zeroed destination <CODE>Raster</CODE>. | ||
| 487 | */ | ||
| 488 | public WritableRaster createCompatibleDestRaster (Raster src) { | ||
| 489 | Rectangle2D r = getBounds2D(src); | ||
| 490 | |||
| 491 | return src.createCompatibleWritableRaster((int)r.getX(), | ||
| 492 | (int)r.getY(), | ||
| 493 | (int)r.getWidth(), | ||
| 494 | (int)r.getHeight()); | ||
| 495 | } | ||
| 496 | |||
| 497 | /** | ||
| 498 | * Returns the location of the corresponding destination point given a | ||
| 499 | * point in the source. If <CODE>dstPt</CODE> is specified, it | ||
| 500 | * is used to hold the return value. | ||
| 501 | * | ||
| 502 | * @param srcPt The <code>Point2D</code> that represents the source | ||
| 503 | * point. | ||
| 504 | * @param dstPt The <CODE>Point2D</CODE> in which to store the result. | ||
| 505 | * | ||
| 506 | * @return The <CODE>Point2D</CODE> in the destination that corresponds to | ||
| 507 | * the specified point in the source. | ||
| 508 | */ | ||
| 509 | public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) { | ||
| 510 | return xform.transform (srcPt, dstPt); | ||
| 511 | } | ||
| 512 | |||
| 513 | /** | ||
| 514 | * Returns the affine transform used by this transform operation. | ||
| 515 | * | ||
| 516 | * @return The <CODE>AffineTransform</CODE> associated with this op. | ||
| 517 | */ | ||
| 518 | public final AffineTransform getTransform() { | ||
| 519 | return (AffineTransform) xform.clone(); | ||
| 520 | } | ||
| 521 | |||
| 522 | /** | ||
| 523 | * Returns the rendering hints used by this transform operation. | ||
| 524 | * | ||
| 525 | * @return The <CODE>RenderingHints</CODE> object associated with this op. | ||
| 526 | */ | ||
| 527 | public final RenderingHints getRenderingHints() { | ||
| 528 | if (hints == null) { | ||
| 529 | Object val; | ||
| 530 | switch(interpolationType) { | ||
| 531 | case TYPE_NEAREST_NEIGHBOR: | ||
| 532 | val = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; | ||
| 533 | break; | ||
| 534 | case TYPE_BILINEAR: | ||
| 535 | val = RenderingHints.VALUE_INTERPOLATION_BILINEAR; | ||
| 536 | break; | ||
| 537 | case TYPE_BICUBIC: | ||
| 538 | val = RenderingHints.VALUE_INTERPOLATION_BICUBIC; | ||
| 539 | break; | ||
| 540 | default: | ||
| 541 | // Should never get here | ||
| 542 | throw new InternalError("Unknown interpolation type "+ | ||
| 543 | interpolationType); | ||
| 544 | |||
| 545 | } | ||
| 546 | hints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, val); | ||
| 547 | } | ||
| 548 | |||
| 549 | return hints; | ||
| 550 | } | ||
| 551 | |||
| 552 | // We need to be able to invert the transform if we want to | ||
| 553 | // transform the image. If the determinant of the matrix is 0, | ||
| 554 | // then we can't invert the transform. | ||
| 555 | void validateTransform(AffineTransform xform) { | ||
| 556 | if (Math.abs(xform.getDeterminant()) <= Double.MIN_VALUE) { | ||
| 557 | throw new ImagingOpException("Unable to invert transform "+xform); | ||
| 558 | } | ||
| 559 | } | ||
| 560 | } | ||
Binary file not shown.
| @@ -0,0 +1,281 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.image.ImageConsumer; | ||
| 29 | import java.awt.image.ColorModel; | ||
| 30 | import java.util.Hashtable; | ||
| 31 | import java.awt.Rectangle; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * An ImageFilter class for scaling images using a simple area averaging | ||
| 35 | * algorithm that produces smoother results than the nearest neighbor | ||
| 36 | * algorithm. | ||
| 37 | * <p>This class extends the basic ImageFilter Class to scale an existing | ||
| 38 | * image and provide a source for a new image containing the resampled | ||
| 39 | * image. The pixels in the source image are blended to produce pixels | ||
| 40 | * for an image of the specified size. The blending process is analogous | ||
| 41 | * to scaling up the source image to a multiple of the destination size | ||
| 42 | * using pixel replication and then scaling it back down to the destination | ||
| 43 | * size by simply averaging all the pixels in the supersized image that | ||
| 44 | * fall within a given pixel of the destination image. If the data from | ||
| 45 | * the source is not delivered in TopDownLeftRight order then the filter | ||
| 46 | * will back off to a simple pixel replication behavior and utilize the | ||
| 47 | * requestTopDownLeftRightResend() method to refilter the pixels in a | ||
| 48 | * better way at the end. | ||
| 49 | * <p>It is meant to be used in conjunction with a FilteredImageSource | ||
| 50 | * object to produce scaled versions of existing images. Due to | ||
| 51 | * implementation dependencies, there may be differences in pixel values | ||
| 52 | * of an image filtered on different platforms. | ||
| 53 | * | ||
| 54 | * @see FilteredImageSource | ||
| 55 | * @see ReplicateScaleFilter | ||
| 56 | * @see ImageFilter | ||
| 57 | * | ||
| 58 | * @author Jim Graham | ||
| 59 | */ | ||
| 60 | public class AreaAveragingScaleFilter extends ReplicateScaleFilter { | ||
| 61 | private static final ColorModel rgbmodel = ColorModel.getRGBdefault(); | ||
| 62 | private static final int neededHints = (TOPDOWNLEFTRIGHT | ||
| 63 | | COMPLETESCANLINES); | ||
| 64 | |||
| 65 | private boolean passthrough; | ||
| 66 | private float reds[], greens[], blues[], alphas[]; | ||
| 67 | private int savedy; | ||
| 68 | private int savedyrem; | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Constructs an AreaAveragingScaleFilter that scales the pixels from | ||
| 72 | * its source Image as specified by the width and height parameters. | ||
| 73 | * @param width the target width to scale the image | ||
| 74 | * @param height the target height to scale the image | ||
| 75 | */ | ||
| 76 | public AreaAveragingScaleFilter(int width, int height) { | ||
| 77 | super(width, height); | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Detect if the data is being delivered with the necessary hints | ||
| 82 | * to allow the averaging algorithm to do its work. | ||
| 83 | * <p> | ||
| 84 | * Note: This method is intended to be called by the | ||
| 85 | * <code>ImageProducer</code> of the <code>Image</code> whose | ||
| 86 | * pixels are being filtered. Developers using | ||
| 87 | * this class to filter pixels from an image should avoid calling | ||
| 88 | * this method directly since that operation could interfere | ||
| 89 | * with the filtering operation. | ||
| 90 | * @see ImageConsumer#setHints | ||
| 91 | */ | ||
| 92 | public void setHints(int hints) { | ||
| 93 | passthrough = ((hints & neededHints) != neededHints); | ||
| 94 | super.setHints(hints); | ||
| 95 | } | ||
| 96 | |||
| 97 | private void makeAccumBuffers() { | ||
| 98 | reds = new float[destWidth]; | ||
| 99 | greens = new float[destWidth]; | ||
| 100 | blues = new float[destWidth]; | ||
| 101 | alphas = new float[destWidth]; | ||
| 102 | } | ||
| 103 | |||
| 104 | private int[] calcRow() { | ||
| 105 | float origmult = ((float) srcWidth) * srcHeight; | ||
| 106 | if (outpixbuf == null || !(outpixbuf instanceof int[])) { | ||
| 107 | outpixbuf = new int[destWidth]; | ||
| 108 | } | ||
| 109 | int[] outpix = (int[]) outpixbuf; | ||
| 110 | for (int x = 0; x < destWidth; x++) { | ||
| 111 | float mult = origmult; | ||
| 112 | int a = Math.round(alphas[x] / mult); | ||
| 113 | if (a <= 0) { | ||
| 114 | a = 0; | ||
| 115 | } else if (a >= 255) { | ||
| 116 | a = 255; | ||
| 117 | } else { | ||
| 118 | // un-premultiply the components (by modifying mult here, we | ||
| 119 | // are effectively doing the divide by mult and divide by | ||
| 120 | // alpha in the same step) | ||
| 121 | mult = alphas[x] / 255; | ||
| 122 | } | ||
| 123 | int r = Math.round(reds[x] / mult); | ||
| 124 | int g = Math.round(greens[x] / mult); | ||
| 125 | int b = Math.round(blues[x] / mult); | ||
| 126 | if (r < 0) {r = 0;} else if (r > 255) {r = 255;} | ||
| 127 | if (g < 0) {g = 0;} else if (g > 255) {g = 255;} | ||
| 128 | if (b < 0) {b = 0;} else if (b > 255) {b = 255;} | ||
| 129 | outpix[x] = (a << 24 | r << 16 | g << 8 | b); | ||
| 130 | } | ||
| 131 | return outpix; | ||
| 132 | } | ||
| 133 | |||
| 134 | private void accumPixels(int x, int y, int w, int h, | ||
| 135 | ColorModel model, Object pixels, int off, | ||
| 136 | int scansize) { | ||
| 137 | if (reds == null) { | ||
| 138 | makeAccumBuffers(); | ||
| 139 | } | ||
| 140 | int sy = y; | ||
| 141 | int syrem = destHeight; | ||
| 142 | int dy, dyrem; | ||
| 143 | if (sy == 0) { | ||
| 144 | dy = 0; | ||
| 145 | dyrem = 0; | ||
| 146 | } else { | ||
| 147 | dy = savedy; | ||
| 148 | dyrem = savedyrem; | ||
| 149 | } | ||
| 150 | while (sy < y + h) { | ||
| 151 | int amty; | ||
| 152 | if (dyrem == 0) { | ||
| 153 | for (int i = 0; i < destWidth; i++) { | ||
| 154 | alphas[i] = reds[i] = greens[i] = blues[i] = 0f; | ||
| 155 | } | ||
| 156 | dyrem = srcHeight; | ||
| 157 | } | ||
| 158 | if (syrem < dyrem) { | ||
| 159 | amty = syrem; | ||
| 160 | } else { | ||
| 161 | amty = dyrem; | ||
| 162 | } | ||
| 163 | int sx = 0; | ||
| 164 | int dx = 0; | ||
| 165 | int sxrem = 0; | ||
| 166 | int dxrem = srcWidth; | ||
| 167 | float a = 0f, r = 0f, g = 0f, b = 0f; | ||
| 168 | while (sx < w) { | ||
| 169 | if (sxrem == 0) { | ||
| 170 | sxrem = destWidth; | ||
| 171 | int rgb; | ||
| 172 | if (pixels instanceof byte[]) { | ||
| 173 | rgb = ((byte[]) pixels)[off + sx] & 0xff; | ||
| 174 | } else { | ||
| 175 | rgb = ((int[]) pixels)[off + sx]; | ||
| 176 | } | ||
| 177 | // getRGB() always returns non-premultiplied components | ||
| 178 | rgb = model.getRGB(rgb); | ||
| 179 | a = rgb >>> 24; | ||
| 180 | r = (rgb >> 16) & 0xff; | ||
| 181 | g = (rgb >> 8) & 0xff; | ||
| 182 | b = rgb & 0xff; | ||
| 183 | // premultiply the components if necessary | ||
| 184 | if (a != 255.0f) { | ||
| 185 | float ascale = a / 255.0f; | ||
| 186 | r *= ascale; | ||
| 187 | g *= ascale; | ||
| 188 | b *= ascale; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | int amtx; | ||
| 192 | if (sxrem < dxrem) { | ||
| 193 | amtx = sxrem; | ||
| 194 | } else { | ||
| 195 | amtx = dxrem; | ||
| 196 | } | ||
| 197 | float mult = ((float) amtx) * amty; | ||
| 198 | alphas[dx] += mult * a; | ||
| 199 | reds[dx] += mult * r; | ||
| 200 | greens[dx] += mult * g; | ||
| 201 | blues[dx] += mult * b; | ||
| 202 | if ((sxrem -= amtx) == 0) { | ||
| 203 | sx++; | ||
| 204 | } | ||
| 205 | if ((dxrem -= amtx) == 0) { | ||
| 206 | dx++; | ||
| 207 | dxrem = srcWidth; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | if ((dyrem -= amty) == 0) { | ||
| 211 | int outpix[] = calcRow(); | ||
| 212 | do { | ||
| 213 | consumer.setPixels(0, dy, destWidth, 1, | ||
| 214 | rgbmodel, outpix, 0, destWidth); | ||
| 215 | dy++; | ||
| 216 | } while ((syrem -= amty) >= amty && amty == srcHeight); | ||
| 217 | } else { | ||
| 218 | syrem -= amty; | ||
| 219 | } | ||
| 220 | if (syrem == 0) { | ||
| 221 | syrem = destHeight; | ||
| 222 | sy++; | ||
| 223 | off += scansize; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | savedyrem = dyrem; | ||
| 227 | savedy = dy; | ||
| 228 | } | ||
| 229 | |||
| 230 | /** | ||
| 231 | * Combine the components for the delivered byte pixels into the | ||
| 232 | * accumulation arrays and send on any averaged data for rows of | ||
| 233 | * pixels that are complete. If the correct hints were not | ||
| 234 | * specified in the setHints call then relay the work to our | ||
| 235 | * superclass which is capable of scaling pixels regardless of | ||
| 236 | * the delivery hints. | ||
| 237 | * <p> | ||
| 238 | * Note: This method is intended to be called by the | ||
| 239 | * <code>ImageProducer</code> of the <code>Image</code> | ||
| 240 | * whose pixels are being filtered. Developers using | ||
| 241 | * this class to filter pixels from an image should avoid calling | ||
| 242 | * this method directly since that operation could interfere | ||
| 243 | * with the filtering operation. | ||
| 244 | * @see ReplicateScaleFilter | ||
| 245 | */ | ||
| 246 | public void setPixels(int x, int y, int w, int h, | ||
| 247 | ColorModel model, byte pixels[], int off, | ||
| 248 | int scansize) { | ||
| 249 | if (passthrough) { | ||
| 250 | super.setPixels(x, y, w, h, model, pixels, off, scansize); | ||
| 251 | } else { | ||
| 252 | accumPixels(x, y, w, h, model, pixels, off, scansize); | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | /** | ||
| 257 | * Combine the components for the delivered int pixels into the | ||
| 258 | * accumulation arrays and send on any averaged data for rows of | ||
| 259 | * pixels that are complete. If the correct hints were not | ||
| 260 | * specified in the setHints call then relay the work to our | ||
| 261 | * superclass which is capable of scaling pixels regardless of | ||
| 262 | * the delivery hints. | ||
| 263 | * <p> | ||
| 264 | * Note: This method is intended to be called by the | ||
| 265 | * <code>ImageProducer</code> of the <code>Image</code> | ||
| 266 | * whose pixels are being filtered. Developers using | ||
| 267 | * this class to filter pixels from an image should avoid calling | ||
| 268 | * this method directly since that operation could interfere | ||
| 269 | * with the filtering operation. | ||
| 270 | * @see ReplicateScaleFilter | ||
| 271 | */ | ||
| 272 | public void setPixels(int x, int y, int w, int h, | ||
| 273 | ColorModel model, int pixels[], int off, | ||
| 274 | int scansize) { | ||
| 275 | if (passthrough) { | ||
| 276 | super.setPixels(x, y, w, h, model, pixels, off, scansize); | ||
| 277 | } else { | ||
| 278 | accumPixels(x, y, w, h, model, pixels, off, scansize); | ||
| 279 | } | ||
| 280 | } | ||
| 281 | } | ||
Binary file not shown.
| @@ -0,0 +1,289 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.GraphicsEnvironment; | ||
| 29 | import java.awt.color.ICC_Profile; | ||
| 30 | import java.awt.geom.Rectangle2D; | ||
| 31 | import java.awt.Rectangle; | ||
| 32 | import java.awt.geom.Point2D; | ||
| 33 | import java.awt.RenderingHints; | ||
| 34 | import sun.awt.image.ImagingLib; | ||
| 35 | import java.util.Arrays; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * This class performs an arbitrary linear combination of the bands | ||
| 39 | * in a <CODE>Raster</CODE>, using a specified matrix. | ||
| 40 | * <p> | ||
| 41 | * The width of the matrix must be equal to the number of bands in the | ||
| 42 | * source <CODE>Raster</CODE>, optionally plus one. If there is one more | ||
| 43 | * column in the matrix than the number of bands, there is an implied 1 at the | ||
| 44 | * end of the vector of band samples representing a pixel. The height | ||
| 45 | * of the matrix must be equal to the number of bands in the destination. | ||
| 46 | * <p> | ||
| 47 | * For example, a 3-banded <CODE>Raster</CODE> might have the following | ||
| 48 | * transformation applied to each pixel in order to invert the second band of | ||
| 49 | * the <CODE>Raster</CODE>. | ||
| 50 | * <pre> | ||
| 51 | * [ 1.0 0.0 0.0 0.0 ] [ b1 ] | ||
| 52 | * [ 0.0 -1.0 0.0 255.0 ] x [ b2 ] | ||
| 53 | * [ 0.0 0.0 1.0 0.0 ] [ b3 ] | ||
| 54 | * [ 1 ] | ||
| 55 | * </pre> | ||
| 56 | * | ||
| 57 | * <p> | ||
| 58 | * Note that the source and destination can be the same object. | ||
| 59 | */ | ||
| 60 | public class BandCombineOp implements RasterOp { | ||
| 61 | float[][] matrix; | ||
| 62 | int nrows = 0; | ||
| 63 | int ncols = 0; | ||
| 64 | RenderingHints hints; | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Constructs a <CODE>BandCombineOp</CODE> with the specified matrix. | ||
| 68 | * The width of the matrix must be equal to the number of bands in | ||
| 69 | * the source <CODE>Raster</CODE>, optionally plus one. If there is one | ||
| 70 | * more column in the matrix than the number of bands, there is an implied | ||
| 71 | * 1 at the end of the vector of band samples representing a pixel. The | ||
| 72 | * height of the matrix must be equal to the number of bands in the | ||
| 73 | * destination. | ||
| 74 | * <p> | ||
| 75 | * The first subscript is the row index and the second | ||
| 76 | * is the column index. This operation uses none of the currently | ||
| 77 | * defined rendering hints; the <CODE>RenderingHints</CODE> argument can be | ||
| 78 | * null. | ||
| 79 | * | ||
| 80 | * @param matrix The matrix to use for the band combine operation. | ||
| 81 | * @param hints The <CODE>RenderingHints</CODE> object for this operation. | ||
| 82 | * Not currently used so it can be null. | ||
| 83 | */ | ||
| 84 | public BandCombineOp (float[][] matrix, RenderingHints hints) { | ||
| 85 | nrows = matrix.length; | ||
| 86 | ncols = matrix[0].length; | ||
| 87 | this.matrix = new float[nrows][]; | ||
| 88 | for (int i=0; i < nrows; i++) { | ||
| 89 | /* Arrays.copyOf is forgiving of the source array being | ||
| 90 | * too short, but it is also faster than other cloning | ||
| 91 | * methods, so we provide our own protection for short | ||
| 92 | * matrix rows. | ||
| 93 | */ | ||
| 94 | if (ncols > matrix[i].length) { | ||
| 95 | throw new IndexOutOfBoundsException("row "+i+" too short"); | ||
| 96 | } | ||
| 97 | this.matrix[i] = Arrays.copyOf(matrix[i], ncols); | ||
| 98 | } | ||
| 99 | this.hints = hints; | ||
| 100 | } | ||
| 101 | |||
| 102 | /** | ||
| 103 | * Returns a copy of the linear combination matrix. | ||
| 104 | * | ||
| 105 | * @return The matrix associated with this band combine operation. | ||
| 106 | */ | ||
| 107 | public final float[][] getMatrix() { | ||
| 108 | float[][] ret = new float[nrows][]; | ||
| 109 | for (int i = 0; i < nrows; i++) { | ||
| 110 | ret[i] = Arrays.copyOf(matrix[i], ncols); | ||
| 111 | } | ||
| 112 | return ret; | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Transforms the <CODE>Raster</CODE> using the matrix specified in the | ||
| 117 | * constructor. An <CODE>IllegalArgumentException</CODE> may be thrown if | ||
| 118 | * the number of bands in the source or destination is incompatible with | ||
| 119 | * the matrix. See the class comments for more details. | ||
| 120 | * <p> | ||
| 121 | * If the destination is null, it will be created with a number of bands | ||
| 122 | * equalling the number of rows in the matrix. No exception is thrown | ||
| 123 | * if the operation causes a data overflow. | ||
| 124 | * | ||
| 125 | * @param src The <CODE>Raster</CODE> to be filtered. | ||
| 126 | * @param dst The <CODE>Raster</CODE> in which to store the results | ||
| 127 | * of the filter operation. | ||
| 128 | * | ||
| 129 | * @return The filtered <CODE>Raster</CODE>. | ||
| 130 | * | ||
| 131 | * @throws IllegalArgumentException If the number of bands in the | ||
| 132 | * source or destination is incompatible with the matrix. | ||
| 133 | */ | ||
| 134 | public WritableRaster filter(Raster src, WritableRaster dst) { | ||
| 135 | int nBands = src.getNumBands(); | ||
| 136 | if (ncols != nBands && ncols != (nBands+1)) { | ||
| 137 | throw new IllegalArgumentException("Number of columns in the "+ | ||
| 138 | "matrix ("+ncols+ | ||
| 139 | ") must be equal to the number"+ | ||
| 140 | " of bands ([+1]) in src ("+ | ||
| 141 | nBands+")."); | ||
| 142 | } | ||
| 143 | if (dst == null) { | ||
| 144 | dst = createCompatibleDestRaster(src); | ||
| 145 | } | ||
| 146 | else if (nrows != dst.getNumBands()) { | ||
| 147 | throw new IllegalArgumentException("Number of rows in the "+ | ||
| 148 | "matrix ("+nrows+ | ||
| 149 | ") must be equal to the number"+ | ||
| 150 | " of bands ([+1]) in dst ("+ | ||
| 151 | nBands+")."); | ||
| 152 | } | ||
| 153 | |||
| 154 | if (ImagingLib.filter(this, src, dst) != null) { | ||
| 155 | return dst; | ||
| 156 | } | ||
| 157 | |||
| 158 | int[] pixel = null; | ||
| 159 | int[] dstPixel = new int[dst.getNumBands()]; | ||
| 160 | float accum; | ||
| 161 | int sminX = src.getMinX(); | ||
| 162 | int sY = src.getMinY(); | ||
| 163 | int dminX = dst.getMinX(); | ||
| 164 | int dY = dst.getMinY(); | ||
| 165 | int sX; | ||
| 166 | int dX; | ||
| 167 | if (ncols == nBands) { | ||
| 168 | for (int y=0; y < src.getHeight(); y++, sY++, dY++) { | ||
| 169 | dX = dminX; | ||
| 170 | sX = sminX; | ||
| 171 | for (int x=0; x < src.getWidth(); x++, sX++, dX++) { | ||
| 172 | pixel = src.getPixel(sX, sY, pixel); | ||
| 173 | for (int r=0; r < nrows; r++) { | ||
| 174 | accum = 0.f; | ||
| 175 | for (int c=0; c < ncols; c++) { | ||
| 176 | accum += matrix[r][c]*pixel[c]; | ||
| 177 | } | ||
| 178 | dstPixel[r] = (int) accum; | ||
| 179 | } | ||
| 180 | dst.setPixel(dX, dY, dstPixel); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | } | ||
| 184 | else { | ||
| 185 | // Need to add constant | ||
| 186 | for (int y=0; y < src.getHeight(); y++, sY++, dY++) { | ||
| 187 | dX = dminX; | ||
| 188 | sX = sminX; | ||
| 189 | for (int x=0; x < src.getWidth(); x++, sX++, dX++) { | ||
| 190 | pixel = src.getPixel(sX, sY, pixel); | ||
| 191 | for (int r=0; r < nrows; r++) { | ||
| 192 | accum = 0.f; | ||
| 193 | for (int c=0; c < nBands; c++) { | ||
| 194 | accum += matrix[r][c]*pixel[c]; | ||
| 195 | } | ||
| 196 | dstPixel[r] = (int) (accum+matrix[r][nBands]); | ||
| 197 | } | ||
| 198 | dst.setPixel(dX, dY, dstPixel); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | return dst; | ||
| 204 | } | ||
| 205 | |||
| 206 | /** | ||
| 207 | * Returns the bounding box of the transformed destination. Since | ||
| 208 | * this is not a geometric operation, the bounding box is the same for | ||
| 209 | * the source and destination. | ||
| 210 | * An <CODE>IllegalArgumentException</CODE> may be thrown if the number of | ||
| 211 | * bands in the source is incompatible with the matrix. See | ||
| 212 | * the class comments for more details. | ||
| 213 | * | ||
| 214 | * @param src The <CODE>Raster</CODE> to be filtered. | ||
| 215 | * | ||
| 216 | * @return The <CODE>Rectangle2D</CODE> representing the destination | ||
| 217 | * image's bounding box. | ||
| 218 | * | ||
| 219 | * @throws IllegalArgumentException If the number of bands in the source | ||
| 220 | * is incompatible with the matrix. | ||
| 221 | */ | ||
| 222 | public final Rectangle2D getBounds2D (Raster src) { | ||
| 223 | return src.getBounds(); | ||
| 224 | } | ||
| 225 | |||
| 226 | |||
| 227 | /** | ||
| 228 | * Creates a zeroed destination <CODE>Raster</CODE> with the correct size | ||
| 229 | * and number of bands. | ||
| 230 | * An <CODE>IllegalArgumentException</CODE> may be thrown if the number of | ||
| 231 | * bands in the source is incompatible with the matrix. See | ||
| 232 | * the class comments for more details. | ||
| 233 | * | ||
| 234 | * @param src The <CODE>Raster</CODE> to be filtered. | ||
| 235 | * | ||
| 236 | * @return The zeroed destination <CODE>Raster</CODE>. | ||
| 237 | */ | ||
| 238 | public WritableRaster createCompatibleDestRaster (Raster src) { | ||
| 239 | int nBands = src.getNumBands(); | ||
| 240 | if ((ncols != nBands) && (ncols != (nBands+1))) { | ||
| 241 | throw new IllegalArgumentException("Number of columns in the "+ | ||
| 242 | "matrix ("+ncols+ | ||
| 243 | ") must be equal to the number"+ | ||
| 244 | " of bands ([+1]) in src ("+ | ||
| 245 | nBands+")."); | ||
| 246 | } | ||
| 247 | if (src.getNumBands() == nrows) { | ||
| 248 | return src.createCompatibleWritableRaster(); | ||
| 249 | } | ||
| 250 | else { | ||
| 251 | throw new IllegalArgumentException("Don't know how to create a "+ | ||
| 252 | " compatible Raster with "+ | ||
| 253 | nrows+" bands."); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | /** | ||
| 258 | * Returns the location of the corresponding destination point given a | ||
| 259 | * point in the source <CODE>Raster</CODE>. If <CODE>dstPt</CODE> is | ||
| 260 | * specified, it is used to hold the return value. | ||
| 261 | * Since this is not a geometric operation, the point returned | ||
| 262 | * is the same as the specified <CODE>srcPt</CODE>. | ||
| 263 | * | ||
| 264 | * @param srcPt The <code>Point2D</code> that represents the point in | ||
| 265 | * the source <code>Raster</code> | ||
| 266 | * @param dstPt The <CODE>Point2D</CODE> in which to store the result. | ||
| 267 | * | ||
| 268 | * @return The <CODE>Point2D</CODE> in the destination image that | ||
| 269 | * corresponds to the specified point in the source image. | ||
| 270 | */ | ||
| 271 | public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) { | ||
| 272 | if (dstPt == null) { | ||
| 273 | dstPt = new Point2D.Float(); | ||
| 274 | } | ||
| 275 | dstPt.setLocation(srcPt.getX(), srcPt.getY()); | ||
| 276 | |||
| 277 | return dstPt; | ||
| 278 | } | ||
| 279 | |||
| 280 | /** | ||
| 281 | * Returns the rendering hints for this operation. | ||
| 282 | * | ||
| 283 | * @return The <CODE>RenderingHints</CODE> object associated with this | ||
| 284 | * operation. Returns null if no hints have been set. | ||
| 285 | */ | ||
| 286 | public final RenderingHints getRenderingHints() { | ||
| 287 | return hints; | ||
| 288 | } | ||
| 289 | } | ||
Binary file not shown.
| @@ -0,0 +1,849 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 | /* **************************************************************** | ||
| 27 | ****************************************************************** | ||
| 28 | ****************************************************************** | ||
| 29 | *** COPYRIGHT (c) Eastman Kodak Company, 1997 | ||
| 30 | *** As an unpublished work pursuant to Title 17 of the United | ||
| 31 | *** States Code. All rights reserved. | ||
| 32 | ****************************************************************** | ||
| 33 | ****************************************************************** | ||
| 34 | ******************************************************************/ | ||
| 35 | |||
| 36 | package java.awt.image; | ||
| 37 | |||
| 38 | /** | ||
| 39 | * This class represents image data which is stored in a band interleaved | ||
| 40 | * fashion and for | ||
| 41 | * which each sample of a pixel occupies one data element of the DataBuffer. | ||
| 42 | * It subclasses ComponentSampleModel but provides a more efficent | ||
| 43 | * implementation for accessing band interleaved image data than is provided | ||
| 44 | * by ComponentSampleModel. This class should typically be used when working | ||
| 45 | * with images which store sample data for each band in a different bank of the | ||
| 46 | * DataBuffer. Accessor methods are provided so that image data can be | ||
| 47 | * manipulated directly. Pixel stride is the number of | ||
| 48 | * data array elements between two samples for the same band on the same | ||
| 49 | * scanline. The pixel stride for a BandedSampleModel is one. | ||
| 50 | * Scanline stride is the number of data array elements between | ||
| 51 | * a given sample and the corresponding sample in the same column of the next | ||
| 52 | * scanline. Band offsets denote the number | ||
| 53 | * of data array elements from the first data array element of the bank | ||
| 54 | * of the DataBuffer holding each band to the first sample of the band. | ||
| 55 | * The bands are numbered from 0 to N-1. | ||
| 56 | * Bank indices denote the correspondence between a bank of the data buffer | ||
| 57 | * and a band of image data. This class supports | ||
| 58 | * {@link DataBuffer#TYPE_BYTE TYPE_BYTE}, | ||
| 59 | * {@link DataBuffer#TYPE_USHORT TYPE_USHORT}, | ||
| 60 | * {@link DataBuffer#TYPE_SHORT TYPE_SHORT}, | ||
| 61 | * {@link DataBuffer#TYPE_INT TYPE_INT}, | ||
| 62 | * {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT}, and | ||
| 63 | * {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE} datatypes | ||
| 64 | */ | ||
| 65 | |||
| 66 | |||
| 67 | public final class BandedSampleModel extends ComponentSampleModel | ||
| 68 | { | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Constructs a BandedSampleModel with the specified parameters. | ||
| 72 | * The pixel stride will be one data element. The scanline stride | ||
| 73 | * will be the same as the width. Each band will be stored in | ||
| 74 | * a separate bank and all band offsets will be zero. | ||
| 75 | * @param dataType The data type for storing samples. | ||
| 76 | * @param w The width (in pixels) of the region of | ||
| 77 | * image data described. | ||
| 78 | * @param h The height (in pixels) of the region of image | ||
| 79 | * data described. | ||
| 80 | * @param numBands The number of bands for the image data. | ||
| 81 | * @throws IllegalArgumentException if <code>dataType</code> is not | ||
| 82 | * one of the supported data types | ||
| 83 | */ | ||
| 84 | public BandedSampleModel(int dataType, int w, int h, int numBands) { | ||
| 85 | super(dataType, w, h, 1, w, | ||
| 86 | BandedSampleModel.createIndicesArray(numBands), | ||
| 87 | BandedSampleModel.createOffsetArray(numBands)); | ||
| 88 | } | ||
| 89 | |||
| 90 | /** | ||
| 91 | * Constructs a BandedSampleModel with the specified parameters. | ||
| 92 | * The number of bands will be inferred from the lengths of the | ||
| 93 | * bandOffsets bankIndices arrays, which must be equal. The pixel | ||
| 94 | * stride will be one data element. | ||
| 95 | * @param dataType The data type for storing samples. | ||
| 96 | * @param w The width (in pixels) of the region of | ||
| 97 | * image data described. | ||
| 98 | * @param h The height (in pixels) of the region of | ||
| 99 | * image data described. | ||
| 100 | * @param scanlineStride The line stride of the of the image data. | ||
| 101 | * @param bankIndices The bank index for each band. | ||
| 102 | * @param bandOffsets The band offset for each band. | ||
| 103 | * @throws IllegalArgumentException if <code>dataType</code> is not | ||
| 104 | * one of the supported data types | ||
| 105 | */ | ||
| 106 | public BandedSampleModel(int dataType, | ||
| 107 | int w, int h, | ||
| 108 | int scanlineStride, | ||
| 109 | int bankIndices[], | ||
| 110 | int bandOffsets[]) { | ||
| 111 | |||
| 112 | super(dataType, w, h, 1,scanlineStride, bankIndices, bandOffsets); | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Creates a new BandedSampleModel with the specified | ||
| 117 | * width and height. The new BandedSampleModel will have the same | ||
| 118 | * number of bands, storage data type, and bank indices | ||
| 119 | * as this BandedSampleModel. The band offsets will be compressed | ||
| 120 | * such that the offset between bands will be w*pixelStride and | ||
| 121 | * the minimum of all of the band offsets is zero. | ||
| 122 | * @param w the width of the resulting <code>BandedSampleModel</code> | ||
| 123 | * @param h the height of the resulting <code>BandedSampleModel</code> | ||
| 124 | * @return a new <code>BandedSampleModel</code> with the specified | ||
| 125 | * width and height. | ||
| 126 | * @throws IllegalArgumentException if <code>w</code> or | ||
| 127 | * <code>h</code> equals either | ||
| 128 | * <code>Integer.MAX_VALUE</code> or | ||
| 129 | * <code>Integer.MIN_VALUE</code> | ||
| 130 | * @throws IllegalArgumentException if <code>dataType</code> is not | ||
| 131 | * one of the supported data types | ||
| 132 | */ | ||
| 133 | public SampleModel createCompatibleSampleModel(int w, int h) { | ||
| 134 | int[] bandOffs; | ||
| 135 | |||
| 136 | if (numBanks == 1) { | ||
| 137 | bandOffs = orderBands(bandOffsets, w*h); | ||
| 138 | } | ||
| 139 | else { | ||
| 140 | bandOffs = new int[bandOffsets.length]; | ||
| 141 | } | ||
| 142 | |||
| 143 | SampleModel sampleModel = | ||
| 144 | new BandedSampleModel(dataType, w, h, w, bankIndices, bandOffs); | ||
| 145 | return sampleModel; | ||
| 146 | } | ||
| 147 | |||
| 148 | /** | ||
| 149 | * Creates a new BandedSampleModel with a subset of the bands of this | ||
| 150 | * BandedSampleModel. The new BandedSampleModel can be | ||
| 151 | * used with any DataBuffer that the existing BandedSampleModel | ||
| 152 | * can be used with. The new BandedSampleModel/DataBuffer | ||
| 153 | * combination will represent an image with a subset of the bands | ||
| 154 | * of the original BandedSampleModel/DataBuffer combination. | ||
| 155 | * @throws RasterFormatException if the number of bands is greater than | ||
| 156 | * the number of banks in this sample model. | ||
| 157 | * @throws IllegalArgumentException if <code>dataType</code> is not | ||
| 158 | * one of the supported data types | ||
| 159 | */ | ||
| 160 | public SampleModel createSubsetSampleModel(int bands[]) { | ||
| 161 | if (bands.length > bankIndices.length) | ||
| 162 | throw new RasterFormatException("There are only " + | ||
| 163 | bankIndices.length + | ||
| 164 | " bands"); | ||
| 165 | int newBankIndices[] = new int[bands.length]; | ||
| 166 | int newBandOffsets[] = new int[bands.length]; | ||
| 167 | |||
| 168 | for (int i=0; i<bands.length; i++) { | ||
| 169 | newBankIndices[i] = bankIndices[bands[i]]; | ||
| 170 | newBandOffsets[i] = bandOffsets[bands[i]]; | ||
| 171 | } | ||
| 172 | |||
| 173 | return new BandedSampleModel(this.dataType, width, height, | ||
| 174 | this.scanlineStride, | ||
| 175 | newBankIndices, newBandOffsets); | ||
| 176 | } | ||
| 177 | |||
| 178 | /** | ||
| 179 | * Creates a DataBuffer that corresponds to this BandedSampleModel, | ||
| 180 | * The DataBuffer's data type, number of banks, and size | ||
| 181 | * will be consistent with this BandedSampleModel. | ||
| 182 | * @throws IllegalArgumentException if <code>dataType</code> is not | ||
| 183 | * one of the supported types. | ||
| 184 | */ | ||
| 185 | public DataBuffer createDataBuffer() { | ||
| 186 | DataBuffer dataBuffer = null; | ||
| 187 | |||
| 188 | int size = scanlineStride * height; | ||
| 189 | switch (dataType) { | ||
| 190 | case DataBuffer.TYPE_BYTE: | ||
| 191 | dataBuffer = new DataBufferByte(size, numBanks); | ||
| 192 | break; | ||
| 193 | case DataBuffer.TYPE_USHORT: | ||
| 194 | dataBuffer = new DataBufferUShort(size, numBanks); | ||
| 195 | break; | ||
| 196 | case DataBuffer.TYPE_SHORT: | ||
| 197 | dataBuffer = new DataBufferShort(size, numBanks); | ||
| 198 | break; | ||
| 199 | case DataBuffer.TYPE_INT: | ||
| 200 | dataBuffer = new DataBufferInt(size, numBanks); | ||
| 201 | break; | ||
| 202 | case DataBuffer.TYPE_FLOAT: | ||
| 203 | dataBuffer = new DataBufferFloat(size, numBanks); | ||
| 204 | break; | ||
| 205 | case DataBuffer.TYPE_DOUBLE: | ||
| 206 | dataBuffer = new DataBufferDouble(size, numBanks); | ||
| 207 | break; | ||
| 208 | default: | ||
| 209 | throw new IllegalArgumentException("dataType is not one " + | ||
| 210 | "of the supported types."); | ||
| 211 | } | ||
| 212 | |||
| 213 | return dataBuffer; | ||
| 214 | } | ||
| 215 | |||
| 216 | |||
| 217 | /** | ||
| 218 | * Returns data for a single pixel in a primitive array of type | ||
| 219 | * TransferType. For a BandedSampleModel, this will be the same | ||
| 220 | * as the data type, and samples will be returned one per array | ||
| 221 | * element. Generally, obj | ||
| 222 | * should be passed in as null, so that the Object will be created | ||
| 223 | * automatically and will be of the right primitive data type. | ||
| 224 | * <p> | ||
| 225 | * The following code illustrates transferring data for one pixel from | ||
| 226 | * DataBuffer <code>db1</code>, whose storage layout is described by | ||
| 227 | * BandedSampleModel <code>bsm1</code>, to DataBuffer <code>db2</code>, | ||
| 228 | * whose storage layout is described by | ||
| 229 | * BandedSampleModel <code>bsm2</code>. | ||
| 230 | * The transfer will generally be more efficient than using | ||
| 231 | * getPixel/setPixel. | ||
| 232 | * <pre> | ||
| 233 | * BandedSampleModel bsm1, bsm2; | ||
| 234 | * DataBufferInt db1, db2; | ||
| 235 | * bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1), | ||
| 236 | * db2); | ||
| 237 | * </pre> | ||
| 238 | * Using getDataElements/setDataElements to transfer between two | ||
| 239 | * DataBuffer/SampleModel pairs is legitimate if the SampleModels have | ||
| 240 | * the same number of bands, corresponding bands have the same number of | ||
| 241 | * bits per sample, and the TransferTypes are the same. | ||
| 242 | * <p> | ||
| 243 | * If obj is non-null, it should be a primitive array of type TransferType. | ||
| 244 | * Otherwise, a ClassCastException is thrown. An | ||
| 245 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 246 | * not in bounds, or if obj is non-null and is not large enough to hold | ||
| 247 | * the pixel data. | ||
| 248 | * @param x The X coordinate of the pixel location | ||
| 249 | * @param y The Y coordinate of the pixel location | ||
| 250 | * @param obj If non-null, a primitive array in which to return | ||
| 251 | * the pixel data. | ||
| 252 | * @param data The DataBuffer containing the image data. | ||
| 253 | * @return the data for the specified pixel. | ||
| 254 | * @see #setDataElements(int, int, Object, DataBuffer) | ||
| 255 | */ | ||
| 256 | public Object getDataElements(int x, int y, Object obj, DataBuffer data) { | ||
| 257 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 258 | throw new ArrayIndexOutOfBoundsException | ||
| 259 | ("Coordinate out of bounds!"); | ||
| 260 | } | ||
| 261 | int type = getTransferType(); | ||
| 262 | int numDataElems = getNumDataElements(); | ||
| 263 | int pixelOffset = y*scanlineStride + x; | ||
| 264 | |||
| 265 | switch(type) { | ||
| 266 | |||
| 267 | case DataBuffer.TYPE_BYTE: | ||
| 268 | |||
| 269 | byte[] bdata; | ||
| 270 | |||
| 271 | if (obj == null) { | ||
| 272 | bdata = new byte[numDataElems]; | ||
| 273 | } else { | ||
| 274 | bdata = (byte[])obj; | ||
| 275 | } | ||
| 276 | |||
| 277 | for (int i=0; i<numDataElems; i++) { | ||
| 278 | bdata[i] = (byte)data.getElem(bankIndices[i], | ||
| 279 | pixelOffset + bandOffsets[i]); | ||
| 280 | } | ||
| 281 | |||
| 282 | obj = (Object)bdata; | ||
| 283 | break; | ||
| 284 | |||
| 285 | case DataBuffer.TYPE_USHORT: | ||
| 286 | case DataBuffer.TYPE_SHORT: | ||
| 287 | |||
| 288 | short[] sdata; | ||
| 289 | |||
| 290 | if (obj == null) { | ||
| 291 | sdata = new short[numDataElems]; | ||
| 292 | } else { | ||
| 293 | sdata = (short[])obj; | ||
| 294 | } | ||
| 295 | |||
| 296 | for (int i=0; i<numDataElems; i++) { | ||
| 297 | sdata[i] = (short)data.getElem(bankIndices[i], | ||
| 298 | pixelOffset + bandOffsets[i]); | ||
| 299 | } | ||
| 300 | |||
| 301 | obj = (Object)sdata; | ||
| 302 | break; | ||
| 303 | |||
| 304 | case DataBuffer.TYPE_INT: | ||
| 305 | |||
| 306 | int[] idata; | ||
| 307 | |||
| 308 | if (obj == null) { | ||
| 309 | idata = new int[numDataElems]; | ||
| 310 | } else { | ||
| 311 | idata = (int[])obj; | ||
| 312 | } | ||
| 313 | |||
| 314 | for (int i=0; i<numDataElems; i++) { | ||
| 315 | idata[i] = data.getElem(bankIndices[i], | ||
| 316 | pixelOffset + bandOffsets[i]); | ||
| 317 | } | ||
| 318 | |||
| 319 | obj = (Object)idata; | ||
| 320 | break; | ||
| 321 | |||
| 322 | case DataBuffer.TYPE_FLOAT: | ||
| 323 | |||
| 324 | float[] fdata; | ||
| 325 | |||
| 326 | if (obj == null) { | ||
| 327 | fdata = new float[numDataElems]; | ||
| 328 | } else { | ||
| 329 | fdata = (float[])obj; | ||
| 330 | } | ||
| 331 | |||
| 332 | for (int i=0; i<numDataElems; i++) { | ||
| 333 | fdata[i] = data.getElemFloat(bankIndices[i], | ||
| 334 | pixelOffset + bandOffsets[i]); | ||
| 335 | } | ||
| 336 | |||
| 337 | obj = (Object)fdata; | ||
| 338 | break; | ||
| 339 | |||
| 340 | case DataBuffer.TYPE_DOUBLE: | ||
| 341 | |||
| 342 | double[] ddata; | ||
| 343 | |||
| 344 | if (obj == null) { | ||
| 345 | ddata = new double[numDataElems]; | ||
| 346 | } else { | ||
| 347 | ddata = (double[])obj; | ||
| 348 | } | ||
| 349 | |||
| 350 | for (int i=0; i<numDataElems; i++) { | ||
| 351 | ddata[i] = data.getElemDouble(bankIndices[i], | ||
| 352 | pixelOffset + bandOffsets[i]); | ||
| 353 | } | ||
| 354 | |||
| 355 | obj = (Object)ddata; | ||
| 356 | break; | ||
| 357 | } | ||
| 358 | |||
| 359 | return obj; | ||
| 360 | } | ||
| 361 | |||
| 362 | /** | ||
| 363 | * Returns all samples for the specified pixel in an int array. | ||
| 364 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 365 | * not in bounds. | ||
| 366 | * @param x The X coordinate of the pixel location | ||
| 367 | * @param y The Y coordinate of the pixel location | ||
| 368 | * @param iArray If non-null, returns the samples in this array | ||
| 369 | * @param data The DataBuffer containing the image data | ||
| 370 | * @return the samples for the specified pixel. | ||
| 371 | * @see #setPixel(int, int, int[], DataBuffer) | ||
| 372 | */ | ||
| 373 | public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { | ||
| 374 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 375 | throw new ArrayIndexOutOfBoundsException | ||
| 376 | ("Coordinate out of bounds!"); | ||
| 377 | } | ||
| 378 | |||
| 379 | int[] pixels; | ||
| 380 | |||
| 381 | if (iArray != null) { | ||
| 382 | pixels = iArray; | ||
| 383 | } else { | ||
| 384 | pixels = new int [numBands]; | ||
| 385 | } | ||
| 386 | |||
| 387 | int pixelOffset = y*scanlineStride + x; | ||
| 388 | for (int i=0; i<numBands; i++) { | ||
| 389 | pixels[i] = data.getElem(bankIndices[i], | ||
| 390 | pixelOffset + bandOffsets[i]); | ||
| 391 | } | ||
| 392 | return pixels; | ||
| 393 | } | ||
| 394 | |||
| 395 | /** | ||
| 396 | * Returns all samples for the specified rectangle of pixels in | ||
| 397 | * an int array, one sample per data array element. | ||
| 398 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 399 | * not in bounds. | ||
| 400 | * @param x The X coordinate of the upper left pixel location | ||
| 401 | * @param y The Y coordinate of the upper left pixel location | ||
| 402 | * @param w The width of the pixel rectangle | ||
| 403 | * @param h The height of the pixel rectangle | ||
| 404 | * @param iArray If non-null, returns the samples in this array | ||
| 405 | * @param data The DataBuffer containing the image data | ||
| 406 | * @return the samples for the pixels within the specified region. | ||
| 407 | * @see #setPixels(int, int, int, int, int[], DataBuffer) | ||
| 408 | */ | ||
| 409 | public int[] getPixels(int x, int y, int w, int h, | ||
| 410 | int iArray[], DataBuffer data) { | ||
| 411 | int x1 = x + w; | ||
| 412 | int y1 = y + h; | ||
| 413 | |||
| 414 | if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || | ||
| 415 | y < 0 || y >= height || h > height || y1 < 0 || y1 > height) | ||
| 416 | { | ||
| 417 | throw new ArrayIndexOutOfBoundsException | ||
| 418 | ("Coordinate out of bounds!"); | ||
| 419 | } | ||
| 420 | int[] pixels; | ||
| 421 | |||
| 422 | if (iArray != null) { | ||
| 423 | pixels = iArray; | ||
| 424 | } else { | ||
| 425 | pixels = new int[w*h*numBands]; | ||
| 426 | } | ||
| 427 | |||
| 428 | for (int k = 0; k < numBands; k++) { | ||
| 429 | int lineOffset = y*scanlineStride + x + bandOffsets[k]; | ||
| 430 | int srcOffset = k; | ||
| 431 | int bank = bankIndices[k]; | ||
| 432 | |||
| 433 | for (int i = 0; i < h; i++) { | ||
| 434 | int pixelOffset = lineOffset; | ||
| 435 | for (int j = 0; j < w; j++) { | ||
| 436 | pixels[srcOffset] = data.getElem(bank, pixelOffset++); | ||
| 437 | srcOffset += numBands; | ||
| 438 | } | ||
| 439 | lineOffset += scanlineStride; | ||
| 440 | } | ||
| 441 | } | ||
| 442 | return pixels; | ||
| 443 | } | ||
| 444 | |||
| 445 | /** | ||
| 446 | * Returns as int the sample in a specified band for the pixel | ||
| 447 | * located at (x,y). | ||
| 448 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 449 | * not in bounds. | ||
| 450 | * @param x The X coordinate of the pixel location | ||
| 451 | * @param y The Y coordinate of the pixel location | ||
| 452 | * @param b The band to return | ||
| 453 | * @param data The DataBuffer containing the image data | ||
| 454 | * @return the sample in the specified band for the specified pixel. | ||
| 455 | * @see #setSample(int, int, int, int, DataBuffer) | ||
| 456 | */ | ||
| 457 | public int getSample(int x, int y, int b, DataBuffer data) { | ||
| 458 | // Bounds check for 'b' will be performed automatically | ||
| 459 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 460 | throw new ArrayIndexOutOfBoundsException | ||
| 461 | ("Coordinate out of bounds!"); | ||
| 462 | } | ||
| 463 | int sample = | ||
| 464 | data.getElem(bankIndices[b], | ||
| 465 | y*scanlineStride + x + bandOffsets[b]); | ||
| 466 | return sample; | ||
| 467 | } | ||
| 468 | |||
| 469 | /** | ||
| 470 | * Returns the sample in a specified band | ||
| 471 | * for the pixel located at (x,y) as a float. | ||
| 472 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 473 | * not in bounds. | ||
| 474 | * @param x The X coordinate of the pixel location | ||
| 475 | * @param y The Y coordinate of the pixel location | ||
| 476 | * @param b The band to return | ||
| 477 | * @param data The DataBuffer containing the image data | ||
| 478 | * @return a float value that represents the sample in the specified | ||
| 479 | * band for the specified pixel. | ||
| 480 | */ | ||
| 481 | public float getSampleFloat(int x, int y, int b, DataBuffer data) { | ||
| 482 | // Bounds check for 'b' will be performed automatically | ||
| 483 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 484 | throw new ArrayIndexOutOfBoundsException | ||
| 485 | ("Coordinate out of bounds!"); | ||
| 486 | } | ||
| 487 | |||
| 488 | float sample = data.getElemFloat(bankIndices[b], | ||
| 489 | y*scanlineStride + x + bandOffsets[b]); | ||
| 490 | return sample; | ||
| 491 | } | ||
| 492 | |||
| 493 | /** | ||
| 494 | * Returns the sample in a specified band | ||
| 495 | * for a pixel located at (x,y) as a double. | ||
| 496 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 497 | * not in bounds. | ||
| 498 | * @param x The X coordinate of the pixel location | ||
| 499 | * @param y The Y coordinate of the pixel location | ||
| 500 | * @param b The band to return | ||
| 501 | * @param data The DataBuffer containing the image data | ||
| 502 | * @return a double value that represents the sample in the specified | ||
| 503 | * band for the specified pixel. | ||
| 504 | */ | ||
| 505 | public double getSampleDouble(int x, int y, int b, DataBuffer data) { | ||
| 506 | // Bounds check for 'b' will be performed automatically | ||
| 507 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 508 | throw new ArrayIndexOutOfBoundsException | ||
| 509 | ("Coordinate out of bounds!"); | ||
| 510 | } | ||
| 511 | |||
| 512 | double sample = data.getElemDouble(bankIndices[b], | ||
| 513 | y*scanlineStride + x + bandOffsets[b]); | ||
| 514 | return sample; | ||
| 515 | } | ||
| 516 | |||
| 517 | /** | ||
| 518 | * Returns the samples in a specified band for the specified rectangle | ||
| 519 | * of pixels in an int array, one sample per data array element. | ||
| 520 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 521 | * not in bounds. | ||
| 522 | * @param x The X coordinate of the upper left pixel location | ||
| 523 | * @param y The Y coordinate of the upper left pixel location | ||
| 524 | * @param w The width of the pixel rectangle | ||
| 525 | * @param h The height of the pixel rectangle | ||
| 526 | * @param b The band to return | ||
| 527 | * @param iArray If non-null, returns the samples in this array | ||
| 528 | * @param data The DataBuffer containing the image data | ||
| 529 | * @return the samples in the specified band for the pixels within | ||
| 530 | * the specified region. | ||
| 531 | * @see #setSamples(int, int, int, int, int, int[], DataBuffer) | ||
| 532 | */ | ||
| 533 | public int[] getSamples(int x, int y, int w, int h, int b, | ||
| 534 | int iArray[], DataBuffer data) { | ||
| 535 | // Bounds check for 'b' will be performed automatically | ||
| 536 | if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { | ||
| 537 | throw new ArrayIndexOutOfBoundsException | ||
| 538 | ("Coordinate out of bounds!"); | ||
| 539 | } | ||
| 540 | int samples[]; | ||
| 541 | if (iArray != null) { | ||
| 542 | samples = iArray; | ||
| 543 | } else { | ||
| 544 | samples = new int [w*h]; | ||
| 545 | } | ||
| 546 | |||
| 547 | int lineOffset = y*scanlineStride + x + bandOffsets[b]; | ||
| 548 | int srcOffset = 0; | ||
| 549 | int bank = bankIndices[b]; | ||
| 550 | |||
| 551 | for (int i = 0; i < h; i++) { | ||
| 552 | int sampleOffset = lineOffset; | ||
| 553 | for (int j = 0; j < w; j++) { | ||
| 554 | samples[srcOffset++] = data.getElem(bank, sampleOffset++); | ||
| 555 | } | ||
| 556 | lineOffset += scanlineStride; | ||
| 557 | } | ||
| 558 | return samples; | ||
| 559 | } | ||
| 560 | |||
| 561 | /** | ||
| 562 | * Sets the data for a single pixel in the specified DataBuffer from a | ||
| 563 | * primitive array of type TransferType. For a BandedSampleModel, | ||
| 564 | * this will be the same as the data type, and samples are transferred | ||
| 565 | * one per array element. | ||
| 566 | * <p> | ||
| 567 | * The following code illustrates transferring data for one pixel from | ||
| 568 | * DataBuffer <code>db1</code>, whose storage layout is described by | ||
| 569 | * BandedSampleModel <code>bsm1</code>, to DataBuffer <code>db2</code>, | ||
| 570 | * whose storage layout is described by | ||
| 571 | * BandedSampleModel <code>bsm2</code>. | ||
| 572 | * The transfer will generally be more efficient than using | ||
| 573 | * getPixel/setPixel. | ||
| 574 | * <pre> | ||
| 575 | * BandedSampleModel bsm1, bsm2; | ||
| 576 | * DataBufferInt db1, db2; | ||
| 577 | * bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1), | ||
| 578 | * db2); | ||
| 579 | * </pre> | ||
| 580 | * Using getDataElements/setDataElements to transfer between two | ||
| 581 | * DataBuffer/SampleModel pairs is legitimate if the SampleModels have | ||
| 582 | * the same number of bands, corresponding bands have the same number of | ||
| 583 | * bits per sample, and the TransferTypes are the same. | ||
| 584 | * <p> | ||
| 585 | * obj must be a primitive array of type TransferType. Otherwise, | ||
| 586 | * a ClassCastException is thrown. An | ||
| 587 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 588 | * not in bounds, or if obj is not large enough to hold the pixel data. | ||
| 589 | * @param x The X coordinate of the pixel location | ||
| 590 | * @param y The Y coordinate of the pixel location | ||
| 591 | * @param obj If non-null, returns the primitive array in this | ||
| 592 | * object | ||
| 593 | * @param data The DataBuffer containing the image data | ||
| 594 | * @see #getDataElements(int, int, Object, DataBuffer) | ||
| 595 | */ | ||
| 596 | public void setDataElements(int x, int y, Object obj, DataBuffer data) { | ||
| 597 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 598 | throw new ArrayIndexOutOfBoundsException | ||
| 599 | ("Coordinate out of bounds!"); | ||
| 600 | } | ||
| 601 | int type = getTransferType(); | ||
| 602 | int numDataElems = getNumDataElements(); | ||
| 603 | int pixelOffset = y*scanlineStride + x; | ||
| 604 | |||
| 605 | switch(type) { | ||
| 606 | |||
| 607 | case DataBuffer.TYPE_BYTE: | ||
| 608 | |||
| 609 | byte[] barray = (byte[])obj; | ||
| 610 | |||
| 611 | for (int i=0; i<numDataElems; i++) { | ||
| 612 | data.setElem(bankIndices[i], pixelOffset + bandOffsets[i], | ||
| 613 | barray[i] & 0xff); | ||
| 614 | } | ||
| 615 | break; | ||
| 616 | |||
| 617 | case DataBuffer.TYPE_USHORT: | ||
| 618 | case DataBuffer.TYPE_SHORT: | ||
| 619 | |||
| 620 | short[] sarray = (short[])obj; | ||
| 621 | |||
| 622 | for (int i=0; i<numDataElems; i++) { | ||
| 623 | data.setElem(bankIndices[i], pixelOffset + bandOffsets[i], | ||
| 624 | sarray[i] & 0xffff); | ||
| 625 | } | ||
| 626 | break; | ||
| 627 | |||
| 628 | case DataBuffer.TYPE_INT: | ||
| 629 | |||
| 630 | int[] iarray = (int[])obj; | ||
| 631 | |||
| 632 | for (int i=0; i<numDataElems; i++) { | ||
| 633 | data.setElem(bankIndices[i], pixelOffset + bandOffsets[i], | ||
| 634 | iarray[i]); | ||
| 635 | } | ||
| 636 | break; | ||
| 637 | |||
| 638 | case DataBuffer.TYPE_FLOAT: | ||
| 639 | |||
| 640 | float[] farray = (float[])obj; | ||
| 641 | |||
| 642 | for (int i=0; i<numDataElems; i++) { | ||
| 643 | data.setElemFloat(bankIndices[i], pixelOffset + bandOffsets[i], | ||
| 644 | farray[i]); | ||
| 645 | } | ||
| 646 | break; | ||
| 647 | |||
| 648 | case DataBuffer.TYPE_DOUBLE: | ||
| 649 | |||
| 650 | double[] darray = (double[])obj; | ||
| 651 | |||
| 652 | for (int i=0; i<numDataElems; i++) { | ||
| 653 | data.setElemDouble(bankIndices[i], pixelOffset + bandOffsets[i], | ||
| 654 | darray[i]); | ||
| 655 | } | ||
| 656 | break; | ||
| 657 | |||
| 658 | } | ||
| 659 | } | ||
| 660 | |||
| 661 | /** | ||
| 662 | * Sets a pixel in the DataBuffer using an int array of samples for input. | ||
| 663 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 664 | * not in bounds. | ||
| 665 | * @param x The X coordinate of the pixel location | ||
| 666 | * @param y The Y coordinate of the pixel location | ||
| 667 | * @param iArray The input samples in an int array | ||
| 668 | * @param data The DataBuffer containing the image data | ||
| 669 | * @see #getPixel(int, int, int[], DataBuffer) | ||
| 670 | */ | ||
| 671 | public void setPixel(int x, int y, int iArray[], DataBuffer data) { | ||
| 672 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 673 | throw new ArrayIndexOutOfBoundsException | ||
| 674 | ("Coordinate out of bounds!"); | ||
| 675 | } | ||
| 676 | int pixelOffset = y*scanlineStride + x; | ||
| 677 | for (int i=0; i<numBands; i++) { | ||
| 678 | data.setElem(bankIndices[i], pixelOffset + bandOffsets[i], | ||
| 679 | iArray[i]); | ||
| 680 | } | ||
| 681 | } | ||
| 682 | |||
| 683 | /** | ||
| 684 | * Sets all samples for a rectangle of pixels from an int array containing | ||
| 685 | * one sample per array element. | ||
| 686 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 687 | * not in bounds. | ||
| 688 | * @param x The X coordinate of the upper left pixel location | ||
| 689 | * @param y The Y coordinate of the upper left pixel location | ||
| 690 | * @param w The width of the pixel rectangle | ||
| 691 | * @param h The height of the pixel rectangle | ||
| 692 | * @param iArray The input samples in an int array | ||
| 693 | * @param data The DataBuffer containing the image data | ||
| 694 | * @see #getPixels(int, int, int, int, int[], DataBuffer) | ||
| 695 | */ | ||
| 696 | public void setPixels(int x, int y, int w, int h, | ||
| 697 | int iArray[], DataBuffer data) { | ||
| 698 | int x1 = x + w; | ||
| 699 | int y1 = y + h; | ||
| 700 | |||
| 701 | if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || | ||
| 702 | y < 0 || y >= height || h > height || y1 < 0 || y1 > height) | ||
| 703 | { | ||
| 704 | throw new ArrayIndexOutOfBoundsException | ||
| 705 | ("Coordinate out of bounds!"); | ||
| 706 | } | ||
| 707 | |||
| 708 | for (int k = 0; k < numBands; k++) { | ||
| 709 | int lineOffset = y*scanlineStride + x + bandOffsets[k]; | ||
| 710 | int srcOffset = k; | ||
| 711 | int bank = bankIndices[k]; | ||
| 712 | |||
| 713 | for (int i = 0; i < h; i++) { | ||
| 714 | int pixelOffset = lineOffset; | ||
| 715 | for (int j = 0; j < w; j++) { | ||
| 716 | data.setElem(bank, pixelOffset++, iArray[srcOffset]); | ||
| 717 | srcOffset += numBands; | ||
| 718 | } | ||
| 719 | lineOffset += scanlineStride; | ||
| 720 | } | ||
| 721 | } | ||
| 722 | } | ||
| 723 | |||
| 724 | /** | ||
| 725 | * Sets a sample in the specified band for the pixel located at (x,y) | ||
| 726 | * in the DataBuffer using an int for input. | ||
| 727 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 728 | * not in bounds. | ||
| 729 | * @param x The X coordinate of the pixel location | ||
| 730 | * @param y The Y coordinate of the pixel location | ||
| 731 | * @param b The band to set | ||
| 732 | * @param s The input sample as an int | ||
| 733 | * @param data The DataBuffer containing the image data | ||
| 734 | * @see #getSample(int, int, int, DataBuffer) | ||
| 735 | */ | ||
| 736 | public void setSample(int x, int y, int b, int s, | ||
| 737 | DataBuffer data) { | ||
| 738 | // Bounds check for 'b' will be performed automatically | ||
| 739 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 740 | throw new ArrayIndexOutOfBoundsException | ||
| 741 | ("Coordinate out of bounds!"); | ||
| 742 | } | ||
| 743 | data.setElem(bankIndices[b], | ||
| 744 | y*scanlineStride + x + bandOffsets[b], s); | ||
| 745 | } | ||
| 746 | |||
| 747 | /** | ||
| 748 | * Sets a sample in the specified band for the pixel located at (x,y) | ||
| 749 | * in the DataBuffer using a float for input. | ||
| 750 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 751 | * not in bounds. | ||
| 752 | * @param x The X coordinate of the pixel location | ||
| 753 | * @param y The Y coordinate of the pixel location | ||
| 754 | * @param b The band to set | ||
| 755 | * @param s The input sample as a float | ||
| 756 | * @param data The DataBuffer containing the image data | ||
| 757 | * @see #getSample(int, int, int, DataBuffer) | ||
| 758 | */ | ||
| 759 | public void setSample(int x, int y, int b, | ||
| 760 | float s , | ||
| 761 | DataBuffer data) { | ||
| 762 | // Bounds check for 'b' will be performed automatically | ||
| 763 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 764 | throw new ArrayIndexOutOfBoundsException | ||
| 765 | ("Coordinate out of bounds!"); | ||
| 766 | } | ||
| 767 | data.setElemFloat(bankIndices[b], | ||
| 768 | y*scanlineStride + x + bandOffsets[b], s); | ||
| 769 | } | ||
| 770 | |||
| 771 | /** | ||
| 772 | * Sets a sample in the specified band for the pixel located at (x,y) | ||
| 773 | * in the DataBuffer using a double for input. | ||
| 774 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 775 | * not in bounds. | ||
| 776 | * @param x The X coordinate of the pixel location | ||
| 777 | * @param y The Y coordinate of the pixel location | ||
| 778 | * @param b The band to set | ||
| 779 | * @param s The input sample as a double | ||
| 780 | * @param data The DataBuffer containing the image data | ||
| 781 | * @see #getSample(int, int, int, DataBuffer) | ||
| 782 | */ | ||
| 783 | public void setSample(int x, int y, int b, | ||
| 784 | double s, | ||
| 785 | DataBuffer data) { | ||
| 786 | // Bounds check for 'b' will be performed automatically | ||
| 787 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 788 | throw new ArrayIndexOutOfBoundsException | ||
| 789 | ("Coordinate out of bounds!"); | ||
| 790 | } | ||
| 791 | data.setElemDouble(bankIndices[b], | ||
| 792 | y*scanlineStride + x + bandOffsets[b], s); | ||
| 793 | } | ||
| 794 | |||
| 795 | /** | ||
| 796 | * Sets the samples in the specified band for the specified rectangle | ||
| 797 | * of pixels from an int array containing one sample per data array element. | ||
| 798 | * ArrayIndexOutOfBoundsException may be thrown if the coordinates are | ||
| 799 | * not in bounds. | ||
| 800 | * @param x The X coordinate of the upper left pixel location | ||
| 801 | * @param y The Y coordinate of the upper left pixel location | ||
| 802 | * @param w The width of the pixel rectangle | ||
| 803 | * @param h The height of the pixel rectangle | ||
| 804 | * @param b The band to set | ||
| 805 | * @param iArray The input sample array | ||
| 806 | * @param data The DataBuffer containing the image data | ||
| 807 | * @see #getSamples(int, int, int, int, int, int[], DataBuffer) | ||
| 808 | */ | ||
| 809 | public void setSamples(int x, int y, int w, int h, int b, | ||
| 810 | int iArray[], DataBuffer data) { | ||
| 811 | // Bounds check for 'b' will be performed automatically | ||
| 812 | if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { | ||
| 813 | throw new ArrayIndexOutOfBoundsException | ||
| 814 | ("Coordinate out of bounds!"); | ||
| 815 | } | ||
| 816 | int lineOffset = y*scanlineStride + x + bandOffsets[b]; | ||
| 817 | int srcOffset = 0; | ||
| 818 | int bank = bankIndices[b]; | ||
| 819 | |||
| 820 | for (int i = 0; i < h; i++) { | ||
| 821 | int sampleOffset = lineOffset; | ||
| 822 | for (int j = 0; j < w; j++) { | ||
| 823 | data.setElem(bank, sampleOffset++, iArray[srcOffset++]); | ||
| 824 | } | ||
| 825 | lineOffset += scanlineStride; | ||
| 826 | } | ||
| 827 | } | ||
| 828 | |||
| 829 | private static int[] createOffsetArray(int numBands) { | ||
| 830 | int[] bandOffsets = new int[numBands]; | ||
| 831 | for (int i=0; i < numBands; i++) { | ||
| 832 | bandOffsets[i] = 0; | ||
| 833 | } | ||
| 834 | return bandOffsets; | ||
| 835 | } | ||
| 836 | |||
| 837 | private static int[] createIndicesArray(int numBands) { | ||
| 838 | int[] bankIndices = new int[numBands]; | ||
| 839 | for (int i=0; i < numBands; i++) { | ||
| 840 | bankIndices[i] = i; | ||
| 841 | } | ||
| 842 | return bankIndices; | ||
| 843 | } | ||
| 844 | |||
| 845 | // Differentiate hash code from other ComponentSampleModel subclasses | ||
| 846 | public int hashCode() { | ||
| 847 | return super.hashCode() ^ 0x2; | ||
| 848 | } | ||
| 849 | } | ||
Binary file not shown.
| @@ -0,0 +1,205 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.BufferCapabilities; | ||
| 29 | import java.awt.Graphics; | ||
| 30 | import java.awt.Image; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * The <code>BufferStrategy</code> class represents the mechanism with which | ||
| 34 | * to organize complex memory on a particular <code>Canvas</code> or | ||
| 35 | * <code>Window</code>. Hardware and software limitations determine whether and | ||
| 36 | * how a particular buffer strategy can be implemented. These limitations | ||
| 37 | * are detectible through the capabilities of the | ||
| 38 | * <code>GraphicsConfiguration</code> used when creating the | ||
| 39 | * <code>Canvas</code> or <code>Window</code>. | ||
| 40 | * <p> | ||
| 41 | * It is worth noting that the terms <i>buffer</i> and <i>surface</i> are meant | ||
| 42 | * to be synonymous: an area of contiguous memory, either in video device | ||
| 43 | * memory or in system memory. | ||
| 44 | * <p> | ||
| 45 | * There are several types of complex buffer strategies, including | ||
| 46 | * sequential ring buffering and blit buffering. | ||
| 47 | * Sequential ring buffering (i.e., double or triple | ||
| 48 | * buffering) is the most common; an application draws to a single <i>back | ||
| 49 | * buffer</i> and then moves the contents to the front (display) in a single | ||
| 50 | * step, either by copying the data or moving the video pointer. | ||
| 51 | * Moving the video pointer exchanges the buffers so that the first buffer | ||
| 52 | * drawn becomes the <i>front buffer</i>, or what is currently displayed on the | ||
| 53 | * device; this is called <i>page flipping</i>. | ||
| 54 | * <p> | ||
| 55 | * Alternatively, the contents of the back buffer can be copied, or | ||
| 56 | * <i>blitted</i> forward in a chain instead of moving the video pointer. | ||
| 57 | * <p> | ||
| 58 | * <pre> | ||
| 59 | * Double buffering: | ||
| 60 | * | ||
| 61 | * *********** *********** | ||
| 62 | * * * ------> * * | ||
| 63 | * [To display] <---- * Front B * Show * Back B. * <---- Rendering | ||
| 64 | * * * <------ * * | ||
| 65 | * *********** *********** | ||
| 66 | * | ||
| 67 | * Triple buffering: | ||
| 68 | * | ||
| 69 | * [To *********** *********** *********** | ||
| 70 | * display] * * --------+---------+------> * * | ||
| 71 | * <---- * Front B * Show * Mid. B. * * Back B. * <---- Rendering | ||
| 72 | * * * <------ * * <----- * * | ||
| 73 | * *********** *********** *********** | ||
| 74 | * | ||
| 75 | * </pre> | ||
| 76 | * <p> | ||
| 77 | * Here is an example of how buffer strategies can be created and used: | ||
| 78 | * <pre><code> | ||
| 79 | * | ||
| 80 | * // Check the capabilities of the GraphicsConfiguration | ||
| 81 | * ... | ||
| 82 | * | ||
| 83 | * // Create our component | ||
| 84 | * Window w = new Window(gc); | ||
| 85 | * | ||
| 86 | * // Show our window | ||
| 87 | * w.setVisible(true); | ||
| 88 | * | ||
| 89 | * // Create a general double-buffering strategy | ||
| 90 | * w.createBufferStrategy(2); | ||
| 91 | * BufferStrategy strategy = w.getBufferStrategy(); | ||
| 92 | * | ||
| 93 | * // Main loop | ||
| 94 | * while (!done) { | ||
| 95 | * // Prepare for rendering the next frame | ||
| 96 | * // ... | ||
| 97 | * | ||
| 98 | * // Render single frame | ||
| 99 | * do { | ||
| 100 | * // The following loop ensures that the contents of the drawing buffer | ||
| 101 | * // are consistent in case the underlying surface was recreated | ||
| 102 | * do { | ||
| 103 | * // Get a new graphics context every time through the loop | ||
| 104 | * // to make sure the strategy is validated | ||
| 105 | * Graphics graphics = strategy.getDrawGraphics(); | ||
| 106 | * | ||
| 107 | * // Render to graphics | ||
| 108 | * // ... | ||
| 109 | * | ||
| 110 | * // Dispose the graphics | ||
| 111 | * graphics.dispose(); | ||
| 112 | * | ||
| 113 | * // Repeat the rendering if the drawing buffer contents | ||
| 114 | * // were restored | ||
| 115 | * } while (strategy.contentsRestored()); | ||
| 116 | * | ||
| 117 | * // Display the buffer | ||
| 118 | * strategy.show(); | ||
| 119 | * | ||
| 120 | * // Repeat the rendering if the drawing buffer was lost | ||
| 121 | * } while (strategy.contentsLost()); | ||
| 122 | * } | ||
| 123 | * | ||
| 124 | * // Dispose the window | ||
| 125 | * w.setVisible(false); | ||
| 126 | * w.dispose(); | ||
| 127 | * </code></pre> | ||
| 128 | * | ||
| 129 | * @see java.awt.Window | ||
| 130 | * @see java.awt.Canvas | ||
| 131 | * @see java.awt.GraphicsConfiguration | ||
| 132 | * @see VolatileImage | ||
| 133 | * @author Michael Martak | ||
| 134 | * @since 1.4 | ||
| 135 | */ | ||
| 136 | public abstract class BufferStrategy { | ||
| 137 | |||
| 138 | /** | ||
| 139 | * Returns the <code>BufferCapabilities</code> for this | ||
| 140 | * <code>BufferStrategy</code>. | ||
| 141 | * | ||
| 142 | * @return the buffering capabilities of this strategy | ||
| 143 | */ | ||
| 144 | public abstract BufferCapabilities getCapabilities(); | ||
| 145 | |||
| 146 | /** | ||
| 147 | * Creates a graphics context for the drawing buffer. This method may not | ||
| 148 | * be synchronized for performance reasons; use of this method by multiple | ||
| 149 | * threads should be handled at the application level. Disposal of the | ||
| 150 | * graphics object obtained must be handled by the application. | ||
| 151 | * | ||
| 152 | * @return a graphics context for the drawing buffer | ||
| 153 | */ | ||
| 154 | public abstract Graphics getDrawGraphics(); | ||
| 155 | |||
| 156 | /** | ||
| 157 | * Returns whether the drawing buffer was lost since the last call to | ||
| 158 | * <code>getDrawGraphics</code>. Since the buffers in a buffer strategy | ||
| 159 | * are usually type <code>VolatileImage</code>, they may become lost. | ||
| 160 | * For a discussion on lost buffers, see <code>VolatileImage</code>. | ||
| 161 | * | ||
| 162 | * @return Whether or not the drawing buffer was lost since the last call | ||
| 163 | * to <code>getDrawGraphics</code>. | ||
| 164 | * @see java.awt.image.VolatileImage | ||
| 165 | */ | ||
| 166 | public abstract boolean contentsLost(); | ||
| 167 | |||
| 168 | /** | ||
| 169 | * Returns whether the drawing buffer was recently restored from a lost | ||
| 170 | * state and reinitialized to the default background color (white). | ||
| 171 | * Since the buffers in a buffer strategy are usually type | ||
| 172 | * <code>VolatileImage</code>, they may become lost. If a surface has | ||
| 173 | * been recently restored from a lost state since the last call to | ||
| 174 | * <code>getDrawGraphics</code>, it may require repainting. | ||
| 175 | * For a discussion on lost buffers, see <code>VolatileImage</code>. | ||
| 176 | * | ||
| 177 | * @return Whether or not the drawing buffer was restored since the last | ||
| 178 | * call to <code>getDrawGraphics</code>. | ||
| 179 | * @see java.awt.image.VolatileImage | ||
| 180 | */ | ||
| 181 | public abstract boolean contentsRestored(); | ||
| 182 | |||
| 183 | /** | ||
| 184 | * Makes the next available buffer visible by either copying the memory | ||
| 185 | * (blitting) or changing the display pointer (flipping). | ||
| 186 | */ | ||
| 187 | public abstract void show(); | ||
| 188 | |||
| 189 | /** | ||
| 190 | * Releases system resources currently consumed by this | ||
| 191 | * <code>BufferStrategy</code> and | ||
| 192 | * removes it from the associated Component. After invoking this | ||
| 193 | * method, <code>getBufferStrategy</code> will return null. Trying | ||
| 194 | * to use a <code>BufferStrategy</code> after it has been disposed will | ||
| 195 | * result in undefined behavior. | ||
| 196 | * | ||
| 197 | * @see java.awt.Window#createBufferStrategy | ||
| 198 | * @see java.awt.Canvas#createBufferStrategy | ||
| 199 | * @see java.awt.Window#getBufferStrategy | ||
| 200 | * @see java.awt.Canvas#getBufferStrategy | ||
| 201 | * @since 1.6 | ||
| 202 | */ | ||
| 203 | public void dispose() { | ||
| 204 | } | ||
| 205 | } | ||
Binary file not shown.
| @@ -0,0 +1,1609 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.Transparency; | ||
| 29 | import java.awt.color.ColorSpace; | ||
| 30 | import java.awt.Graphics2D; | ||
| 31 | import java.awt.GraphicsConfiguration; | ||
| 32 | import java.awt.GraphicsEnvironment; | ||
| 33 | import java.awt.ImageCapabilities; | ||
| 34 | import java.awt.geom.Rectangle2D; | ||
| 35 | import java.awt.geom.Point2D; | ||
| 36 | import java.awt.Point; | ||
| 37 | import java.awt.Rectangle; | ||
| 38 | import java.util.Hashtable; | ||
| 39 | import java.util.Vector; | ||
| 40 | |||
| 41 | import sun.awt.image.BytePackedRaster; | ||
| 42 | import sun.awt.image.ShortComponentRaster; | ||
| 43 | import sun.awt.image.ByteComponentRaster; | ||
| 44 | import sun.awt.image.IntegerComponentRaster; | ||
| 45 | import sun.awt.image.OffScreenImageSource; | ||
| 46 | |||
| 47 | /** | ||
| 48 | * | ||
| 49 | * The <code>BufferedImage</code> subclass describes an {@link | ||
| 50 | * java.awt.Image Image} with an accessible buffer of image data. | ||
| 51 | * A <code>BufferedImage</code> is comprised of a {@link ColorModel} and a | ||
| 52 | * {@link Raster} of image data. | ||
| 53 | * The number and types of bands in the {@link SampleModel} of the | ||
| 54 | * <code>Raster</code> must match the number and types required by the | ||
| 55 | * <code>ColorModel</code> to represent its color and alpha components. | ||
| 56 | * All <code>BufferedImage</code> objects have an upper left corner | ||
| 57 | * coordinate of (0, 0). Any <code>Raster</code> used to construct a | ||
| 58 | * <code>BufferedImage</code> must therefore have minX=0 and minY=0. | ||
| 59 | * | ||
| 60 | * <p> | ||
| 61 | * This class relies on the data fetching and setting methods | ||
| 62 | * of <code>Raster</code>, | ||
| 63 | * and on the color characterization methods of <code>ColorModel</code>. | ||
| 64 | * | ||
| 65 | * @see ColorModel | ||
| 66 | * @see Raster | ||
| 67 | * @see WritableRaster | ||
| 68 | */ | ||
| 69 | |||
| 70 | public class BufferedImage extends java.awt.Image | ||
| 71 | implements WritableRenderedImage, Transparency | ||
| 72 | { | ||
| 73 | int imageType = TYPE_CUSTOM; | ||
| 74 | ColorModel colorModel; | ||
| 75 | WritableRaster raster; | ||
| 76 | OffScreenImageSource osis; | ||
| 77 | Hashtable properties; | ||
| 78 | |||
| 79 | boolean isAlphaPremultiplied;// If true, alpha has been premultiplied in | ||
| 80 | // color channels | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Image Type Constants | ||
| 84 | */ | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Image type is not recognized so it must be a customized | ||
| 88 | * image. This type is only used as a return value for the getType() | ||
| 89 | * method. | ||
| 90 | */ | ||
| 91 | public static final int TYPE_CUSTOM = 0; | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Represents an image with 8-bit RGB color components packed into | ||
| 95 | * integer pixels. The image has a {@link DirectColorModel} without | ||
| 96 | * alpha. | ||
| 97 | * When data with non-opaque alpha is stored | ||
| 98 | * in an image of this type, | ||
| 99 | * the color data must be adjusted to a non-premultiplied form | ||
| 100 | * and the alpha discarded, | ||
| 101 | * as described in the | ||
| 102 | * {@link java.awt.AlphaComposite} documentation. | ||
| 103 | */ | ||
| 104 | public static final int TYPE_INT_RGB = 1; | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Represents an image with 8-bit RGBA color components packed into | ||
| 108 | * integer pixels. The image has a <code>DirectColorModel</code> | ||
| 109 | * with alpha. The color data in this image is considered not to be | ||
| 110 | * premultiplied with alpha. When this type is used as the | ||
| 111 | * <code>imageType</code> argument to a <code>BufferedImage</code> | ||
| 112 | * constructor, the created image is consistent with images | ||
| 113 | * created in the JDK1.1 and earlier releases. | ||
| 114 | */ | ||
| 115 | public static final int TYPE_INT_ARGB = 2; | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Represents an image with 8-bit RGBA color components packed into | ||
| 119 | * integer pixels. The image has a <code>DirectColorModel</code> | ||
| 120 | * with alpha. The color data in this image is considered to be | ||
| 121 | * premultiplied with alpha. | ||
| 122 | */ | ||
| 123 | public static final int TYPE_INT_ARGB_PRE = 3; | ||
| 124 | |||
| 125 | /** | ||
| 126 | * Represents an image with 8-bit RGB color components, corresponding | ||
| 127 | * to a Windows- or Solaris- style BGR color model, with the colors | ||
| 128 | * Blue, Green, and Red packed into integer pixels. There is no alpha. | ||
| 129 | * The image has a {@link DirectColorModel}. | ||
| 130 | * When data with non-opaque alpha is stored | ||
| 131 | * in an image of this type, | ||
| 132 | * the color data must be adjusted to a non-premultiplied form | ||
| 133 | * and the alpha discarded, | ||
| 134 | * as described in the | ||
| 135 | * {@link java.awt.AlphaComposite} documentation. | ||
| 136 | */ | ||
| 137 | public static final int TYPE_INT_BGR = 4; | ||
| 138 | |||
| 139 | /** | ||
| 140 | * Represents an image with 8-bit RGB color components, corresponding | ||
| 141 | * to a Windows-style BGR color model) with the colors Blue, Green, | ||
| 142 | * and Red stored in 3 bytes. There is no alpha. The image has a | ||
| 143 | * <code>ComponentColorModel</code>. | ||
| 144 | * When data with non-opaque alpha is stored | ||
| 145 | * in an image of this type, | ||
| 146 | * the color data must be adjusted to a non-premultiplied form | ||
| 147 | * and the alpha discarded, | ||
| 148 | * as described in the | ||
| 149 | * {@link java.awt.AlphaComposite} documentation. | ||
| 150 | */ | ||
| 151 | public static final int TYPE_3BYTE_BGR = 5; | ||
| 152 | |||
| 153 | /** | ||
| 154 | * Represents an image with 8-bit RGBA color components with the colors | ||
| 155 | * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The | ||
| 156 | * image has a <code>ComponentColorModel</code> with alpha. The | ||
| 157 | * color data in this image is considered not to be premultiplied with | ||
| 158 | * alpha. The byte data is interleaved in a single | ||
| 159 | * byte array in the order A, B, G, R | ||
| 160 | * from lower to higher byte addresses within each pixel. | ||
| 161 | */ | ||
| 162 | public static final int TYPE_4BYTE_ABGR = 6; | ||
| 163 | |||
| 164 | /** | ||
| 165 | * Represents an image with 8-bit RGBA color components with the colors | ||
| 166 | * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The | ||
| 167 | * image has a <code>ComponentColorModel</code> with alpha. The color | ||
| 168 | * data in this image is considered to be premultiplied with alpha. | ||
| 169 | * The byte data is interleaved in a single byte array in the order | ||
| 170 | * A, B, G, R from lower to higher byte addresses within each pixel. | ||
| 171 | */ | ||
| 172 | public static final int TYPE_4BYTE_ABGR_PRE = 7; | ||
| 173 | |||
| 174 | /** | ||
| 175 | * Represents an image with 5-6-5 RGB color components (5-bits red, | ||
| 176 | * 6-bits green, 5-bits blue) with no alpha. This image has | ||
| 177 | * a <code>DirectColorModel</code>. | ||
| 178 | * When data with non-opaque alpha is stored | ||
| 179 | * in an image of this type, | ||
| 180 | * the color data must be adjusted to a non-premultiplied form | ||
| 181 | * and the alpha discarded, | ||
| 182 | * as described in the | ||
| 183 | * {@link java.awt.AlphaComposite} documentation. | ||
| 184 | */ | ||
| 185 | public static final int TYPE_USHORT_565_RGB = 8; | ||
| 186 | |||
| 187 | /** | ||
| 188 | * Represents an image with 5-5-5 RGB color components (5-bits red, | ||
| 189 | * 5-bits green, 5-bits blue) with no alpha. This image has | ||
| 190 | * a <code>DirectColorModel</code>. | ||
| 191 | * When data with non-opaque alpha is stored | ||
| 192 | * in an image of this type, | ||
| 193 | * the color data must be adjusted to a non-premultiplied form | ||
| 194 | * and the alpha discarded, | ||
| 195 | * as described in the | ||
| 196 | * {@link java.awt.AlphaComposite} documentation. | ||
| 197 | */ | ||
| 198 | public static final int TYPE_USHORT_555_RGB = 9; | ||
| 199 | |||
| 200 | /** | ||
| 201 | * Represents a unsigned byte grayscale image, non-indexed. This | ||
| 202 | * image has a <code>ComponentColorModel</code> with a CS_GRAY | ||
| 203 | * {@link ColorSpace}. | ||
| 204 | * When data with non-opaque alpha is stored | ||
| 205 | * in an image of this type, | ||
| 206 | * the color data must be adjusted to a non-premultiplied form | ||
| 207 | * and the alpha discarded, | ||
| 208 | * as described in the | ||
| 209 | * {@link java.awt.AlphaComposite} documentation. | ||
| 210 | */ | ||
| 211 | public static final int TYPE_BYTE_GRAY = 10; | ||
| 212 | |||
| 213 | /** | ||
| 214 | * Represents an unsigned short grayscale image, non-indexed). This | ||
| 215 | * image has a <code>ComponentColorModel</code> with a CS_GRAY | ||
| 216 | * <code>ColorSpace</code>. | ||
| 217 | * When data with non-opaque alpha is stored | ||
| 218 | * in an image of this type, | ||
| 219 | * the color data must be adjusted to a non-premultiplied form | ||
| 220 | * and the alpha discarded, | ||
| 221 | * as described in the | ||
| 222 | * {@link java.awt.AlphaComposite} documentation. | ||
| 223 | */ | ||
| 224 | public static final int TYPE_USHORT_GRAY = 11; | ||
| 225 | |||
| 226 | /** | ||
| 227 | * Represents an opaque byte-packed 1, 2, or 4 bit image. The | ||
| 228 | * image has an {@link IndexColorModel} without alpha. When this | ||
| 229 | * type is used as the <code>imageType</code> argument to the | ||
| 230 | * <code>BufferedImage</code> constructor that takes an | ||
| 231 | * <code>imageType</code> argument but no <code>ColorModel</code> | ||
| 232 | * argument, a 1-bit image is created with an | ||
| 233 | * <code>IndexColorModel</code> with two colors in the default | ||
| 234 | * sRGB <code>ColorSpace</code>: {0, 0, 0} and | ||
| 235 | * {255, 255, 255}. | ||
| 236 | * | ||
| 237 | * <p> Images with 2 or 4 bits per pixel may be constructed via | ||
| 238 | * the <code>BufferedImage</code> constructor that takes a | ||
| 239 | * <code>ColorModel</code> argument by supplying a | ||
| 240 | * <code>ColorModel</code> with an appropriate map size. | ||
| 241 | * | ||
| 242 | * <p> Images with 8 bits per pixel should use the image types | ||
| 243 | * <code>TYPE_BYTE_INDEXED</code> or <code>TYPE_BYTE_GRAY</code> | ||
| 244 | * depending on their <code>ColorModel</code>. | ||
| 245 | |||
| 246 | * <p> When color data is stored in an image of this type, | ||
| 247 | * the closest color in the colormap is determined | ||
| 248 | * by the <code>IndexColorModel</code> and the resulting index is stored. | ||
| 249 | * Approximation and loss of alpha or color components | ||
| 250 | * can result, depending on the colors in the | ||
| 251 | * <code>IndexColorModel</code> colormap. | ||
| 252 | */ | ||
| 253 | public static final int TYPE_BYTE_BINARY = 12; | ||
| 254 | |||
| 255 | /** | ||
| 256 | * Represents an indexed byte image. When this type is used as the | ||
| 257 | * <code>imageType</code> argument to the <code>BufferedImage</code> | ||
| 258 | * constructor that takes an <code>imageType</code> argument | ||
| 259 | * but no <code>ColorModel</code> argument, an | ||
| 260 | * <code>IndexColorModel</code> is created with | ||
| 261 | * a 256-color 6/6/6 color cube palette with the rest of the colors | ||
| 262 | * from 216-255 populated by grayscale values in the | ||
| 263 | * default sRGB ColorSpace. | ||
| 264 | * | ||
| 265 | * <p> When color data is stored in an image of this type, | ||
| 266 | * the closest color in the colormap is determined | ||
| 267 | * by the <code>IndexColorModel</code> and the resulting index is stored. | ||
| 268 | * Approximation and loss of alpha or color components | ||
| 269 | * can result, depending on the colors in the | ||
| 270 | * <code>IndexColorModel</code> colormap. | ||
| 271 | */ | ||
| 272 | public static final int TYPE_BYTE_INDEXED = 13; | ||
| 273 | |||
| 274 | private static final int DCM_RED_MASK = 0x00ff0000; | ||
| 275 | private static final int DCM_GREEN_MASK = 0x0000ff00; | ||
| 276 | private static final int DCM_BLUE_MASK = 0x000000ff; | ||
| 277 | private static final int DCM_ALPHA_MASK = 0xff000000; | ||
| 278 | private static final int DCM_565_RED_MASK = 0xf800; | ||
| 279 | private static final int DCM_565_GRN_MASK = 0x07E0; | ||
| 280 | private static final int DCM_565_BLU_MASK = 0x001F; | ||
| 281 | private static final int DCM_555_RED_MASK = 0x7C00; | ||
| 282 | private static final int DCM_555_GRN_MASK = 0x03E0; | ||
| 283 | private static final int DCM_555_BLU_MASK = 0x001F; | ||
| 284 | private static final int DCM_BGR_RED_MASK = 0x0000ff; | ||
| 285 | private static final int DCM_BGR_GRN_MASK = 0x00ff00; | ||
| 286 | private static final int DCM_BGR_BLU_MASK = 0xff0000; | ||
| 287 | |||
| 288 | |||
| 289 | static private native void initIDs(); | ||
| 290 | static { | ||
| 291 | ColorModel.loadLibraries(); | ||
| 292 | initIDs(); | ||
| 293 | } | ||
| 294 | |||
| 295 | /** | ||
| 296 | * Constructs a <code>BufferedImage</code> of one of the predefined | ||
| 297 | * image types. The <code>ColorSpace</code> for the image is the | ||
| 298 | * default sRGB space. | ||
| 299 | * @param width width of the created image | ||
| 300 | * @param height height of the created image | ||
| 301 | * @param imageType type of the created image | ||
| 302 | * @see ColorSpace | ||
| 303 | * @see #TYPE_INT_RGB | ||
| 304 | * @see #TYPE_INT_ARGB | ||
| 305 | * @see #TYPE_INT_ARGB_PRE | ||
| 306 | * @see #TYPE_INT_BGR | ||
| 307 | * @see #TYPE_3BYTE_BGR | ||
| 308 | * @see #TYPE_4BYTE_ABGR | ||
| 309 | * @see #TYPE_4BYTE_ABGR_PRE | ||
| 310 | * @see #TYPE_BYTE_GRAY | ||
| 311 | * @see #TYPE_USHORT_GRAY | ||
| 312 | * @see #TYPE_BYTE_BINARY | ||
| 313 | * @see #TYPE_BYTE_INDEXED | ||
| 314 | * @see #TYPE_USHORT_565_RGB | ||
| 315 | * @see #TYPE_USHORT_555_RGB | ||
| 316 | */ | ||
| 317 | public BufferedImage(int width, | ||
| 318 | int height, | ||
| 319 | int imageType) { | ||
| 320 | switch (imageType) { | ||
| 321 | case TYPE_INT_RGB: | ||
| 322 | { | ||
| 323 | colorModel = new DirectColorModel(24, | ||
| 324 | 0x00ff0000, // Red | ||
| 325 | 0x0000ff00, // Green | ||
| 326 | 0x000000ff, // Blue | ||
| 327 | 0x0 // Alpha | ||
| 328 | ); | ||
| 329 | raster = colorModel.createCompatibleWritableRaster(width, | ||
| 330 | height); | ||
| 331 | } | ||
| 332 | break; | ||
| 333 | |||
| 334 | case TYPE_INT_ARGB: | ||
| 335 | { | ||
| 336 | colorModel = ColorModel.getRGBdefault(); | ||
| 337 | |||
| 338 | raster = colorModel.createCompatibleWritableRaster(width, | ||
| 339 | height); | ||
| 340 | } | ||
| 341 | break; | ||
| 342 | |||
| 343 | case TYPE_INT_ARGB_PRE: | ||
| 344 | { | ||
| 345 | colorModel = new | ||
| 346 | DirectColorModel( | ||
| 347 | ColorSpace.getInstance(ColorSpace.CS_sRGB), | ||
| 348 | 32, | ||
| 349 | 0x00ff0000,// Red | ||
| 350 | 0x0000ff00,// Green | ||
| 351 | 0x000000ff,// Blue | ||
| 352 | 0xff000000,// Alpha | ||
| 353 | true, // Alpha Premultiplied | ||
| 354 | DataBuffer.TYPE_INT | ||
| 355 | ); | ||
| 356 | |||
| 357 | raster = colorModel.createCompatibleWritableRaster(width, | ||
| 358 | height); | ||
| 359 | } | ||
| 360 | break; | ||
| 361 | |||
| 362 | case TYPE_INT_BGR: | ||
| 363 | { | ||
| 364 | colorModel = new DirectColorModel(24, | ||
| 365 | 0x000000ff, // Red | ||
| 366 | 0x0000ff00, // Green | ||
| 367 | 0x00ff0000 // Blue | ||
| 368 | ); | ||
| 369 | raster = colorModel.createCompatibleWritableRaster(width, | ||
| 370 | height); | ||
| 371 | } | ||
| 372 | break; | ||
| 373 | |||
| 374 | case TYPE_3BYTE_BGR: | ||
| 375 | { | ||
| 376 | ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); | ||
| 377 | int[] nBits = {8, 8, 8}; | ||
| 378 | int[] bOffs = {2, 1, 0}; | ||
| 379 | colorModel = new ComponentColorModel(cs, nBits, false, false, | ||
| 380 | Transparency.OPAQUE, | ||
| 381 | DataBuffer.TYPE_BYTE); | ||
| 382 | raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, | ||
| 383 | width, height, | ||
| 384 | width*3, 3, | ||
| 385 | bOffs, null); | ||
| 386 | } | ||
| 387 | break; | ||
| 388 | |||
| 389 | case TYPE_4BYTE_ABGR: | ||
| 390 | { | ||
| 391 | ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); | ||
| 392 | int[] nBits = {8, 8, 8, 8}; | ||
| 393 | int[] bOffs = {3, 2, 1, 0}; | ||
| 394 | colorModel = new ComponentColorModel(cs, nBits, true, false, | ||
| 395 | Transparency.TRANSLUCENT, | ||
| 396 | DataBuffer.TYPE_BYTE); | ||
| 397 | raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, | ||
| 398 | width, height, | ||
| 399 | width*4, 4, | ||
| 400 | bOffs, null); | ||
| 401 | } | ||
| 402 | break; | ||
| 403 | |||
| 404 | case TYPE_4BYTE_ABGR_PRE: | ||
| 405 | { | ||
| 406 | ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); | ||
| 407 | int[] nBits = {8, 8, 8, 8}; | ||
| 408 | int[] bOffs = {3, 2, 1, 0}; | ||
| 409 | colorModel = new ComponentColorModel(cs, nBits, true, true, | ||
| 410 | Transparency.TRANSLUCENT, | ||
| 411 | DataBuffer.TYPE_BYTE); | ||
| 412 | raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, | ||
| 413 | width, height, | ||
| 414 | width*4, 4, | ||
| 415 | bOffs, null); | ||
| 416 | } | ||
| 417 | break; | ||
| 418 | |||
| 419 | case TYPE_BYTE_GRAY: | ||
| 420 | { | ||
| 421 | ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); | ||
| 422 | int[] nBits = {8}; | ||
| 423 | colorModel = new ComponentColorModel(cs, nBits, false, true, | ||
| 424 | Transparency.OPAQUE, | ||
| 425 | DataBuffer.TYPE_BYTE); | ||
| 426 | raster = colorModel.createCompatibleWritableRaster(width, | ||
| 427 | height); | ||
| 428 | } | ||
| 429 | break; | ||
| 430 | |||
| 431 | case TYPE_USHORT_GRAY: | ||
| 432 | { | ||
| 433 | ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); | ||
| 434 | int[] nBits = {16}; | ||
| 435 | colorModel = new ComponentColorModel(cs, nBits, false, true, | ||
| 436 | Transparency.OPAQUE, | ||
| 437 | DataBuffer.TYPE_USHORT); | ||
| 438 | raster = colorModel.createCompatibleWritableRaster(width, | ||
| 439 | height); | ||
| 440 | } | ||
| 441 | break; | ||
| 442 | |||
| 443 | case TYPE_BYTE_BINARY: | ||
| 444 | { | ||
| 445 | byte[] arr = {(byte)0, (byte)0xff}; | ||
| 446 | |||
| 447 | colorModel = new IndexColorModel(1, 2, arr, arr, arr); | ||
| 448 | raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, | ||
| 449 | width, height, 1, 1, null); | ||
| 450 | } | ||
| 451 | break; | ||
| 452 | |||
| 453 | case TYPE_BYTE_INDEXED: | ||
| 454 | { | ||
| 455 | // Create a 6x6x6 color cube | ||
| 456 | int[] cmap = new int[256]; | ||
| 457 | int i=0; | ||
| 458 | for (int r=0; r < 256; r += 51) { | ||
| 459 | for (int g=0; g < 256; g += 51) { | ||
| 460 | for (int b=0; b < 256; b += 51) { | ||
| 461 | cmap[i++] = (r<<16)|(g<<8)|b; | ||
| 462 | } | ||
| 463 | } | ||
| 464 | } | ||
| 465 | // And populate the rest of the cmap with gray values | ||
| 466 | int grayIncr = 256/(256-i); | ||
| 467 | |||
| 468 | // The gray ramp will be between 18 and 252 | ||
| 469 | int gray = grayIncr*3; | ||
| 470 | for (; i < 256; i++) { | ||
| 471 | cmap[i] = (gray<<16)|(gray<<8)|gray; | ||
| 472 | gray += grayIncr; | ||
| 473 | } | ||
| 474 | |||
| 475 | colorModel = new IndexColorModel(8, 256, cmap, 0, false, -1, | ||
| 476 | DataBuffer.TYPE_BYTE); | ||
| 477 | raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, | ||
| 478 | width, height, 1, null); | ||
| 479 | } | ||
| 480 | break; | ||
| 481 | |||
| 482 | case TYPE_USHORT_565_RGB: | ||
| 483 | { | ||
| 484 | colorModel = new DirectColorModel(16, | ||
| 485 | DCM_565_RED_MASK, | ||
| 486 | DCM_565_GRN_MASK, | ||
| 487 | DCM_565_BLU_MASK | ||
| 488 | ); | ||
| 489 | raster = colorModel.createCompatibleWritableRaster(width, | ||
| 490 | height); | ||
| 491 | } | ||
| 492 | break; | ||
| 493 | |||
| 494 | case TYPE_USHORT_555_RGB: | ||
| 495 | { | ||
| 496 | colorModel = new DirectColorModel(15, | ||
| 497 | DCM_555_RED_MASK, | ||
| 498 | DCM_555_GRN_MASK, | ||
| 499 | DCM_555_BLU_MASK | ||
| 500 | ); | ||
| 501 | raster = colorModel.createCompatibleWritableRaster(width, | ||
| 502 | height); | ||
| 503 | } | ||
| 504 | break; | ||
| 505 | |||
| 506 | default: | ||
| 507 | throw new IllegalArgumentException ("Unknown image type " + | ||
| 508 | imageType); | ||
| 509 | } | ||
| 510 | |||
| 511 | this.imageType = imageType; | ||
| 512 | } | ||
| 513 | |||
| 514 | /** | ||
| 515 | * Constructs a <code>BufferedImage</code> of one of the predefined | ||
| 516 | * image types: | ||
| 517 | * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED. | ||
| 518 | * | ||
| 519 | * <p> If the image type is TYPE_BYTE_BINARY, the number of | ||
| 520 | * entries in the color model is used to determine whether the | ||
| 521 | * image should have 1, 2, or 4 bits per pixel. If the color model | ||
| 522 | * has 1 or 2 entries, the image will have 1 bit per pixel. If it | ||
| 523 | * has 3 or 4 entries, the image with have 2 bits per pixel. If | ||
| 524 | * it has between 5 and 16 entries, the image will have 4 bits per | ||
| 525 | * pixel. Otherwise, an IllegalArgumentException will be thrown. | ||
| 526 | * | ||
| 527 | * @param width width of the created image | ||
| 528 | * @param height height of the created image | ||
| 529 | * @param imageType type of the created image | ||
| 530 | * @param cm <code>IndexColorModel</code> of the created image | ||
| 531 | * @throws IllegalArgumentException if the imageType is not | ||
| 532 | * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED or if the imageType is | ||
| 533 | * TYPE_BYTE_BINARY and the color map has more than 16 entries. | ||
| 534 | * @see #TYPE_BYTE_BINARY | ||
| 535 | * @see #TYPE_BYTE_INDEXED | ||
| 536 | */ | ||
| 537 | public BufferedImage (int width, | ||
| 538 | int height, | ||
| 539 | int imageType, | ||
| 540 | IndexColorModel cm) { | ||
| 541 | if (cm.hasAlpha() && cm.isAlphaPremultiplied()) { | ||
| 542 | throw new IllegalArgumentException("This image types do not have "+ | ||
| 543 | "premultiplied alpha."); | ||
| 544 | } | ||
| 545 | |||
| 546 | switch(imageType) { | ||
| 547 | case TYPE_BYTE_BINARY: | ||
| 548 | int bits; // Will be set below | ||
| 549 | int mapSize = cm.getMapSize(); | ||
| 550 | if (mapSize <= 2) { | ||
| 551 | bits = 1; | ||
| 552 | } else if (mapSize <= 4) { | ||
| 553 | bits = 2; | ||
| 554 | } else if (mapSize <= 16) { | ||
| 555 | bits = 4; | ||
| 556 | } else { | ||
| 557 | throw new IllegalArgumentException | ||
| 558 | ("Color map for TYPE_BYTE_BINARY " + | ||
| 559 | "must have no more than 16 entries"); | ||
| 560 | } | ||
| 561 | raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, | ||
| 562 | width, height, 1, bits, null); | ||
| 563 | break; | ||
| 564 | |||
| 565 | case TYPE_BYTE_INDEXED: | ||
| 566 | raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, | ||
| 567 | width, height, 1, null); | ||
| 568 | break; | ||
| 569 | default: | ||
| 570 | throw new IllegalArgumentException("Invalid image type (" + | ||
| 571 | imageType+"). Image type must"+ | ||
| 572 | " be either TYPE_BYTE_BINARY or "+ | ||
| 573 | " TYPE_BYTE_INDEXED"); | ||
| 574 | } | ||
| 575 | |||
| 576 | if (!cm.isCompatibleRaster(raster)) { | ||
| 577 | throw new IllegalArgumentException("Incompatible image type and IndexColorModel"); | ||
| 578 | } | ||
| 579 | |||
| 580 | colorModel = cm; | ||
| 581 | this.imageType = imageType; | ||
| 582 | } | ||
| 583 | |||
| 584 | /** | ||
| 585 | * Constructs a new <code>BufferedImage</code> with a specified | ||
| 586 | * <code>ColorModel</code> and <code>Raster</code>. If the number and | ||
| 587 | * types of bands in the <code>SampleModel</code> of the | ||
| 588 | * <code>Raster</code> do not match the number and types required by | ||
| 589 | * the <code>ColorModel</code> to represent its color and alpha | ||
| 590 | * components, a {@link RasterFormatException} is thrown. This | ||
| 591 | * method can multiply or divide the color <code>Raster</code> data by | ||
| 592 | * alpha to match the <code>alphaPremultiplied</code> state | ||
| 593 | * in the <code>ColorModel</code>. Properties for this | ||
| 594 | * <code>BufferedImage</code> can be established by passing | ||
| 595 | * in a {@link Hashtable} of <code>String</code>/<code>Object</code> | ||
| 596 | * pairs. | ||
| 597 | * @param cm <code>ColorModel</code> for the new image | ||
| 598 | * @param raster <code>Raster</code> for the image data | ||
| 599 | * @param isRasterPremultiplied if <code>true</code>, the data in | ||
| 600 | * the raster has been premultiplied with alpha. | ||
| 601 | * @param properties <code>Hashtable</code> of | ||
| 602 | * <code>String</code>/<code>Object</code> pairs. | ||
| 603 | * @exception <code>RasterFormatException</code> if the number and | ||
| 604 | * types of bands in the <code>SampleModel</code> of the | ||
| 605 | * <code>Raster</code> do not match the number and types required by | ||
| 606 | * the <code>ColorModel</code> to represent its color and alpha | ||
| 607 | * components. | ||
| 608 | * @exception <code>IllegalArgumentException</code> if | ||
| 609 | * <code>raster</code> is incompatible with <code>cm</code> | ||
| 610 | * @see ColorModel | ||
| 611 | * @see Raster | ||
| 612 | * @see WritableRaster | ||
| 613 | */ | ||
| 614 | |||
| 615 | |||
| 616 | /* | ||
| 617 | * | ||
| 618 | * FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF | ||
| 619 | * SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER | ||
| 620 | * | ||
| 621 | */ | ||
| 622 | public BufferedImage (ColorModel cm, | ||
| 623 | WritableRaster raster, | ||
| 624 | boolean isRasterPremultiplied, | ||
| 625 | Hashtable<?,?> properties) { | ||
| 626 | |||
| 627 | if (!cm.isCompatibleRaster(raster)) { | ||
| 628 | throw new | ||
| 629 | IllegalArgumentException("Raster "+raster+ | ||
| 630 | " is incompatible with ColorModel "+ | ||
| 631 | cm); | ||
| 632 | } | ||
| 633 | |||
| 634 | if ((raster.minX != 0) || (raster.minY != 0)) { | ||
| 635 | throw new | ||
| 636 | IllegalArgumentException("Raster "+raster+ | ||
| 637 | " has minX or minY not equal to zero: " | ||
| 638 | + raster.minX + " " + raster.minY); | ||
| 639 | } | ||
| 640 | |||
| 641 | colorModel = cm; | ||
| 642 | this.raster = raster; | ||
| 643 | this.properties = properties; | ||
| 644 | int numBands = raster.getNumBands(); | ||
| 645 | boolean isAlphaPre = cm.isAlphaPremultiplied(); | ||
| 646 | ColorSpace cs; | ||
| 647 | |||
| 648 | // Force the raster data alpha state to match the premultiplied | ||
| 649 | // state in the color model | ||
| 650 | coerceData(isRasterPremultiplied); | ||
| 651 | |||
| 652 | SampleModel sm = raster.getSampleModel(); | ||
| 653 | cs = cm.getColorSpace(); | ||
| 654 | int csType = cs.getType(); | ||
| 655 | if (csType != ColorSpace.TYPE_RGB) { | ||
| 656 | if (csType == ColorSpace.TYPE_GRAY | ||
| 657 | && cm instanceof ComponentColorModel) { | ||
| 658 | // Check if this might be a child raster (fix for bug 4240596) | ||
| 659 | if (sm instanceof ComponentSampleModel && | ||
| 660 | ((ComponentSampleModel)sm).getPixelStride() != numBands) { | ||
| 661 | imageType = TYPE_CUSTOM; | ||
| 662 | } else if (raster instanceof ByteComponentRaster && | ||
| 663 | raster.getNumBands() == 1 && | ||
| 664 | cm.getComponentSize(0) == 8 && | ||
| 665 | ((ByteComponentRaster)raster).getPixelStride() == 1) { | ||
| 666 | imageType = TYPE_BYTE_GRAY; | ||
| 667 | } else if (raster instanceof ShortComponentRaster && | ||
| 668 | raster.getNumBands() == 1 && | ||
| 669 | cm.getComponentSize(0) == 16 && | ||
| 670 | ((ShortComponentRaster)raster).getPixelStride() == 1) { | ||
| 671 | imageType = TYPE_USHORT_GRAY; | ||
| 672 | } | ||
| 673 | } else { | ||
| 674 | imageType = TYPE_CUSTOM; | ||
| 675 | } | ||
| 676 | return; | ||
| 677 | } | ||
| 678 | |||
| 679 | if ((raster instanceof IntegerComponentRaster) && | ||
| 680 | (numBands == 3 || numBands == 4)) { | ||
| 681 | IntegerComponentRaster iraster = | ||
| 682 | (IntegerComponentRaster) raster; | ||
| 683 | // Check if the raster params and the color model | ||
| 684 | // are correct | ||
| 685 | int pixSize = cm.getPixelSize(); | ||
| 686 | if (iraster.getPixelStride() == 1 && | ||
| 687 | cm instanceof DirectColorModel && | ||
| 688 | (pixSize == 32 || pixSize == 24)) | ||
| 689 | { | ||
| 690 | // Now check on the DirectColorModel params | ||
| 691 | DirectColorModel dcm = (DirectColorModel) cm; | ||
| 692 | int rmask = dcm.getRedMask(); | ||
| 693 | int gmask = dcm.getGreenMask(); | ||
| 694 | int bmask = dcm.getBlueMask(); | ||
| 695 | if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK && | ||
| 696 | bmask == DCM_BLUE_MASK) | ||
| 697 | { | ||
| 698 | if (dcm.getAlphaMask() == DCM_ALPHA_MASK) { | ||
| 699 | imageType = (isAlphaPre | ||
| 700 | ? TYPE_INT_ARGB_PRE | ||
| 701 | : TYPE_INT_ARGB); | ||
| 702 | } | ||
| 703 | else { | ||
| 704 | // No Alpha | ||
| 705 | if (!dcm.hasAlpha()) { | ||
| 706 | imageType = TYPE_INT_RGB; | ||
| 707 | } | ||
| 708 | } | ||
| 709 | } // if (dcm.getRedMask() == DCM_RED_MASK && | ||
| 710 | else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK | ||
| 711 | && bmask == DCM_BGR_BLU_MASK) { | ||
| 712 | if (!dcm.hasAlpha()) { | ||
| 713 | imageType = TYPE_INT_BGR; | ||
| 714 | } | ||
| 715 | } // if (rmask == DCM_BGR_RED_MASK && | ||
| 716 | } // if (iraster.getPixelStride() == 1 | ||
| 717 | } // ((raster instanceof IntegerComponentRaster) && | ||
| 718 | else if ((cm instanceof IndexColorModel) && (numBands == 1) && | ||
| 719 | (!cm.hasAlpha() || !isAlphaPre)) | ||
| 720 | { | ||
| 721 | IndexColorModel icm = (IndexColorModel) cm; | ||
| 722 | int pixSize = icm.getPixelSize(); | ||
| 723 | |||
| 724 | if (raster instanceof BytePackedRaster) { | ||
| 725 | imageType = TYPE_BYTE_BINARY; | ||
| 726 | } // if (raster instanceof BytePackedRaster) | ||
| 727 | else if (raster instanceof ByteComponentRaster) { | ||
| 728 | ByteComponentRaster braster = (ByteComponentRaster) raster; | ||
| 729 | if (braster.getPixelStride() == 1 && pixSize <= 8) { | ||
| 730 | imageType = TYPE_BYTE_INDEXED; | ||
| 731 | } | ||
| 732 | } | ||
| 733 | } // else if (cm instanceof IndexColorModel) && (numBands == 1)) | ||
| 734 | else if ((raster instanceof ShortComponentRaster) | ||
| 735 | && (cm instanceof DirectColorModel) | ||
| 736 | && (numBands == 3) | ||
| 737 | && !cm.hasAlpha()) | ||
| 738 | { | ||
| 739 | DirectColorModel dcm = (DirectColorModel) cm; | ||
| 740 | if (dcm.getRedMask() == DCM_565_RED_MASK) { | ||
| 741 | if (dcm.getGreenMask() == DCM_565_GRN_MASK && | ||
| 742 | dcm.getBlueMask() == DCM_565_BLU_MASK) { | ||
| 743 | imageType = TYPE_USHORT_565_RGB; | ||
| 744 | } | ||
| 745 | } | ||
| 746 | else if (dcm.getRedMask() == DCM_555_RED_MASK) { | ||
| 747 | if (dcm.getGreenMask() == DCM_555_GRN_MASK && | ||
| 748 | dcm.getBlueMask() == DCM_555_BLU_MASK) { | ||
| 749 | imageType = TYPE_USHORT_555_RGB; | ||
| 750 | } | ||
| 751 | } | ||
| 752 | } // else if ((cm instanceof IndexColorModel) && (numBands == 1)) | ||
| 753 | else if ((raster instanceof ByteComponentRaster) | ||
| 754 | && (cm instanceof ComponentColorModel) | ||
| 755 | && (raster.getSampleModel() instanceof PixelInterleavedSampleModel) | ||
| 756 | && (numBands == 3 || numBands == 4)) | ||
| 757 | { | ||
| 758 | ComponentColorModel ccm = (ComponentColorModel) cm; | ||
| 759 | PixelInterleavedSampleModel csm = | ||
| 760 | (PixelInterleavedSampleModel)raster.getSampleModel(); | ||
| 761 | ByteComponentRaster braster = (ByteComponentRaster) raster; | ||
| 762 | int[] offs = csm.getBandOffsets(); | ||
| 763 | if (ccm.getNumComponents() != numBands) { | ||
| 764 | throw new RasterFormatException("Number of components in "+ | ||
| 765 | "ColorModel ("+ | ||
| 766 | ccm.getNumComponents()+ | ||
| 767 | ") does not match # in "+ | ||
| 768 | " Raster ("+numBands+")"); | ||
| 769 | } | ||
| 770 | int[] nBits = ccm.getComponentSize(); | ||
| 771 | boolean is8bit = true; | ||
| 772 | for (int i=0; i < numBands; i++) { | ||
| 773 | if (nBits[i] != 8) { | ||
| 774 | is8bit = false; | ||
| 775 | break; | ||
| 776 | } | ||
| 777 | } | ||
| 778 | if (is8bit && | ||
| 779 | offs[0] == numBands-1 && | ||
| 780 | offs[1] == numBands-2 && | ||
| 781 | offs[2] == numBands-3) | ||
| 782 | { | ||
| 783 | if (numBands == 3) { | ||
| 784 | imageType = TYPE_3BYTE_BGR; | ||
| 785 | } | ||
| 786 | else if (offs[3] == 0) { | ||
| 787 | imageType = (isAlphaPre | ||
| 788 | ? TYPE_4BYTE_ABGR_PRE | ||
| 789 | : TYPE_4BYTE_ABGR); | ||
| 790 | } | ||
| 791 | } | ||
| 792 | } // else if ((raster instanceof ByteComponentRaster) && | ||
| 793 | } | ||
| 794 | |||
| 795 | /** | ||
| 796 | * Returns the image type. If it is not one of the known types, | ||
| 797 | * TYPE_CUSTOM is returned. | ||
| 798 | * @return the image type of this <code>BufferedImage</code>. | ||
| 799 | * @see #TYPE_INT_RGB | ||
| 800 | * @see #TYPE_INT_ARGB | ||
| 801 | * @see #TYPE_INT_ARGB_PRE | ||
| 802 | * @see #TYPE_INT_BGR | ||
| 803 | * @see #TYPE_3BYTE_BGR | ||
| 804 | * @see #TYPE_4BYTE_ABGR | ||
| 805 | * @see #TYPE_4BYTE_ABGR_PRE | ||
| 806 | * @see #TYPE_BYTE_GRAY | ||
| 807 | * @see #TYPE_BYTE_BINARY | ||
| 808 | * @see #TYPE_BYTE_INDEXED | ||
| 809 | * @see #TYPE_USHORT_GRAY | ||
| 810 | * @see #TYPE_USHORT_565_RGB | ||
| 811 | * @see #TYPE_USHORT_555_RGB | ||
| 812 | * @see #TYPE_CUSTOM | ||
| 813 | */ | ||
| 814 | public int getType() { | ||
| 815 | return imageType; | ||
| 816 | } | ||
| 817 | |||
| 818 | /** | ||
| 819 | * Returns the <code>ColorModel</code>. | ||
| 820 | * @return the <code>ColorModel</code> of this | ||
| 821 | * <code>BufferedImage</code>. | ||
| 822 | */ | ||
| 823 | public ColorModel getColorModel() { | ||
| 824 | return colorModel; | ||
| 825 | } | ||
| 826 | |||
| 827 | /** | ||
| 828 | * Returns the {@link WritableRaster}. | ||
| 829 | * @return the <code>WriteableRaster</code> of this | ||
| 830 | * <code>BufferedImage</code>. | ||
| 831 | */ | ||
| 832 | public WritableRaster getRaster() { | ||
| 833 | return raster; | ||
| 834 | } | ||
| 835 | |||
| 836 | |||
| 837 | /** | ||
| 838 | * Returns a <code>WritableRaster</code> representing the alpha | ||
| 839 | * channel for <code>BufferedImage</code> objects | ||
| 840 | * with <code>ColorModel</code> objects that support a separate | ||
| 841 | * spatial alpha channel, such as <code>ComponentColorModel</code> and | ||
| 842 | * <code>DirectColorModel</code>. Returns <code>null</code> if there | ||
| 843 | * is no alpha channel associated with the <code>ColorModel</code> in | ||
| 844 | * this image. This method assumes that for all | ||
| 845 | * <code>ColorModel</code> objects other than | ||
| 846 | * <code>IndexColorModel</code>, if the <code>ColorModel</code> | ||
| 847 | * supports alpha, there is a separate alpha channel | ||
| 848 | * which is stored as the last band of image data. | ||
| 849 | * If the image uses an <code>IndexColorModel</code> that | ||
| 850 | * has alpha in the lookup table, this method returns | ||
| 851 | * <code>null</code> since there is no spatially discrete alpha | ||
| 852 | * channel. This method creates a new | ||
| 853 | * <code>WritableRaster</code>, but shares the data array. | ||
| 854 | * @return a <code>WritableRaster</code> or <code>null</code> if this | ||
| 855 | * <code>BufferedImage</code> has no alpha channel associated | ||
| 856 | * with its <code>ColorModel</code>. | ||
| 857 | */ | ||
| 858 | public WritableRaster getAlphaRaster() { | ||
| 859 | return colorModel.getAlphaRaster(raster); | ||
| 860 | } | ||
| 861 | |||
| 862 | /** | ||
| 863 | * Returns an integer pixel in the default RGB color model | ||
| 864 | * (TYPE_INT_ARGB) and default sRGB colorspace. Color | ||
| 865 | * conversion takes place if this default model does not match | ||
| 866 | * the image <code>ColorModel</code>. There are only 8-bits of | ||
| 867 | * precision for each color component in the returned data when using | ||
| 868 | * this method. | ||
| 869 | * | ||
| 870 | * <p> | ||
| 871 | * | ||
| 872 | * An <code>ArrayOutOfBoundsException</code> may be thrown | ||
| 873 | * if the coordinates are not in bounds. | ||
| 874 | * However, explicit bounds checking is not guaranteed. | ||
| 875 | * | ||
| 876 | * @param x the X coordinate of the pixel from which to get | ||
| 877 | * the pixel in the default RGB color model and sRGB | ||
| 878 | * color space | ||
| 879 | * @param y the Y coordinate of the pixel from which to get | ||
| 880 | * the pixel in the default RGB color model and sRGB | ||
| 881 | * color space | ||
| 882 | * @return an integer pixel in the default RGB color model and | ||
| 883 | * default sRGB colorspace. | ||
| 884 | * @see #setRGB(int, int, int) | ||
| 885 | * @see #setRGB(int, int, int, int, int[], int, int) | ||
| 886 | */ | ||
| 887 | public int getRGB(int x, int y) { | ||
| 888 | return colorModel.getRGB(raster.getDataElements(x, y, null)); | ||
| 889 | } | ||
| 890 | |||
| 891 | /** | ||
| 892 | * Returns an array of integer pixels in the default RGB color model | ||
| 893 | * (TYPE_INT_ARGB) and default sRGB color space, | ||
| 894 | * from a portion of the image data. Color conversion takes | ||
| 895 | * place if the default model does not match the image | ||
| 896 | * <code>ColorModel</code>. There are only 8-bits of precision for | ||
| 897 | * each color component in the returned data when | ||
| 898 | * using this method. With a specified coordinate (x, y) in the | ||
| 899 | * image, the ARGB pixel can be accessed in this way: | ||
| 900 | * </p> | ||
| 901 | * | ||
| 902 | * <pre> | ||
| 903 | * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]; </pre> | ||
| 904 | * | ||
| 905 | * <p> | ||
| 906 | * | ||
| 907 | * An <code>ArrayOutOfBoundsException</code> may be thrown | ||
| 908 | * if the region is not in bounds. | ||
| 909 | * However, explicit bounds checking is not guaranteed. | ||
| 910 | * | ||
| 911 | * @param startX the starting X coordinate | ||
| 912 | * @param startY the starting Y coordinate | ||
| 913 | * @param w width of region | ||
| 914 | * @param h height of region | ||
| 915 | * @param rgbArray if not <code>null</code>, the rgb pixels are | ||
| 916 | * written here | ||
| 917 | * @param offset offset into the <code>rgbArray</code> | ||
| 918 | * @param scansize scanline stride for the <code>rgbArray</code> | ||
| 919 | * @return array of RGB pixels. | ||
| 920 | * @see #setRGB(int, int, int) | ||
| 921 | * @see #setRGB(int, int, int, int, int[], int, int) | ||
| 922 | */ | ||
| 923 | public int[] getRGB(int startX, int startY, int w, int h, | ||
| 924 | int[] rgbArray, int offset, int scansize) { | ||
| 925 | int yoff = offset; | ||
| 926 | int off; | ||
| 927 | Object data; | ||
| 928 | int nbands = raster.getNumBands(); | ||
| 929 | int dataType = raster.getDataBuffer().getDataType(); | ||
| 930 | switch (dataType) { | ||
| 931 | case DataBuffer.TYPE_BYTE: | ||
| 932 | data = new byte[nbands]; | ||
| 933 | break; | ||
| 934 | case DataBuffer.TYPE_USHORT: | ||
| 935 | data = new short[nbands]; | ||
| 936 | break; | ||
| 937 | case DataBuffer.TYPE_INT: | ||
| 938 | data = new int[nbands]; | ||
| 939 | break; | ||
| 940 | case DataBuffer.TYPE_FLOAT: | ||
| 941 | data = new float[nbands]; | ||
| 942 | break; | ||
| 943 | case DataBuffer.TYPE_DOUBLE: | ||
| 944 | data = new double[nbands]; | ||
| 945 | break; | ||
| 946 | default: | ||
| 947 | throw new IllegalArgumentException("Unknown data buffer type: "+ | ||
| 948 | dataType); | ||
| 949 | } | ||
| 950 | |||
| 951 | if (rgbArray == null) { | ||
| 952 | rgbArray = new int[offset+h*scansize]; | ||
| 953 | } | ||
| 954 | |||
| 955 | for (int y = startY; y < startY+h; y++, yoff+=scansize) { | ||
| 956 | off = yoff; | ||
| 957 | for (int x = startX; x < startX+w; x++) { | ||
| 958 | rgbArray[off++] = colorModel.getRGB(raster.getDataElements(x, | ||
| 959 | y, | ||
| 960 | data)); | ||
| 961 | } | ||
| 962 | } | ||
| 963 | |||
| 964 | return rgbArray; | ||
| 965 | } | ||
| 966 | |||
| 967 | |||
| 968 | /** | ||
| 969 | * Sets a pixel in this <code>BufferedImage</code> to the specified | ||
| 970 | * RGB value. The pixel is assumed to be in the default RGB color | ||
| 971 | * model, TYPE_INT_ARGB, and default sRGB color space. For images | ||
| 972 | * with an <code>IndexColorModel</code>, the index with the nearest | ||
| 973 | * color is chosen. | ||
| 974 | * | ||
| 975 | * <p> | ||
| 976 | * | ||
| 977 | * An <code>ArrayOutOfBoundsException</code> may be thrown | ||
| 978 | * if the coordinates are not in bounds. | ||
| 979 | * However, explicit bounds checking is not guaranteed. | ||
| 980 | * | ||
| 981 | * @param x the X coordinate of the pixel to set | ||
| 982 | * @param y the Y coordinate of the pixel to set | ||
| 983 | * @param rgb the RGB value | ||
| 984 | * @see #getRGB(int, int) | ||
| 985 | * @see #getRGB(int, int, int, int, int[], int, int) | ||
| 986 | */ | ||
| 987 | public synchronized void setRGB(int x, int y, int rgb) { | ||
| 988 | raster.setDataElements(x, y, colorModel.getDataElements(rgb, null)); | ||
| 989 | } | ||
| 990 | |||
| 991 | /** | ||
| 992 | * Sets an array of integer pixels in the default RGB color model | ||
| 993 | * (TYPE_INT_ARGB) and default sRGB color space, | ||
| 994 | * into a portion of the image data. Color conversion takes place | ||
| 995 | * if the default model does not match the image | ||
| 996 | * <code>ColorModel</code>. There are only 8-bits of precision for | ||
| 997 | * each color component in the returned data when | ||
| 998 | * using this method. With a specified coordinate (x, y) in the | ||
| 999 | * this image, the ARGB pixel can be accessed in this way: | ||
| 1000 | * <pre> | ||
| 1001 | * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]; | ||
| 1002 | * </pre> | ||
| 1003 | * WARNING: No dithering takes place. | ||
| 1004 | * | ||
| 1005 | * <p> | ||
| 1006 | * | ||
| 1007 | * An <code>ArrayOutOfBoundsException</code> may be thrown | ||
| 1008 | * if the region is not in bounds. | ||
| 1009 | * However, explicit bounds checking is not guaranteed. | ||
| 1010 | * | ||
| 1011 | * @param startX the starting X coordinate | ||
| 1012 | * @param startY the starting Y coordinate | ||
| 1013 | * @param w width of the region | ||
| 1014 | * @param h height of the region | ||
| 1015 | * @param rgbArray the rgb pixels | ||
| 1016 | * @param offset offset into the <code>rgbArray</code> | ||
| 1017 | * @param scansize scanline stride for the <code>rgbArray</code> | ||
| 1018 | * @see #getRGB(int, int) | ||
| 1019 | * @see #getRGB(int, int, int, int, int[], int, int) | ||
| 1020 | */ | ||
| 1021 | public void setRGB(int startX, int startY, int w, int h, | ||
| 1022 | int[] rgbArray, int offset, int scansize) { | ||
| 1023 | int yoff = offset; | ||
| 1024 | int off; | ||
| 1025 | Object pixel = null; | ||
| 1026 | |||
| 1027 | for (int y = startY; y < startY+h; y++, yoff+=scansize) { | ||
| 1028 | off = yoff; | ||
| 1029 | for (int x = startX; x < startX+w; x++) { | ||
| 1030 | pixel = colorModel.getDataElements(rgbArray[off++], pixel); | ||
| 1031 | raster.setDataElements(x, y, pixel); | ||
| 1032 | } | ||
| 1033 | } | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | |||
| 1037 | /** | ||
| 1038 | * Returns the width of the <code>BufferedImage</code>. | ||
| 1039 | * @return the width of this <code>BufferedImage</code> | ||
| 1040 | */ | ||
| 1041 | public int getWidth() { | ||
| 1042 | return raster.getWidth(); | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | /** | ||
| 1046 | * Returns the height of the <code>BufferedImage</code>. | ||
| 1047 | * @return the height of this <code>BufferedImage</code> | ||
| 1048 | */ | ||
| 1049 | public int getHeight() { | ||
| 1050 | return raster.getHeight(); | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | /** | ||
| 1054 | * Returns the width of the <code>BufferedImage</code>. | ||
| 1055 | * @param observer ignored | ||
| 1056 | * @return the width of this <code>BufferedImage</code> | ||
| 1057 | */ | ||
| 1058 | public int getWidth(ImageObserver observer) { | ||
| 1059 | return raster.getWidth(); | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | /** | ||
| 1063 | * Returns the height of the <code>BufferedImage</code>. | ||
| 1064 | * @param observer ignored | ||
| 1065 | * @return the height of this <code>BufferedImage</code> | ||
| 1066 | */ | ||
| 1067 | public int getHeight(ImageObserver observer) { | ||
| 1068 | return raster.getHeight(); | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | /** | ||
| 1072 | * Returns the object that produces the pixels for the image. | ||
| 1073 | * @return the {@link ImageProducer} that is used to produce the | ||
| 1074 | * pixels for this image. | ||
| 1075 | * @see ImageProducer | ||
| 1076 | */ | ||
| 1077 | public ImageProducer getSource() { | ||
| 1078 | if (osis == null) { | ||
| 1079 | if (properties == null) { | ||
| 1080 | properties = new Hashtable(); | ||
| 1081 | } | ||
| 1082 | osis = new OffScreenImageSource(this, properties); | ||
| 1083 | } | ||
| 1084 | return osis; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | |||
| 1088 | /** | ||
| 1089 | * Returns a property of the image by name. Individual property names | ||
| 1090 | * are defined by the various image formats. If a property is not | ||
| 1091 | * defined for a particular image, this method returns the | ||
| 1092 | * <code>UndefinedProperty</code> field. If the properties | ||
| 1093 | * for this image are not yet known, then this method returns | ||
| 1094 | * <code>null</code> and the <code>ImageObserver</code> object is | ||
| 1095 | * notified later. The property name "comment" should be used to | ||
| 1096 | * store an optional comment that can be presented to the user as a | ||
| 1097 | * description of the image, its source, or its author. | ||
| 1098 | * @param name the property name | ||
| 1099 | * @param observer the <code>ImageObserver</code> that receives | ||
| 1100 | * notification regarding image information | ||
| 1101 | * @return an {@link Object} that is the property referred to by the | ||
| 1102 | * specified <code>name</code> or <code>null</code> if the | ||
| 1103 | * properties of this image are not yet known. | ||
| 1104 | * @throws <code>NullPointerException</code> if the property name is null. | ||
| 1105 | * @see ImageObserver | ||
| 1106 | * @see java.awt.Image#UndefinedProperty | ||
| 1107 | */ | ||
| 1108 | public Object getProperty(String name, ImageObserver observer) { | ||
| 1109 | return getProperty(name); | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | /** | ||
| 1113 | * Returns a property of the image by name. | ||
| 1114 | * @param name the property name | ||
| 1115 | * @return an <code>Object</code> that is the property referred to by | ||
| 1116 | * the specified <code>name</code>. | ||
| 1117 | * @throws <code>NullPointerException</code> if the property name is null. | ||
| 1118 | */ | ||
| 1119 | public Object getProperty(String name) { | ||
| 1120 | if (name == null) { | ||
| 1121 | throw new NullPointerException("null property name is not allowed"); | ||
| 1122 | } | ||
| 1123 | if (properties == null) { | ||
| 1124 | return java.awt.Image.UndefinedProperty; | ||
| 1125 | } | ||
| 1126 | Object o = properties.get(name); | ||
| 1127 | if (o == null) { | ||
| 1128 | o = java.awt.Image.UndefinedProperty; | ||
| 1129 | } | ||
| 1130 | return o; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | /** | ||
| 1134 | * This method returns a {@link Graphics2D}, but is here | ||
| 1135 | * for backwards compatibility. {@link #createGraphics() createGraphics} is more | ||
| 1136 | * convenient, since it is declared to return a | ||
| 1137 | * <code>Graphics2D</code>. | ||
| 1138 | * @return a <code>Graphics2D</code>, which can be used to draw into | ||
| 1139 | * this image. | ||
| 1140 | */ | ||
| 1141 | public java.awt.Graphics getGraphics() { | ||
| 1142 | return createGraphics(); | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | /** | ||
| 1146 | * Creates a <code>Graphics2D</code>, which can be used to draw into | ||
| 1147 | * this <code>BufferedImage</code>. | ||
| 1148 | * @return a <code>Graphics2D</code>, used for drawing into this | ||
| 1149 | * image. | ||
| 1150 | */ | ||
| 1151 | public Graphics2D createGraphics() { | ||
| 1152 | GraphicsEnvironment env = | ||
| 1153 | GraphicsEnvironment.getLocalGraphicsEnvironment(); | ||
| 1154 | return env.createGraphics(this); | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | /** | ||
| 1158 | * Returns a subimage defined by a specified rectangular region. | ||
| 1159 | * The returned <code>BufferedImage</code> shares the same | ||
| 1160 | * data array as the original image. | ||
| 1161 | * @param x the X coordinate of the upper-left corner of the | ||
| 1162 | * specified rectangular region | ||
| 1163 | * @param y the Y coordinate of the upper-left corner of the | ||
| 1164 | * specified rectangular region | ||
| 1165 | * @param w the width of the specified rectangular region | ||
| 1166 | * @param h the height of the specified rectangular region | ||
| 1167 | * @return a <code>BufferedImage</code> that is the subimage of this | ||
| 1168 | * <code>BufferedImage</code>. | ||
| 1169 | * @exception <code>RasterFormatException</code> if the specified | ||
| 1170 | * area is not contained within this <code>BufferedImage</code>. | ||
| 1171 | */ | ||
| 1172 | public BufferedImage getSubimage (int x, int y, int w, int h) { | ||
| 1173 | return new BufferedImage (colorModel, | ||
| 1174 | raster.createWritableChild(x, y, w, h, | ||
| 1175 | 0, 0, null), | ||
| 1176 | colorModel.isAlphaPremultiplied(), | ||
| 1177 | properties); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | /** | ||
| 1181 | * Returns whether or not the alpha has been premultiplied. It | ||
| 1182 | * returns <code>false</code> if there is no alpha. | ||
| 1183 | * @return <code>true</code> if the alpha has been premultiplied; | ||
| 1184 | * <code>false</code> otherwise. | ||
| 1185 | */ | ||
| 1186 | public boolean isAlphaPremultiplied() { | ||
| 1187 | return colorModel.isAlphaPremultiplied(); | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | /** | ||
| 1191 | * Forces the data to match the state specified in the | ||
| 1192 | * <code>isAlphaPremultiplied</code> variable. It may multiply or | ||
| 1193 | * divide the color raster data by alpha, or do nothing if the data is | ||
| 1194 | * in the correct state. | ||
| 1195 | * @param isAlphaPremultiplied <code>true</code> if the alpha has been | ||
| 1196 | * premultiplied; <code>false</code> otherwise. | ||
| 1197 | */ | ||
| 1198 | public void coerceData (boolean isAlphaPremultiplied) { | ||
| 1199 | if (colorModel.hasAlpha() && | ||
| 1200 | colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) { | ||
| 1201 | // Make the color model do the conversion | ||
| 1202 | colorModel = colorModel.coerceData (raster, isAlphaPremultiplied); | ||
| 1203 | } | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | /** | ||
| 1207 | * Returns a <code>String</code> representation of this | ||
| 1208 | * <code>BufferedImage</code> object and its values. | ||
| 1209 | * @return a <code>String</code> representing this | ||
| 1210 | * <code>BufferedImage</code>. | ||
| 1211 | */ | ||
| 1212 | public String toString() { | ||
| 1213 | return "BufferedImage@"+Integer.toHexString(hashCode()) | ||
| 1214 | +": type = "+imageType | ||
| 1215 | +" "+colorModel+" "+raster; | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | /** | ||
| 1219 | * Returns a {@link Vector} of {@link RenderedImage} objects that are | ||
| 1220 | * the immediate sources, not the sources of these immediate sources, | ||
| 1221 | * of image data for this <code>BufferedImage</code>. This | ||
| 1222 | * method returns <code>null</code> if the <code>BufferedImage</code> | ||
| 1223 | * has no information about its immediate sources. It returns an | ||
| 1224 | * empty <code>Vector</code> if the <code>BufferedImage</code> has no | ||
| 1225 | * immediate sources. | ||
| 1226 | * @return a <code>Vector</code> containing immediate sources of | ||
| 1227 | * this <code>BufferedImage</code> object's image date, or | ||
| 1228 | * <code>null</code> if this <code>BufferedImage</code> has | ||
| 1229 | * no information about its immediate sources, or an empty | ||
| 1230 | * <code>Vector</code> if this <code>BufferedImage</code> | ||
| 1231 | * has no immediate sources. | ||
| 1232 | */ | ||
| 1233 | public Vector<RenderedImage> getSources() { | ||
| 1234 | return null; | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | /** | ||
| 1238 | * Returns an array of names recognized by | ||
| 1239 | * {@link #getProperty(String) getProperty(String)} | ||
| 1240 | * or <code>null</code>, if no property names are recognized. | ||
| 1241 | * @return a <code>String</code> array containing all of the property | ||
| 1242 | * names that <code>getProperty(String)</code> recognizes; | ||
| 1243 | * or <code>null</code> if no property names are recognized. | ||
| 1244 | */ | ||
| 1245 | public String[] getPropertyNames() { | ||
| 1246 | return null; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | /** | ||
| 1250 | * Returns the minimum x coordinate of this | ||
| 1251 | * <code>BufferedImage</code>. This is always zero. | ||
| 1252 | * @return the minimum x coordinate of this | ||
| 1253 | * <code>BufferedImage</code>. | ||
| 1254 | */ | ||
| 1255 | public int getMinX() { | ||
| 1256 | return raster.getMinX(); | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | /** | ||
| 1260 | * Returns the minimum y coordinate of this | ||
| 1261 | * <code>BufferedImage</code>. This is always zero. | ||
| 1262 | * @return the minimum y coordinate of this | ||
| 1263 | * <code>BufferedImage</code>. | ||
| 1264 | */ | ||
| 1265 | public int getMinY() { | ||
| 1266 | return raster.getMinY(); | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | /** | ||
| 1270 | * Returns the <code>SampleModel</code> associated with this | ||
| 1271 | * <code>BufferedImage</code>. | ||
| 1272 | * @return the <code>SampleModel</code> of this | ||
| 1273 | * <code>BufferedImage</code>. | ||
| 1274 | */ | ||
| 1275 | public SampleModel getSampleModel() { | ||
| 1276 | return raster.getSampleModel(); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | /** | ||
| 1280 | * Returns the number of tiles in the x direction. | ||
| 1281 | * This is always one. | ||
| 1282 | * @return the number of tiles in the x direction. | ||
| 1283 | */ | ||
| 1284 | public int getNumXTiles() { | ||
| 1285 | return 1; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | /** | ||
| 1289 | * Returns the number of tiles in the y direction. | ||
| 1290 | * This is always one. | ||
| 1291 | * @return the number of tiles in the y direction. | ||
| 1292 | */ | ||
| 1293 | public int getNumYTiles() { | ||
| 1294 | return 1; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | /** | ||
| 1298 | * Returns the minimum tile index in the x direction. | ||
| 1299 | * This is always zero. | ||
| 1300 | * @return the minimum tile index in the x direction. | ||
| 1301 | */ | ||
| 1302 | public int getMinTileX() { | ||
| 1303 | return 0; | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | /** | ||
| 1307 | * Returns the minimum tile index in the y direction. | ||
| 1308 | * This is always zero. | ||
| 1309 | * @return the mininum tile index in the y direction. | ||
| 1310 | */ | ||
| 1311 | public int getMinTileY() { | ||
| 1312 | return 0; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | /** | ||
| 1316 | * Returns the tile width in pixels. | ||
| 1317 | * @return the tile width in pixels. | ||
| 1318 | */ | ||
| 1319 | public int getTileWidth() { | ||
| 1320 | return raster.getWidth(); | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | /** | ||
| 1324 | * Returns the tile height in pixels. | ||
| 1325 | * @return the tile height in pixels. | ||
| 1326 | */ | ||
| 1327 | public int getTileHeight() { | ||
| 1328 | return raster.getHeight(); | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | /** | ||
| 1332 | * Returns the x offset of the tile grid relative to the origin, | ||
| 1333 | * For example, the x coordinate of the location of tile | ||
| 1334 | * (0, 0). This is always zero. | ||
| 1335 | * @return the x offset of the tile grid. | ||
| 1336 | */ | ||
| 1337 | public int getTileGridXOffset() { | ||
| 1338 | return raster.getSampleModelTranslateX(); | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | /** | ||
| 1342 | * Returns the y offset of the tile grid relative to the origin, | ||
| 1343 | * For example, the y coordinate of the location of tile | ||
| 1344 | * (0, 0). This is always zero. | ||
| 1345 | * @return the y offset of the tile grid. | ||
| 1346 | */ | ||
| 1347 | public int getTileGridYOffset() { | ||
| 1348 | return raster.getSampleModelTranslateY(); | ||
| 1349 | } | ||
| 1350 | |||
| 1351 | /** | ||
| 1352 | * Returns tile (<code>tileX</code>, <code>tileY</code>). Note | ||
| 1353 | * that <code>tileX</code> and <code>tileY</code> are indices | ||
| 1354 | * into the tile array, not pixel locations. The <code>Raster</code> | ||
| 1355 | * that is returned is live, which means that it is updated if the | ||
| 1356 | * image is changed. | ||
| 1357 | * @param tileX the x index of the requested tile in the tile array | ||
| 1358 | * @param tileY the y index of the requested tile in the tile array | ||
| 1359 | * @return a <code>Raster</code> that is the tile defined by the | ||
| 1360 | * arguments <code>tileX</code> and <code>tileY</code>. | ||
| 1361 | * @exception <code>ArrayIndexOutOfBoundsException</code> if both | ||
| 1362 | * <code>tileX</code> and <code>tileY</code> are not | ||
| 1363 | * equal to 0 | ||
| 1364 | */ | ||
| 1365 | public Raster getTile(int tileX, int tileY) { | ||
| 1366 | if (tileX == 0 && tileY == 0) { | ||
| 1367 | return raster; | ||
| 1368 | } | ||
| 1369 | throw new ArrayIndexOutOfBoundsException("BufferedImages only have"+ | ||
| 1370 | " one tile with index 0,0"); | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | /** | ||
| 1374 | * Returns the image as one large tile. The <code>Raster</code> | ||
| 1375 | * returned is a copy of the image data is not updated if the | ||
| 1376 | * image is changed. | ||
| 1377 | * @return a <code>Raster</code> that is a copy of the image data. | ||
| 1378 | * @see #setData(Raster) | ||
| 1379 | */ | ||
| 1380 | public Raster getData() { | ||
| 1381 | |||
| 1382 | // REMIND : this allocates a whole new tile if raster is a | ||
| 1383 | // subtile. (It only copies in the requested area) | ||
| 1384 | // We should do something smarter. | ||
| 1385 | int width = raster.getWidth(); | ||
| 1386 | int height = raster.getHeight(); | ||
| 1387 | int startX = raster.getMinX(); | ||
| 1388 | int startY = raster.getMinY(); | ||
| 1389 | WritableRaster wr = | ||
| 1390 | Raster.createWritableRaster(raster.getSampleModel(), | ||
| 1391 | new Point(raster.getSampleModelTranslateX(), | ||
| 1392 | raster.getSampleModelTranslateY())); | ||
| 1393 | |||
| 1394 | Object tdata = null; | ||
| 1395 | |||
| 1396 | for (int i = startY; i < startY+height; i++) { | ||
| 1397 | tdata = raster.getDataElements(startX,i,width,1,tdata); | ||
| 1398 | wr.setDataElements(startX,i,width,1, tdata); | ||
| 1399 | } | ||
| 1400 | return wr; | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | /** | ||
| 1404 | * Computes and returns an arbitrary region of the | ||
| 1405 | * <code>BufferedImage</code>. The <code>Raster</code> returned is a | ||
| 1406 | * copy of the image data and is not updated if the image is | ||
| 1407 | * changed. | ||
| 1408 | * @param rect the region of the <code>BufferedImage</code> to be | ||
| 1409 | * returned. | ||
| 1410 | * @return a <code>Raster</code> that is a copy of the image data of | ||
| 1411 | * the specified region of the <code>BufferedImage</code> | ||
| 1412 | * @see #setData(Raster) | ||
| 1413 | */ | ||
| 1414 | public Raster getData(Rectangle rect) { | ||
| 1415 | SampleModel sm = raster.getSampleModel(); | ||
| 1416 | SampleModel nsm = sm.createCompatibleSampleModel(rect.width, | ||
| 1417 | rect.height); | ||
| 1418 | WritableRaster wr = Raster.createWritableRaster(nsm, | ||
| 1419 | rect.getLocation()); | ||
| 1420 | int width = rect.width; | ||
| 1421 | int height = rect.height; | ||
| 1422 | int startX = rect.x; | ||
| 1423 | int startY = rect.y; | ||
| 1424 | |||
| 1425 | Object tdata = null; | ||
| 1426 | |||
| 1427 | for (int i = startY; i < startY+height; i++) { | ||
| 1428 | tdata = raster.getDataElements(startX,i,width,1,tdata); | ||
| 1429 | wr.setDataElements(startX,i,width,1, tdata); | ||
| 1430 | } | ||
| 1431 | return wr; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | /** | ||
| 1435 | * Computes an arbitrary rectangular region of the | ||
| 1436 | * <code>BufferedImage</code> and copies it into a specified | ||
| 1437 | * <code>WritableRaster</code>. The region to be computed is | ||
| 1438 | * determined from the bounds of the specified | ||
| 1439 | * <code>WritableRaster</code>. The specified | ||
| 1440 | * <code>WritableRaster</code> must have a | ||
| 1441 | * <code>SampleModel</code> that is compatible with this image. If | ||
| 1442 | * <code>outRaster</code> is <code>null</code>, | ||
| 1443 | * an appropriate <code>WritableRaster</code> is created. | ||
| 1444 | * @param outRaster a <code>WritableRaster</code> to hold the returned | ||
| 1445 | * part of the image, or <code>null</code> | ||
| 1446 | * @return a reference to the supplied or created | ||
| 1447 | * <code>WritableRaster</code>. | ||
| 1448 | */ | ||
| 1449 | public WritableRaster copyData(WritableRaster outRaster) { | ||
| 1450 | if (outRaster == null) { | ||
| 1451 | return (WritableRaster) getData(); | ||
| 1452 | } | ||
| 1453 | int width = outRaster.getWidth(); | ||
| 1454 | int height = outRaster.getHeight(); | ||
| 1455 | int startX = outRaster.getMinX(); | ||
| 1456 | int startY = outRaster.getMinY(); | ||
| 1457 | |||
| 1458 | Object tdata = null; | ||
| 1459 | |||
| 1460 | for (int i = startY; i < startY+height; i++) { | ||
| 1461 | tdata = raster.getDataElements(startX,i,width,1,tdata); | ||
| 1462 | outRaster.setDataElements(startX,i,width,1, tdata); | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | return outRaster; | ||
| 1466 | } | ||
| 1467 | |||
| 1468 | /** | ||
| 1469 | * Sets a rectangular region of the image to the contents of the | ||
| 1470 | * specified <code>Raster</code> <code>r</code>, which is | ||
| 1471 | * assumed to be in the same coordinate space as the | ||
| 1472 | * <code>BufferedImage</code>. The operation is clipped to the bounds | ||
| 1473 | * of the <code>BufferedImage</code>. | ||
| 1474 | * @param r the specified <code>Raster</code> | ||
| 1475 | * @see #getData | ||
| 1476 | * @see #getData(Rectangle) | ||
| 1477 | */ | ||
| 1478 | public void setData(Raster r) { | ||
| 1479 | int width = r.getWidth(); | ||
| 1480 | int height = r.getHeight(); | ||
| 1481 | int startX = r.getMinX(); | ||
| 1482 | int startY = r.getMinY(); | ||
| 1483 | |||
| 1484 | int[] tdata = null; | ||
| 1485 | |||
| 1486 | // Clip to the current Raster | ||
| 1487 | Rectangle rclip = new Rectangle(startX, startY, width, height); | ||
| 1488 | Rectangle bclip = new Rectangle(0, 0, raster.width, raster.height); | ||
| 1489 | Rectangle intersect = rclip.intersection(bclip); | ||
| 1490 | if (intersect.isEmpty()) { | ||
| 1491 | return; | ||
| 1492 | } | ||
| 1493 | width = intersect.width; | ||
| 1494 | height = intersect.height; | ||
| 1495 | startX = intersect.x; | ||
| 1496 | startY = intersect.y; | ||
| 1497 | |||
| 1498 | // remind use get/setDataElements for speed if Rasters are | ||
| 1499 | // compatible | ||
| 1500 | for (int i = startY; i < startY+height; i++) { | ||
| 1501 | tdata = r.getPixels(startX,i,width,1,tdata); | ||
| 1502 | raster.setPixels(startX,i,width,1, tdata); | ||
| 1503 | } | ||
| 1504 | } | ||
| 1505 | |||
| 1506 | |||
| 1507 | /** | ||
| 1508 | * Adds a tile observer. If the observer is already present, | ||
| 1509 | * it receives multiple notifications. | ||
| 1510 | * @param to the specified {@link TileObserver} | ||
| 1511 | */ | ||
| 1512 | public void addTileObserver (TileObserver to) { | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | /** | ||
| 1516 | * Removes a tile observer. If the observer was not registered, | ||
| 1517 | * nothing happens. If the observer was registered for multiple | ||
| 1518 | * notifications, it is now registered for one fewer notification. | ||
| 1519 | * @param to the specified <code>TileObserver</code>. | ||
| 1520 | */ | ||
| 1521 | public void removeTileObserver (TileObserver to) { | ||
| 1522 | } | ||
| 1523 | |||
| 1524 | /** | ||
| 1525 | * Returns whether or not a tile is currently checked out for writing. | ||
| 1526 | * @param tileX the x index of the tile. | ||
| 1527 | * @param tileY the y index of the tile. | ||
| 1528 | * @return <code>true</code> if the tile specified by the specified | ||
| 1529 | * indices is checked out for writing; <code>false</code> | ||
| 1530 | * otherwise. | ||
| 1531 | * @exception <code>ArrayIndexOutOfBoundsException</code> if both | ||
| 1532 | * <code>tileX</code> and <code>tileY</code> are not equal | ||
| 1533 | * to 0 | ||
| 1534 | */ | ||
| 1535 | public boolean isTileWritable (int tileX, int tileY) { | ||
| 1536 | if (tileX == 0 && tileY == 0) { | ||
| 1537 | return true; | ||
| 1538 | } | ||
| 1539 | throw new IllegalArgumentException("Only 1 tile in image"); | ||
| 1540 | } | ||
| 1541 | |||
| 1542 | /** | ||
| 1543 | * Returns an array of {@link Point} objects indicating which tiles | ||
| 1544 | * are checked out for writing. Returns <code>null</code> if none are | ||
| 1545 | * checked out. | ||
| 1546 | * @return a <code>Point</code> array that indicates the tiles that | ||
| 1547 | * are checked out for writing, or <code>null</code> if no | ||
| 1548 | * tiles are checked out for writing. | ||
| 1549 | */ | ||
| 1550 | public Point[] getWritableTileIndices() { | ||
| 1551 | Point[] p = new Point[1]; | ||
| 1552 | p[0] = new Point(0, 0); | ||
| 1553 | |||
| 1554 | return p; | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | /** | ||
| 1558 | * Returns whether or not any tile is checked out for writing. | ||
| 1559 | * Semantically equivalent to | ||
| 1560 | * <pre> | ||
| 1561 | * (getWritableTileIndices() != null). | ||
| 1562 | * </pre> | ||
| 1563 | * @return <code>true</code> if any tile is checked out for writing; | ||
| 1564 | * <code>false</code> otherwise. | ||
| 1565 | */ | ||
| 1566 | public boolean hasTileWriters () { | ||
| 1567 | return true; | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | /** | ||
| 1571 | * Checks out a tile for writing. All registered | ||
| 1572 | * <code>TileObservers</code> are notified when a tile goes from having | ||
| 1573 | * no writers to having one writer. | ||
| 1574 | * @param tileX the x index of the tile | ||
| 1575 | * @param tileY the y index of the tile | ||
| 1576 | * @return a <code>WritableRaster</code> that is the tile, indicated by | ||
| 1577 | * the specified indices, to be checked out for writing. | ||
| 1578 | */ | ||
| 1579 | public WritableRaster getWritableTile (int tileX, int tileY) { | ||
| 1580 | return raster; | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | /** | ||
| 1584 | * Relinquishes permission to write to a tile. If the caller | ||
| 1585 | * continues to write to the tile, the results are undefined. | ||
| 1586 | * Calls to this method should only appear in matching pairs | ||
| 1587 | * with calls to {@link #getWritableTile(int, int) getWritableTile(int, int)}. Any other leads | ||
| 1588 | * to undefined results. All registered <code>TileObservers</code> | ||
| 1589 | * are notified when a tile goes from having one writer to having no | ||
| 1590 | * writers. | ||
| 1591 | * @param tileX the x index of the tile | ||
| 1592 | * @param tileY the y index of the tile | ||
| 1593 | */ | ||
| 1594 | public void releaseWritableTile (int tileX, int tileY) { | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | /** | ||
| 1598 | * Returns the transparency. Returns either OPAQUE, BITMASK, | ||
| 1599 | * or TRANSLUCENT. | ||
| 1600 | * @return the transparency of this <code>BufferedImage</code>. | ||
| 1601 | * @see Transparency#OPAQUE | ||
| 1602 | * @see Transparency#BITMASK | ||
| 1603 | * @see Transparency#TRANSLUCENT | ||
| 1604 | * @since 1.5 | ||
| 1605 | */ | ||
| 1606 | public int getTransparency() { | ||
| 1607 | return colorModel.getTransparency(); | ||
| 1608 | } | ||
| 1609 | } | ||
Binary file not shown.
| @@ -0,0 +1,417 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.util.Hashtable; | ||
| 29 | import java.awt.image.ImageConsumer; | ||
| 30 | import java.awt.image.ImageFilter; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * The <code>BufferedImageFilter</code> class subclasses an | ||
| 34 | * <code>ImageFilter</code> to provide a simple means of | ||
| 35 | * using a single-source/single-destination image operator | ||
| 36 | * ({@link BufferedImageOp}) to filter a <code>BufferedImage</code> | ||
| 37 | * in the Image Producer/Consumer/Observer | ||
| 38 | * paradigm. Examples of these image operators are: {@link ConvolveOp}, | ||
| 39 | * {@link AffineTransformOp} and {@link LookupOp}. | ||
| 40 | * | ||
| 41 | * @see ImageFilter | ||
| 42 | * @see BufferedImage | ||
| 43 | * @see BufferedImageOp | ||
| 44 | */ | ||
| 45 | |||
| 46 | public class BufferedImageFilter extends ImageFilter implements Cloneable { | ||
| 47 | BufferedImageOp bufferedImageOp; | ||
| 48 | ColorModel model; | ||
| 49 | int width; | ||
| 50 | int height; | ||
| 51 | byte[] bytePixels; | ||
| 52 | int[] intPixels; | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Constructs a <code>BufferedImageFilter</code> with the | ||
| 56 | * specified single-source/single-destination operator. | ||
| 57 | * @param op the specified <code>BufferedImageOp</code> to | ||
| 58 | * use to filter a <code>BufferedImage</code> | ||
| 59 | * @throws NullPointerException if op is null | ||
| 60 | */ | ||
| 61 | public BufferedImageFilter (BufferedImageOp op) { | ||
| 62 | super(); | ||
| 63 | if (op == null) { | ||
| 64 | throw new NullPointerException("Operation cannot be null"); | ||
| 65 | } | ||
| 66 | bufferedImageOp = op; | ||
| 67 | } | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Returns the <code>BufferedImageOp</code>. | ||
| 71 | * @return the operator of this <code>BufferedImageFilter</code>. | ||
| 72 | */ | ||
| 73 | public BufferedImageOp getBufferedImageOp() { | ||
| 74 | return bufferedImageOp; | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Filters the information provided in the | ||
| 79 | * {@link ImageConsumer#setDimensions(int, int) setDimensions } method | ||
| 80 | * of the {@link ImageConsumer} interface. | ||
| 81 | * <p> | ||
| 82 | * Note: This method is intended to be called by the | ||
| 83 | * {@link ImageProducer} of the <code>Image</code> whose pixels are | ||
| 84 | * being filtered. Developers using this class to retrieve pixels from | ||
| 85 | * an image should avoid calling this method directly since that | ||
| 86 | * operation could result in problems with retrieving the requested | ||
| 87 | * pixels. | ||
| 88 | * <p> | ||
| 89 | * @param width the width to which to set the width of this | ||
| 90 | * <code>BufferedImageFilter</code> | ||
| 91 | * @param height the height to which to set the height of this | ||
| 92 | * <code>BufferedImageFilter</code> | ||
| 93 | * @see ImageConsumer#setDimensions | ||
| 94 | */ | ||
| 95 | public void setDimensions(int width, int height) { | ||
| 96 | if (width <= 0 || height <= 0) { | ||
| 97 | imageComplete(STATICIMAGEDONE); | ||
| 98 | return; | ||
| 99 | } | ||
| 100 | this.width = width; | ||
| 101 | this.height = height; | ||
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * Filters the information provided in the | ||
| 106 | * {@link ImageConsumer#setColorModel(ColorModel) setColorModel} method | ||
| 107 | * of the <code>ImageConsumer</code> interface. | ||
| 108 | * <p> | ||
| 109 | * If <code>model</code> is <code>null</code>, this | ||
| 110 | * method clears the current <code>ColorModel</code> of this | ||
| 111 | * <code>BufferedImageFilter</code>. | ||
| 112 | * <p> | ||
| 113 | * Note: This method is intended to be called by the | ||
| 114 | * <code>ImageProducer</code> of the <code>Image</code> | ||
| 115 | * whose pixels are being filtered. Developers using this | ||
| 116 | * class to retrieve pixels from an image | ||
| 117 | * should avoid calling this method directly since that | ||
| 118 | * operation could result in problems with retrieving the | ||
| 119 | * requested pixels. | ||
| 120 | * @param model the {@link ColorModel} to which to set the | ||
| 121 | * <code>ColorModel</code> of this <code>BufferedImageFilter</code> | ||
| 122 | * @see ImageConsumer#setColorModel | ||
| 123 | */ | ||
| 124 | public void setColorModel(ColorModel model) { | ||
| 125 | this.model = model; | ||
| 126 | } | ||
| 127 | |||
| 128 | private void convertToRGB() { | ||
| 129 | int size = width * height; | ||
| 130 | int newpixels[] = new int[size]; | ||
| 131 | if (bytePixels != null) { | ||
| 132 | for (int i = 0; i < size; i++) { | ||
| 133 | newpixels[i] = this.model.getRGB(bytePixels[i] & 0xff); | ||
| 134 | } | ||
| 135 | } else if (intPixels != null) { | ||
| 136 | for (int i = 0; i < size; i++) { | ||
| 137 | newpixels[i] = this.model.getRGB(intPixels[i]); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | bytePixels = null; | ||
| 141 | intPixels = newpixels; | ||
| 142 | this.model = ColorModel.getRGBdefault(); | ||
| 143 | } | ||
| 144 | |||
| 145 | /** | ||
| 146 | * Filters the information provided in the <code>setPixels</code> | ||
| 147 | * method of the <code>ImageConsumer</code> interface which takes | ||
| 148 | * an array of bytes. | ||
| 149 | * <p> | ||
| 150 | * Note: This method is intended to be called by the | ||
| 151 | * <code>ImageProducer</code> of the <code>Image</code> whose pixels | ||
| 152 | * are being filtered. Developers using | ||
| 153 | * this class to retrieve pixels from an image should avoid calling | ||
| 154 | * this method directly since that operation could result in problems | ||
| 155 | * with retrieving the requested pixels. | ||
| 156 | * @throws IllegalArgumentException if width or height are less than | ||
| 157 | * zero. | ||
| 158 | * @see ImageConsumer#setPixels(int, int, int, int, ColorModel, byte[], | ||
| 159 | int, int) | ||
| 160 | */ | ||
| 161 | public void setPixels(int x, int y, int w, int h, | ||
| 162 | ColorModel model, byte pixels[], int off, | ||
| 163 | int scansize) { | ||
| 164 | // Fix 4184230 | ||
| 165 | if (w < 0 || h < 0) { | ||
| 166 | throw new IllegalArgumentException("Width ("+w+ | ||
| 167 | ") and height ("+h+ | ||
| 168 | ") must be > 0"); | ||
| 169 | } | ||
| 170 | // Nothing to do | ||
| 171 | if (w == 0 || h == 0) { | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | if (y < 0) { | ||
| 175 | int diff = -y; | ||
| 176 | if (diff >= h) { | ||
| 177 | return; | ||
| 178 | } | ||
| 179 | off += scansize * diff; | ||
| 180 | y += diff; | ||
| 181 | h -= diff; | ||
| 182 | } | ||
| 183 | if (y + h > height) { | ||
| 184 | h = height - y; | ||
| 185 | if (h <= 0) { | ||
| 186 | return; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | if (x < 0) { | ||
| 190 | int diff = -x; | ||
| 191 | if (diff >= w) { | ||
| 192 | return; | ||
| 193 | } | ||
| 194 | off += diff; | ||
| 195 | x += diff; | ||
| 196 | w -= diff; | ||
| 197 | } | ||
| 198 | if (x + w > width) { | ||
| 199 | w = width - x; | ||
| 200 | if (w <= 0) { | ||
| 201 | return; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | int dstPtr = y*width + x; | ||
| 205 | if (intPixels == null) { | ||
| 206 | if (bytePixels == null) { | ||
| 207 | bytePixels = new byte[width*height]; | ||
| 208 | this.model = model; | ||
| 209 | } else if (this.model != model) { | ||
| 210 | convertToRGB(); | ||
| 211 | } | ||
| 212 | if (bytePixels != null) { | ||
| 213 | for (int sh = h; sh > 0; sh--) { | ||
| 214 | System.arraycopy(pixels, off, bytePixels, dstPtr, w); | ||
| 215 | off += scansize; | ||
| 216 | dstPtr += width; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | } | ||
| 220 | if (intPixels != null) { | ||
| 221 | int dstRem = width - w; | ||
| 222 | int srcRem = scansize - w; | ||
| 223 | for (int sh = h; sh > 0; sh--) { | ||
| 224 | for (int sw = w; sw > 0; sw--) { | ||
| 225 | intPixels[dstPtr++] = model.getRGB(pixels[off++]&0xff); | ||
| 226 | } | ||
| 227 | off += srcRem; | ||
| 228 | dstPtr += dstRem; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | } | ||
| 232 | /** | ||
| 233 | * Filters the information provided in the <code>setPixels</code> | ||
| 234 | * method of the <code>ImageConsumer</code> interface which takes | ||
| 235 | * an array of integers. | ||
| 236 | * <p> | ||
| 237 | * Note: This method is intended to be called by the | ||
| 238 | * <code>ImageProducer</code> of the <code>Image</code> whose | ||
| 239 | * pixels are being filtered. Developers using this class to | ||
| 240 | * retrieve pixels from an image should avoid calling this method | ||
| 241 | * directly since that operation could result in problems | ||
| 242 | * with retrieving the requested pixels. | ||
| 243 | * @throws IllegalArgumentException if width or height are less than | ||
| 244 | * zero. | ||
| 245 | * @see ImageConsumer#setPixels(int, int, int, int, ColorModel, int[], | ||
| 246 | int, int) | ||
| 247 | */ | ||
| 248 | public void setPixels(int x, int y, int w, int h, | ||
| 249 | ColorModel model, int pixels[], int off, | ||
| 250 | int scansize) { | ||
| 251 | // Fix 4184230 | ||
| 252 | if (w < 0 || h < 0) { | ||
| 253 | throw new IllegalArgumentException("Width ("+w+ | ||
| 254 | ") and height ("+h+ | ||
| 255 | ") must be > 0"); | ||
| 256 | } | ||
| 257 | // Nothing to do | ||
| 258 | if (w == 0 || h == 0) { | ||
| 259 | return; | ||
| 260 | } | ||
| 261 | if (y < 0) { | ||
| 262 | int diff = -y; | ||
| 263 | if (diff >= h) { | ||
| 264 | return; | ||
| 265 | } | ||
| 266 | off += scansize * diff; | ||
| 267 | y += diff; | ||
| 268 | h -= diff; | ||
| 269 | } | ||
| 270 | if (y + h > height) { | ||
| 271 | h = height - y; | ||
| 272 | if (h <= 0) { | ||
| 273 | return; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | if (x < 0) { | ||
| 277 | int diff = -x; | ||
| 278 | if (diff >= w) { | ||
| 279 | return; | ||
| 280 | } | ||
| 281 | off += diff; | ||
| 282 | x += diff; | ||
| 283 | w -= diff; | ||
| 284 | } | ||
| 285 | if (x + w > width) { | ||
| 286 | w = width - x; | ||
| 287 | if (w <= 0) { | ||
| 288 | return; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | if (intPixels == null) { | ||
| 293 | if (bytePixels == null) { | ||
| 294 | intPixels = new int[width * height]; | ||
| 295 | this.model = model; | ||
| 296 | } else { | ||
| 297 | convertToRGB(); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | int dstPtr = y*width + x; | ||
| 301 | if (this.model == model) { | ||
| 302 | for (int sh = h; sh > 0; sh--) { | ||
| 303 | System.arraycopy(pixels, off, intPixels, dstPtr, w); | ||
| 304 | off += scansize; | ||
| 305 | dstPtr += width; | ||
| 306 | } | ||
| 307 | } else { | ||
| 308 | if (this.model != ColorModel.getRGBdefault()) { | ||
| 309 | convertToRGB(); | ||
| 310 | } | ||
| 311 | int dstRem = width - w; | ||
| 312 | int srcRem = scansize - w; | ||
| 313 | for (int sh = h; sh > 0; sh--) { | ||
| 314 | for (int sw = w; sw > 0; sw--) { | ||
| 315 | intPixels[dstPtr++] = model.getRGB(pixels[off++]); | ||
| 316 | } | ||
| 317 | off += srcRem; | ||
| 318 | dstPtr += dstRem; | ||
| 319 | } | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | /** | ||
| 324 | * Filters the information provided in the <code>imageComplete</code> | ||
| 325 | * method of the <code>ImageConsumer</code> interface. | ||
| 326 | * <p> | ||
| 327 | * Note: This method is intended to be called by the | ||
| 328 | * <code>ImageProducer</code> of the <code>Image</code> whose pixels | ||
| 329 | * are being filtered. Developers using | ||
| 330 | * this class to retrieve pixels from an image should avoid calling | ||
| 331 | * this method directly since that operation could result in problems | ||
| 332 | * with retrieving the requested pixels. | ||
| 333 | * @param status the status of image loading | ||
| 334 | * @throws ImagingOpException if there was a problem calling the filter | ||
| 335 | * method of the <code>BufferedImageOp</code> associated with this | ||
| 336 | * instance. | ||
| 337 | * @see ImageConsumer#imageComplete | ||
| 338 | */ | ||
| 339 | public void imageComplete(int status) { | ||
| 340 | WritableRaster wr; | ||
| 341 | switch(status) { | ||
| 342 | case IMAGEERROR: | ||
| 343 | case IMAGEABORTED: | ||
| 344 | // reinitialize the params | ||
| 345 | model = null; | ||
| 346 | width = -1; | ||
| 347 | height = -1; | ||
| 348 | intPixels = null; | ||
| 349 | bytePixels = null; | ||
| 350 | break; | ||
| 351 | |||
| 352 | case SINGLEFRAMEDONE: | ||
| 353 | case STATICIMAGEDONE: | ||
| 354 | if (width <= 0 || height <= 0) break; | ||
| 355 | if (model instanceof DirectColorModel) { | ||
| 356 | if (intPixels == null) break; | ||
| 357 | wr = createDCMraster(); | ||
| 358 | } | ||
| 359 | else if (model instanceof IndexColorModel) { | ||
| 360 | int[] bandOffsets = {0}; | ||
| 361 | if (bytePixels == null) break; | ||
| 362 | DataBufferByte db = new DataBufferByte(bytePixels, | ||
| 363 | width*height); | ||
| 364 | wr = Raster.createInterleavedRaster(db, width, height, width, | ||
| 365 | 1, bandOffsets, null); | ||
| 366 | } | ||
| 367 | else { | ||
| 368 | convertToRGB(); | ||
| 369 | if (intPixels == null) break; | ||
| 370 | wr = createDCMraster(); | ||
| 371 | } | ||
| 372 | BufferedImage bi = new BufferedImage(model, wr, | ||
| 373 | model.isAlphaPremultiplied(), | ||
| 374 | null); | ||
| 375 | bi = bufferedImageOp.filter(bi, null); | ||
| 376 | WritableRaster r = bi.getRaster(); | ||
| 377 | ColorModel cm = bi.getColorModel(); | ||
| 378 | int w = r.getWidth(); | ||
| 379 | int h = r.getHeight(); | ||
| 380 | consumer.setDimensions(w, h); | ||
| 381 | consumer.setColorModel(cm); | ||
| 382 | if (cm instanceof DirectColorModel) { | ||
| 383 | DataBufferInt db = (DataBufferInt) r.getDataBuffer(); | ||
| 384 | consumer.setPixels(0, 0, w, h, | ||
| 385 | cm, db.getData(), 0, w); | ||
| 386 | } | ||
| 387 | else if (cm instanceof IndexColorModel) { | ||
| 388 | DataBufferByte db = (DataBufferByte) r.getDataBuffer(); | ||
| 389 | consumer.setPixels(0, 0, w, h, | ||
| 390 | cm, db.getData(), 0, w); | ||
| 391 | } | ||
| 392 | else { | ||
| 393 | throw new InternalError("Unknown color model "+cm); | ||
| 394 | } | ||
| 395 | break; | ||
| 396 | } | ||
| 397 | consumer.imageComplete(status); | ||
| 398 | } | ||
| 399 | |||
| 400 | private final WritableRaster createDCMraster() { | ||
| 401 | WritableRaster wr; | ||
| 402 | DirectColorModel dcm = (DirectColorModel) model; | ||
| 403 | boolean hasAlpha = model.hasAlpha(); | ||
| 404 | int[] bandMasks = new int[3+(hasAlpha ? 1 : 0)]; | ||
| 405 | bandMasks[0] = dcm.getRedMask(); | ||
| 406 | bandMasks[1] = dcm.getGreenMask(); | ||
| 407 | bandMasks[2] = dcm.getBlueMask(); | ||
| 408 | if (hasAlpha) { | ||
| 409 | bandMasks[3] = dcm.getAlphaMask(); | ||
| 410 | } | ||
| 411 | DataBufferInt db = new DataBufferInt(intPixels, width*height); | ||
| 412 | wr = Raster.createPackedRaster(db, width, height, width, | ||
| 413 | bandMasks, null); | ||
| 414 | return wr; | ||
| 415 | } | ||
| 416 | |||
| 417 | } | ||
Binary file not shown.
| @@ -0,0 +1,136 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.geom.Rectangle2D; | ||
| 29 | import java.awt.geom.Point2D; | ||
| 30 | import java.awt.RenderingHints; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * This interface describes single-input/single-output | ||
| 34 | * operations performed on <CODE>BufferedImage</CODE> objects. | ||
| 35 | * It is implemented by <CODE>AffineTransformOp</CODE>, | ||
| 36 | * <CODE>ConvolveOp</CODE>, <CODE>ColorConvertOp</CODE>, <CODE>RescaleOp</CODE>, | ||
| 37 | * and <CODE>LookupOp</CODE>. These objects can be passed into | ||
| 38 | * a <CODE>BufferedImageFilter</CODE> to operate on a | ||
| 39 | * <CODE>BufferedImage</CODE> in the | ||
| 40 | * ImageProducer-ImageFilter-ImageConsumer paradigm. | ||
| 41 | * <p> | ||
| 42 | * Classes that implement this | ||
| 43 | * interface must specify whether or not they allow in-place filtering-- | ||
| 44 | * filter operations where the source object is equal to the destination | ||
| 45 | * object. | ||
| 46 | * <p> | ||
| 47 | * This interface cannot be used to describe more sophisticated operations | ||
| 48 | * such as those that take multiple sources. Note that this restriction also | ||
| 49 | * means that the values of the destination pixels prior to the operation are | ||
| 50 | * not used as input to the filter operation. | ||
| 51 | |||
| 52 | * @see BufferedImage | ||
| 53 | * @see BufferedImageFilter | ||
| 54 | * @see AffineTransformOp | ||
| 55 | * @see BandCombineOp | ||
| 56 | * @see ColorConvertOp | ||
| 57 | * @see ConvolveOp | ||
| 58 | * @see LookupOp | ||
| 59 | * @see RescaleOp | ||
| 60 | */ | ||
| 61 | public interface BufferedImageOp { | ||
| 62 | /** | ||
| 63 | * Performs a single-input/single-output operation on a | ||
| 64 | * <CODE>BufferedImage</CODE>. | ||
| 65 | * If the color models for the two images do not match, a color | ||
| 66 | * conversion into the destination color model is performed. | ||
| 67 | * If the destination image is null, | ||
| 68 | * a <CODE>BufferedImage</CODE> with an appropriate <CODE>ColorModel</CODE> | ||
| 69 | * is created. | ||
| 70 | * <p> | ||
| 71 | * An <CODE>IllegalArgumentException</CODE> may be thrown if the source | ||
| 72 | * and/or destination image is incompatible with the types of images $ | ||
| 73 | * allowed by the class implementing this filter. | ||
| 74 | * | ||
| 75 | * @param src The <CODE>BufferedImage</CODE> to be filtered | ||
| 76 | * @param dest The <CODE>BufferedImage</CODE> in which to store the results$ | ||
| 77 | * | ||
| 78 | * @return The filtered <CODE>BufferedImage</CODE>. | ||
| 79 | * | ||
| 80 | * @throws IllegalArgumentException If the source and/or destination | ||
| 81 | * image is not compatible with the types of images allowed by the class | ||
| 82 | * implementing this filter. | ||
| 83 | */ | ||
| 84 | public BufferedImage filter(BufferedImage src, BufferedImage dest); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Returns the bounding box of the filtered destination image. | ||
| 88 | * An <CODE>IllegalArgumentException</CODE> may be thrown if the source | ||
| 89 | * image is incompatible with the types of images allowed | ||
| 90 | * by the class implementing this filter. | ||
| 91 | * | ||
| 92 | * @param src The <CODE>BufferedImage</CODE> to be filtered | ||
| 93 | * | ||
| 94 | * @return The <CODE>Rectangle2D</CODE> representing the destination | ||
| 95 | * image's bounding box. | ||
| 96 | */ | ||
| 97 | public Rectangle2D getBounds2D (BufferedImage src); | ||
| 98 | |||
| 99 | /** | ||
| 100 | * Creates a zeroed destination image with the correct size and number of | ||
| 101 | * bands. | ||
| 102 | * An <CODE>IllegalArgumentException</CODE> may be thrown if the source | ||
| 103 | * image is incompatible with the types of images allowed | ||
| 104 | * by the class implementing this filter. | ||
| 105 | * | ||
| 106 | * @param src The <CODE>BufferedImage</CODE> to be filtered | ||
| 107 | * @param destCM <CODE>ColorModel</CODE> of the destination. If null, | ||
| 108 | * the <CODE>ColorModel</CODE> of the source is used. | ||
| 109 | * | ||
| 110 | * @return The zeroed destination image. | ||
| 111 | */ | ||
| 112 | public BufferedImage createCompatibleDestImage (BufferedImage src, | ||
| 113 | ColorModel destCM); | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Returns the location of the corresponding destination point given a | ||
| 117 | * point in the source image. If <CODE>dstPt</CODE> is specified, it | ||
| 118 | * is used to hold the return value. | ||
| 119 | * @param srcPt the <code>Point2D</code> that represents the point in | ||
| 120 | * the source image | ||
| 121 | * @param dstPt The <CODE>Point2D</CODE> in which to store the result | ||
| 122 | * | ||
| 123 | * @return The <CODE>Point2D</CODE> in the destination image that | ||
| 124 | * corresponds to the specified point in the source image. | ||
| 125 | */ | ||
| 126 | public Point2D getPoint2D (Point2D srcPt, Point2D dstPt); | ||
| 127 | |||
| 128 | /** | ||
| 129 | * Returns the rendering hints for this operation. | ||
| 130 | * | ||
| 131 | * @return The <CODE>RenderingHints</CODE> object for this | ||
| 132 | * <CODE>BufferedImageOp</CODE>. Returns | ||
| 133 | * null if no hints have been set. | ||
| 134 | */ | ||
| 135 | public RenderingHints getRenderingHints(); | ||
| 136 | } | ||
Binary file not shown.
| @@ -0,0 +1,210 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | |||
| 29 | /** | ||
| 30 | * This class defines a lookup table object. The output of a | ||
| 31 | * lookup operation using an object of this class is interpreted | ||
| 32 | * as an unsigned byte quantity. The lookup table contains byte | ||
| 33 | * data arrays for one or more bands (or components) of an image, | ||
| 34 | * and it contains an offset which will be subtracted from the | ||
| 35 | * input values before indexing the arrays. This allows an array | ||
| 36 | * smaller than the native data size to be provided for a | ||
| 37 | * constrained input. If there is only one array in the lookup | ||
| 38 | * table, it will be applied to all bands. | ||
| 39 | * | ||
| 40 | * @see ShortLookupTable | ||
| 41 | * @see LookupOp | ||
| 42 | */ | ||
| 43 | public class ByteLookupTable extends LookupTable { | ||
| 44 | |||
| 45 | /** | ||
| 46 | * Constants | ||
| 47 | */ | ||
| 48 | |||
| 49 | byte data[][]; | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Constructs a ByteLookupTable object from an array of byte | ||
| 53 | * arrays representing a lookup table for each | ||
| 54 | * band. The offset will be subtracted from input | ||
| 55 | * values before indexing into the arrays. The number of | ||
| 56 | * bands is the length of the data argument. The | ||
| 57 | * data array for each band is stored as a reference. | ||
| 58 | * @param offset the value subtracted from the input values | ||
| 59 | * before indexing into the arrays | ||
| 60 | * @param data an array of byte arrays representing a lookup | ||
| 61 | * table for each band | ||
| 62 | * @throws IllegalArgumentException if <code>offset</code> is | ||
| 63 | * is less than 0 or if the length of <code>data</code> | ||
| 64 | * is less than 1 | ||
| 65 | */ | ||
| 66 | public ByteLookupTable(int offset, byte data[][]) { | ||
| 67 | super(offset,data.length); | ||
| 68 | numComponents = data.length; | ||
| 69 | numEntries = data[0].length; | ||
| 70 | this.data = new byte[numComponents][]; | ||
| 71 | // Allocate the array and copy the data reference | ||
| 72 | for (int i=0; i < numComponents; i++) { | ||
| 73 | this.data[i] = data[i]; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Constructs a ByteLookupTable object from an array | ||
| 79 | * of bytes representing a lookup table to be applied to all | ||
| 80 | * bands. The offset will be subtracted from input | ||
| 81 | * values before indexing into the array. | ||
| 82 | * The data array is stored as a reference. | ||
| 83 | * @param offset the value subtracted from the input values | ||
| 84 | * before indexing into the array | ||
| 85 | * @param data an array of bytes | ||
| 86 | * @throws IllegalArgumentException if <code>offset</code> is | ||
| 87 | * is less than 0 or if the length of <code>data</code> | ||
| 88 | * is less than 1 | ||
| 89 | */ | ||
| 90 | public ByteLookupTable(int offset, byte data[]) { | ||
| 91 | super(offset,data.length); | ||
| 92 | numComponents = 1; | ||
| 93 | numEntries = data.length; | ||
| 94 | this.data = new byte[1][]; | ||
| 95 | this.data[0] = data; | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * Returns the lookup table data by reference. If this ByteLookupTable | ||
| 100 | * was constructed using a single byte array, the length of the returned | ||
| 101 | * array is one. | ||
| 102 | * @return the data array of this <code>ByteLookupTable</code>. | ||
| 103 | */ | ||
| 104 | public final byte[][] getTable(){ | ||
| 105 | return data; | ||
| 106 | } | ||
| 107 | |||
| 108 | /** | ||
| 109 | * Returns an array of samples of a pixel, translated with the lookup | ||
| 110 | * table. The source and destination array can be the same array. | ||
| 111 | * Array <code>dst</code> is returned. | ||
| 112 | * | ||
| 113 | * @param src the source array. | ||
| 114 | * @param dst the destination array. This array must be at least as | ||
| 115 | * long as <code>src</code>. If <code>dst</code> is | ||
| 116 | * <code>null</code>, a new array will be allocated having the | ||
| 117 | * same length as <code>src</code>. | ||
| 118 | * @return the array <code>dst</code>, an <code>int</code> array of | ||
| 119 | * samples. | ||
| 120 | * @exception ArrayIndexOutOfBoundsException if <code>src</code> is | ||
| 121 | * longer than <code>dst</code> or if for any element | ||
| 122 | * <code>i</code> of <code>src</code>, | ||
| 123 | * <code>src[i]-offset</code> is either less than zero or | ||
| 124 | * greater than or equal to the length of the lookup table | ||
| 125 | * for any band. | ||
| 126 | */ | ||
| 127 | public int[] lookupPixel(int[] src, int[] dst){ | ||
| 128 | if (dst == null) { | ||
| 129 | // Need to alloc a new destination array | ||
| 130 | dst = new int[src.length]; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (numComponents == 1) { | ||
| 134 | // Apply one LUT to all bands | ||
| 135 | for (int i=0; i < src.length; i++) { | ||
| 136 | int s = src[i] - offset; | ||
| 137 | if (s < 0) { | ||
| 138 | throw new ArrayIndexOutOfBoundsException("src["+i+ | ||
| 139 | "]-offset is "+ | ||
| 140 | "less than zero"); | ||
| 141 | } | ||
| 142 | dst[i] = (int) data[0][s]; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | else { | ||
| 146 | for (int i=0; i < src.length; i++) { | ||
| 147 | int s = src[i] - offset; | ||
| 148 | if (s < 0) { | ||
| 149 | throw new ArrayIndexOutOfBoundsException("src["+i+ | ||
| 150 | "]-offset is "+ | ||
| 151 | "less than zero"); | ||
| 152 | } | ||
| 153 | dst[i] = (int) data[i][s]; | ||
| 154 | } | ||
| 155 | } | ||
| 156 | return dst; | ||
| 157 | } | ||
| 158 | |||
| 159 | /** | ||
| 160 | * Returns an array of samples of a pixel, translated with the lookup | ||
| 161 | * table. The source and destination array can be the same array. | ||
| 162 | * Array <code>dst</code> is returned. | ||
| 163 | * | ||
| 164 | * @param src the source array. | ||
| 165 | * @param dst the destination array. This array must be at least as | ||
| 166 | * long as <code>src</code>. If <code>dst</code> is | ||
| 167 | * <code>null</code>, a new array will be allocated having the | ||
| 168 | * same length as <code>src</code>. | ||
| 169 | * @return the array <code>dst</code>, an <code>int</code> array of | ||
| 170 | * samples. | ||
| 171 | * @exception ArrayIndexOutOfBoundsException if <code>src</code> is | ||
| 172 | * longer than <code>dst</code> or if for any element | ||
| 173 | * <code>i</code> of <code>src</code>, | ||
| 174 | * <code>(src[i]&0xff)-offset</code> is either less than | ||
| 175 | * zero or greater than or equal to the length of the | ||
| 176 | * lookup table for any band. | ||
| 177 | */ | ||
| 178 | public byte[] lookupPixel(byte[] src, byte[] dst){ | ||
| 179 | if (dst == null) { | ||
| 180 | // Need to alloc a new destination array | ||
| 181 | dst = new byte[src.length]; | ||
| 182 | } | ||
| 183 | |||
| 184 | if (numComponents == 1) { | ||
| 185 | // Apply one LUT to all bands | ||
| 186 | for (int i=0; i < src.length; i++) { | ||
| 187 | int s = (src[i]&0xff) - offset; | ||
| 188 | if (s < 0) { | ||
| 189 | throw new ArrayIndexOutOfBoundsException("src["+i+ | ||
| 190 | "]-offset is "+ | ||
| 191 | "less than zero"); | ||
| 192 | } | ||
| 193 | dst[i] = data[0][s]; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | else { | ||
| 197 | for (int i=0; i < src.length; i++) { | ||
| 198 | int s = (src[i]&0xff) - offset; | ||
| 199 | if (s < 0) { | ||
| 200 | throw new ArrayIndexOutOfBoundsException("src["+i+ | ||
| 201 | "]-offset is "+ | ||
| 202 | "less than zero"); | ||
| 203 | } | ||
| 204 | dst[i] = data[i][s]; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | return dst; | ||
| 208 | } | ||
| 209 | |||
| 210 | } | ||
Binary file not shown.
| @@ -0,0 +1,1109 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 | /********************************************************************** | ||
| 27 | ********************************************************************** | ||
| 28 | ********************************************************************** | ||
| 29 | *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** | ||
| 30 | *** As an unpublished work pursuant to Title 17 of the United *** | ||
| 31 | *** States Code. All rights reserved. *** | ||
| 32 | ********************************************************************** | ||
| 33 | ********************************************************************** | ||
| 34 | **********************************************************************/ | ||
| 35 | |||
| 36 | package java.awt.image; | ||
| 37 | |||
| 38 | import java.awt.Point; | ||
| 39 | import java.awt.Graphics2D; | ||
| 40 | import java.awt.color.*; | ||
| 41 | import sun.java2d.cmm.ColorTransform; | ||
| 42 | import sun.java2d.cmm.CMSManager; | ||
| 43 | import sun.java2d.cmm.ProfileDeferralMgr; | ||
| 44 | import sun.java2d.cmm.PCMM; | ||
| 45 | import java.awt.geom.Rectangle2D; | ||
| 46 | import java.awt.geom.Point2D; | ||
| 47 | import java.awt.RenderingHints; | ||
| 48 | |||
| 49 | /** | ||
| 50 | * This class performs a pixel-by-pixel color conversion of the data in | ||
| 51 | * the source image. The resulting color values are scaled to the precision | ||
| 52 | * of the destination image. Color conversion can be specified | ||
| 53 | * via an array of ColorSpace objects or an array of ICC_Profile objects. | ||
| 54 | * <p> | ||
| 55 | * If the source is a BufferedImage with premultiplied alpha, the | ||
| 56 | * color components are divided by the alpha component before color conversion. | ||
| 57 | * If the destination is a BufferedImage with premultiplied alpha, the | ||
| 58 | * color components are multiplied by the alpha component after conversion. | ||
| 59 | * Rasters are treated as having no alpha channel, i.e. all bands are | ||
| 60 | * color bands. | ||
| 61 | * <p> | ||
| 62 | * If a RenderingHints object is specified in the constructor, the | ||
| 63 | * color rendering hint and the dithering hint may be used to control | ||
| 64 | * color conversion. | ||
| 65 | * <p> | ||
| 66 | * Note that Source and Destination may be the same object. | ||
| 67 | * <p> | ||
| 68 | * @see java.awt.RenderingHints#KEY_COLOR_RENDERING | ||
| 69 | * @see java.awt.RenderingHints#KEY_DITHERING | ||
| 70 | */ | ||
| 71 | public class ColorConvertOp implements BufferedImageOp, RasterOp { | ||
| 72 | ICC_Profile[] profileList; | ||
| 73 | ColorSpace[] CSList; | ||
| 74 | ColorTransform thisTransform, thisRasterTransform; | ||
| 75 | ICC_Profile thisSrcProfile, thisDestProfile; | ||
| 76 | RenderingHints hints; | ||
| 77 | boolean gotProfiles; | ||
| 78 | float[] srcMinVals, srcMaxVals, dstMinVals, dstMaxVals; | ||
| 79 | |||
| 80 | /* the class initializer */ | ||
| 81 | static { | ||
| 82 | if (ProfileDeferralMgr.deferring) { | ||
| 83 | ProfileDeferralMgr.activateProfiles(); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Constructs a new ColorConvertOp which will convert | ||
| 89 | * from a source color space to a destination color space. | ||
| 90 | * The RenderingHints argument may be null. | ||
| 91 | * This Op can be used only with BufferedImages, and will convert | ||
| 92 | * directly from the ColorSpace of the source image to that of the | ||
| 93 | * destination. The destination argument of the filter method | ||
| 94 | * cannot be specified as null. | ||
| 95 | * @param hints the <code>RenderingHints</code> object used to control | ||
| 96 | * the color conversion, or <code>null</code> | ||
| 97 | */ | ||
| 98 | public ColorConvertOp (RenderingHints hints) | ||
| 99 | { | ||
| 100 | profileList = new ICC_Profile [0]; /* 0 length list */ | ||
| 101 | this.hints = hints; | ||
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * Constructs a new ColorConvertOp from a ColorSpace object. | ||
| 106 | * The RenderingHints argument may be null. This | ||
| 107 | * Op can be used only with BufferedImages, and is primarily useful | ||
| 108 | * when the {@link #filter(BufferedImage, BufferedImage) filter} | ||
| 109 | * method is invoked with a destination argument of null. | ||
| 110 | * In that case, the ColorSpace defines the destination color space | ||
| 111 | * for the destination created by the filter method. Otherwise, the | ||
| 112 | * ColorSpace defines an intermediate space to which the source is | ||
| 113 | * converted before being converted to the destination space. | ||
| 114 | * @param cspace defines the destination <code>ColorSpace</code> or an | ||
| 115 | * intermediate <code>ColorSpace</code> | ||
| 116 | * @param hints the <code>RenderingHints</code> object used to control | ||
| 117 | * the color conversion, or <code>null</code> | ||
| 118 | * @throws NullPointerException if cspace is null | ||
| 119 | */ | ||
| 120 | public ColorConvertOp (ColorSpace cspace, RenderingHints hints) | ||
| 121 | { | ||
| 122 | if (cspace == null) { | ||
| 123 | throw new NullPointerException("ColorSpace cannot be null"); | ||
| 124 | } | ||
| 125 | if (cspace instanceof ICC_ColorSpace) { | ||
| 126 | profileList = new ICC_Profile [1]; /* 1 profile in the list */ | ||
| 127 | |||
| 128 | profileList [0] = ((ICC_ColorSpace) cspace).getProfile(); | ||
| 129 | } | ||
| 130 | else { | ||
| 131 | CSList = new ColorSpace[1]; /* non-ICC case: 1 ColorSpace in list */ | ||
| 132 | CSList[0] = cspace; | ||
| 133 | } | ||
| 134 | this.hints = hints; | ||
| 135 | } | ||
| 136 | |||
| 137 | |||
| 138 | /** | ||
| 139 | * Constructs a new ColorConvertOp from two ColorSpace objects. | ||
| 140 | * The RenderingHints argument may be null. | ||
| 141 | * This Op is primarily useful for calling the filter method on | ||
| 142 | * Rasters, in which case the two ColorSpaces define the operation | ||
| 143 | * to be performed on the Rasters. In that case, the number of bands | ||
| 144 | * in the source Raster must match the number of components in | ||
| 145 | * srcCspace, and the number of bands in the destination Raster | ||
| 146 | * must match the number of components in dstCspace. For BufferedImages, | ||
| 147 | * the two ColorSpaces define intermediate spaces through which the | ||
| 148 | * source is converted before being converted to the destination space. | ||
| 149 | * @param srcCspace the source <code>ColorSpace</code> | ||
| 150 | * @param dstCspace the destination <code>ColorSpace</code> | ||
| 151 | * @param hints the <code>RenderingHints</code> object used to control | ||
| 152 | * the color conversion, or <code>null</code> | ||
| 153 | * @throws NullPointerException if either srcCspace or dstCspace is null | ||
| 154 | */ | ||
| 155 | public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace, | ||
| 156 | RenderingHints hints) | ||
| 157 | { | ||
| 158 | if ((srcCspace == null) || (dstCspace == null)) { | ||
| 159 | throw new NullPointerException("ColorSpaces cannot be null"); | ||
| 160 | } | ||
| 161 | if ((srcCspace instanceof ICC_ColorSpace) && | ||
| 162 | (dstCspace instanceof ICC_ColorSpace)) { | ||
| 163 | profileList = new ICC_Profile [2]; /* 2 profiles in the list */ | ||
| 164 | |||
| 165 | profileList [0] = ((ICC_ColorSpace) srcCspace).getProfile(); | ||
| 166 | profileList [1] = ((ICC_ColorSpace) dstCspace).getProfile(); | ||
| 167 | |||
| 168 | getMinMaxValsFromColorSpaces(srcCspace, dstCspace); | ||
| 169 | } else { | ||
| 170 | /* non-ICC case: 2 ColorSpaces in list */ | ||
| 171 | CSList = new ColorSpace[2]; | ||
| 172 | CSList[0] = srcCspace; | ||
| 173 | CSList[1] = dstCspace; | ||
| 174 | } | ||
| 175 | this.hints = hints; | ||
| 176 | } | ||
| 177 | |||
| 178 | |||
| 179 | /** | ||
| 180 | * Constructs a new ColorConvertOp from an array of ICC_Profiles. | ||
| 181 | * The RenderingHints argument may be null. | ||
| 182 | * The sequence of profiles may include profiles that represent color | ||
| 183 | * spaces, profiles that represent effects, etc. If the whole sequence | ||
| 184 | * does not represent a well-defined color conversion, an exception is | ||
| 185 | * thrown. | ||
| 186 | * <p>For BufferedImages, if the ColorSpace | ||
| 187 | * of the source BufferedImage does not match the requirements of the | ||
| 188 | * first profile in the array, | ||
| 189 | * the first conversion is to an appropriate ColorSpace. | ||
| 190 | * If the requirements of the last profile in the array are not met | ||
| 191 | * by the ColorSpace of the destination BufferedImage, | ||
| 192 | * the last conversion is to the destination's ColorSpace. | ||
| 193 | * <p>For Rasters, the number of bands in the source Raster must match | ||
| 194 | * the requirements of the first profile in the array, and the | ||
| 195 | * number of bands in the destination Raster must match the requirements | ||
| 196 | * of the last profile in the array. The array must have at least two | ||
| 197 | * elements or calling the filter method for Rasters will throw an | ||
| 198 | * IllegalArgumentException. | ||
| 199 | * @param profiles the array of <code>ICC_Profile</code> objects | ||
| 200 | * @param hints the <code>RenderingHints</code> object used to control | ||
| 201 | * the color conversion, or <code>null</code> | ||
| 202 | * @exception IllegalArgumentException when the profile sequence does not | ||
| 203 | * specify a well-defined color conversion | ||
| 204 | * @exception NullPointerException if profiles is null | ||
| 205 | */ | ||
| 206 | public ColorConvertOp (ICC_Profile[] profiles, RenderingHints hints) | ||
| 207 | { | ||
| 208 | if (profiles == null) { | ||
| 209 | throw new NullPointerException("Profiles cannot be null"); | ||
| 210 | } | ||
| 211 | gotProfiles = true; | ||
| 212 | profileList = new ICC_Profile[profiles.length]; | ||
| 213 | for (int i1 = 0; i1 < profiles.length; i1++) { | ||
| 214 | profileList[i1] = profiles[i1]; | ||
| 215 | } | ||
| 216 | this.hints = hints; | ||
| 217 | } | ||
| 218 | |||
| 219 | |||
| 220 | /** | ||
| 221 | * Returns the array of ICC_Profiles used to construct this ColorConvertOp. | ||
| 222 | * Returns null if the ColorConvertOp was not constructed from such an | ||
| 223 | * array. | ||
| 224 | * @return the array of <code>ICC_Profile</code> objects of this | ||
| 225 | * <code>ColorConvertOp</code>, or <code>null</code> if this | ||
| 226 | * <code>ColorConvertOp</code> was not constructed with an | ||
| 227 | * array of <code>ICC_Profile</code> objects. | ||
| 228 | */ | ||
| 229 | public final ICC_Profile[] getICC_Profiles() { | ||
| 230 | if (gotProfiles) { | ||
| 231 | ICC_Profile[] profiles = new ICC_Profile[profileList.length]; | ||
| 232 | for (int i1 = 0; i1 < profileList.length; i1++) { | ||
| 233 | profiles[i1] = profileList[i1]; | ||
| 234 | } | ||
| 235 | return profiles; | ||
| 236 | } | ||
| 237 | return null; | ||
| 238 | } | ||
| 239 | |||
| 240 | /** | ||
| 241 | * ColorConverts the source BufferedImage. | ||
| 242 | * If the destination image is null, | ||
| 243 | * a BufferedImage will be created with an appropriate ColorModel. | ||
| 244 | * @param src the source <code>BufferedImage</code> to be converted | ||
| 245 | * @param dest the destination <code>BufferedImage</code>, | ||
| 246 | * or <code>null</code> | ||
| 247 | * @return <code>dest</code> color converted from <code>src</code> | ||
| 248 | * or a new, converted <code>BufferedImage</code> | ||
| 249 | * if <code>dest</code> is <code>null</code> | ||
| 250 | * @exception IllegalArgumentException if dest is null and this op was | ||
| 251 | * constructed using the constructor which takes only a | ||
| 252 | * RenderingHints argument, since the operation is ill defined. | ||
| 253 | */ | ||
| 254 | public final BufferedImage filter(BufferedImage src, BufferedImage dest) { | ||
| 255 | ColorSpace srcColorSpace, destColorSpace; | ||
| 256 | BufferedImage savdest = null; | ||
| 257 | |||
| 258 | if (src.getColorModel() instanceof IndexColorModel) { | ||
| 259 | IndexColorModel icm = (IndexColorModel) src.getColorModel(); | ||
| 260 | src = icm.convertToIntDiscrete(src.getRaster(), true); | ||
| 261 | } | ||
| 262 | srcColorSpace = src.getColorModel().getColorSpace(); | ||
| 263 | if (dest != null) { | ||
| 264 | if (dest.getColorModel() instanceof IndexColorModel) { | ||
| 265 | savdest = dest; | ||
| 266 | dest = null; | ||
| 267 | destColorSpace = null; | ||
| 268 | } else { | ||
| 269 | destColorSpace = dest.getColorModel().getColorSpace(); | ||
| 270 | } | ||
| 271 | } else { | ||
| 272 | destColorSpace = null; | ||
| 273 | } | ||
| 274 | |||
| 275 | if ((CSList != null) || | ||
| 276 | (!(srcColorSpace instanceof ICC_ColorSpace)) || | ||
| 277 | ((dest != null) && | ||
| 278 | (!(destColorSpace instanceof ICC_ColorSpace)))) { | ||
| 279 | /* non-ICC case */ | ||
| 280 | dest = nonICCBIFilter(src, srcColorSpace, dest, destColorSpace); | ||
| 281 | } else { | ||
| 282 | dest = ICCBIFilter(src, srcColorSpace, dest, destColorSpace); | ||
| 283 | } | ||
| 284 | |||
| 285 | if (savdest != null) { | ||
| 286 | Graphics2D big = savdest.createGraphics(); | ||
| 287 | try { | ||
| 288 | big.drawImage(dest, 0, 0, null); | ||
| 289 | } finally { | ||
| 290 | big.dispose(); | ||
| 291 | } | ||
| 292 | return savdest; | ||
| 293 | } else { | ||
| 294 | return dest; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | private final BufferedImage ICCBIFilter(BufferedImage src, | ||
| 299 | ColorSpace srcColorSpace, | ||
| 300 | BufferedImage dest, | ||
| 301 | ColorSpace destColorSpace) { | ||
| 302 | int nProfiles = profileList.length; | ||
| 303 | ICC_Profile srcProfile = null, destProfile = null; | ||
| 304 | |||
| 305 | srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile(); | ||
| 306 | |||
| 307 | if (dest == null) { /* last profile in the list defines | ||
| 308 | the output color space */ | ||
| 309 | if (nProfiles == 0) { | ||
| 310 | throw new IllegalArgumentException( | ||
| 311 | "Destination ColorSpace is undefined"); | ||
| 312 | } | ||
| 313 | destProfile = profileList [nProfiles - 1]; | ||
| 314 | dest = createCompatibleDestImage(src, null); | ||
| 315 | } | ||
| 316 | else { | ||
| 317 | if (src.getHeight() != dest.getHeight() || | ||
| 318 | src.getWidth() != dest.getWidth()) { | ||
| 319 | throw new IllegalArgumentException( | ||
| 320 | "Width or height of BufferedImages do not match"); | ||
| 321 | } | ||
| 322 | destProfile = ((ICC_ColorSpace) destColorSpace).getProfile(); | ||
| 323 | } | ||
| 324 | |||
| 325 | /* Checking if all profiles in the transform sequence are the same. | ||
| 326 | * If so, performing just copying the data. | ||
| 327 | */ | ||
| 328 | if (srcProfile == destProfile) { | ||
| 329 | boolean noTrans = true; | ||
| 330 | for (int i = 0; i < nProfiles; i++) { | ||
| 331 | if (srcProfile != profileList[i]) { | ||
| 332 | noTrans = false; | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | if (noTrans) { | ||
| 337 | Graphics2D g = dest.createGraphics(); | ||
| 338 | try { | ||
| 339 | g.drawImage(src, 0, 0, null); | ||
| 340 | } finally { | ||
| 341 | g.dispose(); | ||
| 342 | } | ||
| 343 | |||
| 344 | return dest; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | /* make a new transform if needed */ | ||
| 349 | if ((thisTransform == null) || (thisSrcProfile != srcProfile) || | ||
| 350 | (thisDestProfile != destProfile) ) { | ||
| 351 | updateBITransform(srcProfile, destProfile); | ||
| 352 | } | ||
| 353 | |||
| 354 | /* color convert the image */ | ||
| 355 | thisTransform.colorConvert(src, dest); | ||
| 356 | |||
| 357 | return dest; | ||
| 358 | } | ||
| 359 | |||
| 360 | private void updateBITransform(ICC_Profile srcProfile, | ||
| 361 | ICC_Profile destProfile) { | ||
| 362 | ICC_Profile[] theProfiles; | ||
| 363 | int i1, nProfiles, nTransforms, whichTrans, renderState; | ||
| 364 | ColorTransform[] theTransforms; | ||
| 365 | boolean useSrc = false, useDest = false; | ||
| 366 | |||
| 367 | nProfiles = profileList.length; | ||
| 368 | nTransforms = nProfiles; | ||
| 369 | if ((nProfiles == 0) || (srcProfile != profileList[0])) { | ||
| 370 | nTransforms += 1; | ||
| 371 | useSrc = true; | ||
| 372 | } | ||
| 373 | if ((nProfiles == 0) || (destProfile != profileList[nProfiles - 1]) || | ||
| 374 | (nTransforms < 2)) { | ||
| 375 | nTransforms += 1; | ||
| 376 | useDest = true; | ||
| 377 | } | ||
| 378 | |||
| 379 | /* make the profile list */ | ||
| 380 | theProfiles = new ICC_Profile[nTransforms]; /* the list of profiles | ||
| 381 | for this Op */ | ||
| 382 | |||
| 383 | int idx = 0; | ||
| 384 | if (useSrc) { | ||
| 385 | /* insert source as first profile */ | ||
| 386 | theProfiles[idx++] = srcProfile; | ||
| 387 | } | ||
| 388 | |||
| 389 | for (i1 = 0; i1 < nProfiles; i1++) { | ||
| 390 | /* insert profiles defined in this Op */ | ||
| 391 | theProfiles[idx++] = profileList [i1]; | ||
| 392 | } | ||
| 393 | |||
| 394 | if (useDest) { | ||
| 395 | /* insert dest as last profile */ | ||
| 396 | theProfiles[idx] = destProfile; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* make the transform list */ | ||
| 400 | theTransforms = new ColorTransform [nTransforms]; | ||
| 401 | |||
| 402 | /* initialize transform get loop */ | ||
| 403 | if (theProfiles[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) { | ||
| 404 | /* if first profile is a printer | ||
| 405 | render as colorimetric */ | ||
| 406 | renderState = ICC_Profile.icRelativeColorimetric; | ||
| 407 | } | ||
| 408 | else { | ||
| 409 | renderState = ICC_Profile.icPerceptual; /* render any other | ||
| 410 | class perceptually */ | ||
| 411 | } | ||
| 412 | |||
| 413 | whichTrans = ColorTransform.In; | ||
| 414 | |||
| 415 | PCMM mdl = CMSManager.getModule(); | ||
| 416 | |||
| 417 | /* get the transforms from each profile */ | ||
| 418 | for (i1 = 0; i1 < nTransforms; i1++) { | ||
| 419 | if (i1 == nTransforms -1) { /* last profile? */ | ||
| 420 | whichTrans = ColorTransform.Out; /* get output transform */ | ||
| 421 | } | ||
| 422 | else { /* check for abstract profile */ | ||
| 423 | if ((whichTrans == ColorTransform.Simulation) && | ||
| 424 | (theProfiles[i1].getProfileClass () == | ||
| 425 | ICC_Profile.CLASS_ABSTRACT)) { | ||
| 426 | renderState = ICC_Profile.icPerceptual; | ||
| 427 | whichTrans = ColorTransform.In; | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 431 | theTransforms[i1] = mdl.createTransform ( | ||
| 432 | theProfiles[i1], renderState, whichTrans); | ||
| 433 | |||
| 434 | /* get this profile's rendering intent to select transform | ||
| 435 | from next profile */ | ||
| 436 | renderState = getRenderingIntent(theProfiles[i1]); | ||
| 437 | |||
| 438 | /* "middle" profiles use simulation transform */ | ||
| 439 | whichTrans = ColorTransform.Simulation; | ||
| 440 | } | ||
| 441 | |||
| 442 | /* make the net transform */ | ||
| 443 | thisTransform = mdl.createTransform(theTransforms); | ||
| 444 | |||
| 445 | /* update corresponding source and dest profiles */ | ||
| 446 | thisSrcProfile = srcProfile; | ||
| 447 | thisDestProfile = destProfile; | ||
| 448 | } | ||
| 449 | |||
| 450 | /** | ||
| 451 | * ColorConverts the image data in the source Raster. | ||
| 452 | * If the destination Raster is null, a new Raster will be created. | ||
| 453 | * The number of bands in the source and destination Rasters must | ||
| 454 | * meet the requirements explained above. The constructor used to | ||
| 455 | * create this ColorConvertOp must have provided enough information | ||
| 456 | * to define both source and destination color spaces. See above. | ||
| 457 | * Otherwise, an exception is thrown. | ||
| 458 | * @param src the source <code>Raster</code> to be converted | ||
| 459 | * @param dest the destination <code>WritableRaster</code>, | ||
| 460 | * or <code>null</code> | ||
| 461 | * @return <code>dest</code> color converted from <code>src</code> | ||
| 462 | * or a new, converted <code>WritableRaster</code> | ||
| 463 | * if <code>dest</code> is <code>null</code> | ||
| 464 | * @exception IllegalArgumentException if the number of source or | ||
| 465 | * destination bands is incorrect, the source or destination | ||
| 466 | * color spaces are undefined, or this op was constructed | ||
| 467 | * with one of the constructors that applies only to | ||
| 468 | * operations on BufferedImages. | ||
| 469 | */ | ||
| 470 | public final WritableRaster filter (Raster src, WritableRaster dest) { | ||
| 471 | |||
| 472 | if (CSList != null) { | ||
| 473 | /* non-ICC case */ | ||
| 474 | return nonICCRasterFilter(src, dest); | ||
| 475 | } | ||
| 476 | int nProfiles = profileList.length; | ||
| 477 | if (nProfiles < 2) { | ||
| 478 | throw new IllegalArgumentException( | ||
| 479 | "Source or Destination ColorSpace is undefined"); | ||
| 480 | } | ||
| 481 | if (src.getNumBands() != profileList[0].getNumComponents()) { | ||
| 482 | throw new IllegalArgumentException( | ||
| 483 | "Numbers of source Raster bands and source color space " + | ||
| 484 | "components do not match"); | ||
| 485 | } | ||
| 486 | if (dest == null) { | ||
| 487 | dest = createCompatibleDestRaster(src); | ||
| 488 | } | ||
| 489 | else { | ||
| 490 | if (src.getHeight() != dest.getHeight() || | ||
| 491 | src.getWidth() != dest.getWidth()) { | ||
| 492 | throw new IllegalArgumentException( | ||
| 493 | "Width or height of Rasters do not match"); | ||
| 494 | } | ||
| 495 | if (dest.getNumBands() != | ||
| 496 | profileList[nProfiles-1].getNumComponents()) { | ||
| 497 | throw new IllegalArgumentException( | ||
| 498 | "Numbers of destination Raster bands and destination " + | ||
| 499 | "color space components do not match"); | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | /* make a new transform if needed */ | ||
| 504 | if (thisRasterTransform == null) { | ||
| 505 | int i1, whichTrans, renderState; | ||
| 506 | ColorTransform[] theTransforms; | ||
| 507 | |||
| 508 | /* make the transform list */ | ||
| 509 | theTransforms = new ColorTransform [nProfiles]; | ||
| 510 | |||
| 511 | /* initialize transform get loop */ | ||
| 512 | if (profileList[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) { | ||
| 513 | /* if first profile is a printer | ||
| 514 | render as colorimetric */ | ||
| 515 | renderState = ICC_Profile.icRelativeColorimetric; | ||
| 516 | } | ||
| 517 | else { | ||
| 518 | renderState = ICC_Profile.icPerceptual; /* render any other | ||
| 519 | class perceptually */ | ||
| 520 | } | ||
| 521 | |||
| 522 | whichTrans = ColorTransform.In; | ||
| 523 | |||
| 524 | PCMM mdl = CMSManager.getModule(); | ||
| 525 | |||
| 526 | /* get the transforms from each profile */ | ||
| 527 | for (i1 = 0; i1 < nProfiles; i1++) { | ||
| 528 | if (i1 == nProfiles -1) { /* last profile? */ | ||
| 529 | whichTrans = ColorTransform.Out; /* get output transform */ | ||
| 530 | } | ||
| 531 | else { /* check for abstract profile */ | ||
| 532 | if ((whichTrans == ColorTransform.Simulation) && | ||
| 533 | (profileList[i1].getProfileClass () == | ||
| 534 | ICC_Profile.CLASS_ABSTRACT)) { | ||
| 535 | renderState = ICC_Profile.icPerceptual; | ||
| 536 | whichTrans = ColorTransform.In; | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | theTransforms[i1] = mdl.createTransform ( | ||
| 541 | profileList[i1], renderState, whichTrans); | ||
| 542 | |||
| 543 | /* get this profile's rendering intent to select transform | ||
| 544 | from next profile */ | ||
| 545 | renderState = getRenderingIntent(profileList[i1]); | ||
| 546 | |||
| 547 | /* "middle" profiles use simulation transform */ | ||
| 548 | whichTrans = ColorTransform.Simulation; | ||
| 549 | } | ||
| 550 | |||
| 551 | /* make the net transform */ | ||
| 552 | thisRasterTransform = mdl.createTransform(theTransforms); | ||
| 553 | } | ||
| 554 | |||
| 555 | int srcTransferType = src.getTransferType(); | ||
| 556 | int dstTransferType = dest.getTransferType(); | ||
| 557 | if ((srcTransferType == DataBuffer.TYPE_FLOAT) || | ||
| 558 | (srcTransferType == DataBuffer.TYPE_DOUBLE) || | ||
| 559 | (dstTransferType == DataBuffer.TYPE_FLOAT) || | ||
| 560 | (dstTransferType == DataBuffer.TYPE_DOUBLE)) { | ||
| 561 | if (srcMinVals == null) { | ||
| 562 | getMinMaxValsFromProfiles(profileList[0], | ||
| 563 | profileList[nProfiles-1]); | ||
| 564 | } | ||
| 565 | /* color convert the raster */ | ||
| 566 | thisRasterTransform.colorConvert(src, dest, | ||
| 567 | srcMinVals, srcMaxVals, | ||
| 568 | dstMinVals, dstMaxVals); | ||
| 569 | } else { | ||
| 570 | /* color convert the raster */ | ||
| 571 | thisRasterTransform.colorConvert(src, dest); | ||
| 572 | } | ||
| 573 | |||
| 574 | |||
| 575 | return dest; | ||
| 576 | } | ||
| 577 | |||
| 578 | /** | ||
| 579 | * Returns the bounding box of the destination, given this source. | ||
| 580 | * Note that this will be the same as the the bounding box of the | ||
| 581 | * source. | ||
| 582 | * @param src the source <code>BufferedImage</code> | ||
| 583 | * @return a <code>Rectangle2D</code> that is the bounding box | ||
| 584 | * of the destination, given the specified <code>src</code> | ||
| 585 | */ | ||
| 586 | public final Rectangle2D getBounds2D (BufferedImage src) { | ||
| 587 | return getBounds2D(src.getRaster()); | ||
| 588 | } | ||
| 589 | |||
| 590 | /** | ||
| 591 | * Returns the bounding box of the destination, given this source. | ||
| 592 | * Note that this will be the same as the the bounding box of the | ||
| 593 | * source. | ||
| 594 | * @param src the source <code>Raster</code> | ||
| 595 | * @return a <code>Rectangle2D</code> that is the bounding box | ||
| 596 | * of the destination, given the specified <code>src</code> | ||
| 597 | */ | ||
| 598 | public final Rectangle2D getBounds2D (Raster src) { | ||
| 599 | /* return new Rectangle (src.getXOffset(), | ||
| 600 | src.getYOffset(), | ||
| 601 | src.getWidth(), src.getHeight()); */ | ||
| 602 | return src.getBounds(); | ||
| 603 | } | ||
| 604 | |||
| 605 | /** | ||
| 606 | * Creates a zeroed destination image with the correct size and number of | ||
| 607 | * bands, given this source. | ||
| 608 | * @param src Source image for the filter operation. | ||
| 609 | * @param destCM ColorModel of the destination. If null, an | ||
| 610 | * appropriate ColorModel will be used. | ||
| 611 | * @return a <code>BufferedImage</code> with the correct size and | ||
| 612 | * number of bands from the specified <code>src</code>. | ||
| 613 | * @throws IllegalArgumentException if <code>destCM</code> is | ||
| 614 | * <code>null</code> and this <code>ColorConvertOp</code> was | ||
| 615 | * created without any <code>ICC_Profile</code> or | ||
| 616 | * <code>ColorSpace</code> defined for the destination | ||
| 617 | */ | ||
| 618 | public BufferedImage createCompatibleDestImage (BufferedImage src, | ||
| 619 | ColorModel destCM) { | ||
| 620 | ColorSpace cs = null;; | ||
| 621 | if (destCM == null) { | ||
| 622 | if (CSList == null) { | ||
| 623 | /* ICC case */ | ||
| 624 | int nProfiles = profileList.length; | ||
| 625 | if (nProfiles == 0) { | ||
| 626 | throw new IllegalArgumentException( | ||
| 627 | "Destination ColorSpace is undefined"); | ||
| 628 | } | ||
| 629 | ICC_Profile destProfile = profileList[nProfiles - 1]; | ||
| 630 | cs = new ICC_ColorSpace(destProfile); | ||
| 631 | } else { | ||
| 632 | /* non-ICC case */ | ||
| 633 | int nSpaces = CSList.length; | ||
| 634 | cs = CSList[nSpaces - 1]; | ||
| 635 | } | ||
| 636 | } | ||
| 637 | return createCompatibleDestImage(src, destCM, cs); | ||
| 638 | } | ||
| 639 | |||
| 640 | private BufferedImage createCompatibleDestImage(BufferedImage src, | ||
| 641 | ColorModel destCM, | ||
| 642 | ColorSpace destCS) { | ||
| 643 | BufferedImage image; | ||
| 644 | if (destCM == null) { | ||
| 645 | ColorModel srcCM = src.getColorModel(); | ||
| 646 | int nbands = destCS.getNumComponents(); | ||
| 647 | boolean hasAlpha = srcCM.hasAlpha(); | ||
| 648 | if (hasAlpha) { | ||
| 649 | nbands += 1; | ||
| 650 | } | ||
| 651 | int[] nbits = new int[nbands]; | ||
| 652 | for (int i = 0; i < nbands; i++) { | ||
| 653 | nbits[i] = 8; | ||
| 654 | } | ||
| 655 | destCM = new ComponentColorModel(destCS, nbits, hasAlpha, | ||
| 656 | srcCM.isAlphaPremultiplied(), | ||
| 657 | srcCM.getTransparency(), | ||
| 658 | DataBuffer.TYPE_BYTE); | ||
| 659 | } | ||
| 660 | int w = src.getWidth(); | ||
| 661 | int h = src.getHeight(); | ||
| 662 | image = new BufferedImage(destCM, | ||
| 663 | destCM.createCompatibleWritableRaster(w, h), | ||
| 664 | destCM.isAlphaPremultiplied(), null); | ||
| 665 | return image; | ||
| 666 | } | ||
| 667 | |||
| 668 | |||
| 669 | /** | ||
| 670 | * Creates a zeroed destination Raster with the correct size and number of | ||
| 671 | * bands, given this source. | ||
| 672 | * @param src the specified <code>Raster</code> | ||
| 673 | * @return a <code>WritableRaster</code> with the correct size and number | ||
| 674 | * of bands from the specified <code>src</code> | ||
| 675 | * @throws IllegalArgumentException if this <code>ColorConvertOp</code> | ||
| 676 | * was created without sufficient information to define the | ||
| 677 | * <code>dst</code> and <code>src</code> color spaces | ||
| 678 | */ | ||
| 679 | public WritableRaster createCompatibleDestRaster (Raster src) { | ||
| 680 | int ncomponents; | ||
| 681 | |||
| 682 | if (CSList != null) { | ||
| 683 | /* non-ICC case */ | ||
| 684 | if (CSList.length != 2) { | ||
| 685 | throw new IllegalArgumentException( | ||
| 686 | "Destination ColorSpace is undefined"); | ||
| 687 | } | ||
| 688 | ncomponents = CSList[1].getNumComponents(); | ||
| 689 | } else { | ||
| 690 | /* ICC case */ | ||
| 691 | int nProfiles = profileList.length; | ||
| 692 | if (nProfiles < 2) { | ||
| 693 | throw new IllegalArgumentException( | ||
| 694 | "Destination ColorSpace is undefined"); | ||
| 695 | } | ||
| 696 | ncomponents = profileList[nProfiles-1].getNumComponents(); | ||
| 697 | } | ||
| 698 | |||
| 699 | WritableRaster dest = | ||
| 700 | Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, | ||
| 701 | src.getWidth(), | ||
| 702 | src.getHeight(), | ||
| 703 | ncomponents, | ||
| 704 | new Point(src.getMinX(), src.getMinY())); | ||
| 705 | return dest; | ||
| 706 | } | ||
| 707 | |||
| 708 | /** | ||
| 709 | * Returns the location of the destination point given a | ||
| 710 | * point in the source. If <code>dstPt</code> is non-null, | ||
| 711 | * it will be used to hold the return value. Note that | ||
| 712 | * for this class, the destination point will be the same | ||
| 713 | * as the source point. | ||
| 714 | * @param srcPt the specified source <code>Point2D</code> | ||
| 715 | * @param dstPt the destination <code>Point2D</code> | ||
| 716 | * @return <code>dstPt</code> after setting its location to be | ||
| 717 | * the same as <code>srcPt</code> | ||
| 718 | */ | ||
| 719 | public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) { | ||
| 720 | if (dstPt == null) { | ||
| 721 | dstPt = new Point2D.Float(); | ||
| 722 | } | ||
| 723 | dstPt.setLocation(srcPt.getX(), srcPt.getY()); | ||
| 724 | |||
| 725 | return dstPt; | ||
| 726 | } | ||
| 727 | |||
| 728 | |||
| 729 | /** | ||
| 730 | * Returns the RenderingIntent from the specified ICC Profile. | ||
| 731 | */ | ||
| 732 | private int getRenderingIntent (ICC_Profile profile) { | ||
| 733 | byte[] header = profile.getData(ICC_Profile.icSigHead); | ||
| 734 | int index = ICC_Profile.icHdrRenderingIntent; | ||
| 735 | return (((header[index] & 0xff) << 24) | | ||
| 736 | ((header[index+1] & 0xff) << 16) | | ||
| 737 | ((header[index+2] & 0xff) << 8) | | ||
| 738 | (header[index+3] & 0xff)); | ||
| 739 | } | ||
| 740 | |||
| 741 | /** | ||
| 742 | * Returns the rendering hints used by this op. | ||
| 743 | * @return the <code>RenderingHints</code> object of this | ||
| 744 | * <code>ColorConvertOp</code> | ||
| 745 | */ | ||
| 746 | public final RenderingHints getRenderingHints() { | ||
| 747 | return hints; | ||
| 748 | } | ||
| 749 | |||
| 750 | private final BufferedImage nonICCBIFilter(BufferedImage src, | ||
| 751 | ColorSpace srcColorSpace, | ||
| 752 | BufferedImage dst, | ||
| 753 | ColorSpace dstColorSpace) { | ||
| 754 | |||
| 755 | int w = src.getWidth(); | ||
| 756 | int h = src.getHeight(); | ||
| 757 | ICC_ColorSpace ciespace = | ||
| 758 | (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); | ||
| 759 | if (dst == null) { | ||
| 760 | dst = createCompatibleDestImage(src, null); | ||
| 761 | dstColorSpace = dst.getColorModel().getColorSpace(); | ||
| 762 | } else { | ||
| 763 | if ((h != dst.getHeight()) || (w != dst.getWidth())) { | ||
| 764 | throw new IllegalArgumentException( | ||
| 765 | "Width or height of BufferedImages do not match"); | ||
| 766 | } | ||
| 767 | } | ||
| 768 | Raster srcRas = src.getRaster(); | ||
| 769 | WritableRaster dstRas = dst.getRaster(); | ||
| 770 | ColorModel srcCM = src.getColorModel(); | ||
| 771 | ColorModel dstCM = dst.getColorModel(); | ||
| 772 | int srcNumComp = srcCM.getNumColorComponents(); | ||
| 773 | int dstNumComp = dstCM.getNumColorComponents(); | ||
| 774 | boolean dstHasAlpha = dstCM.hasAlpha(); | ||
| 775 | boolean needSrcAlpha = srcCM.hasAlpha() && dstHasAlpha; | ||
| 776 | ColorSpace[] list; | ||
| 777 | if ((CSList == null) && (profileList.length != 0)) { | ||
| 778 | /* possible non-ICC src, some profiles, possible non-ICC dst */ | ||
| 779 | boolean nonICCSrc, nonICCDst; | ||
| 780 | ICC_Profile srcProfile, dstProfile; | ||
| 781 | if (!(srcColorSpace instanceof ICC_ColorSpace)) { | ||
| 782 | nonICCSrc = true; | ||
| 783 | srcProfile = ciespace.getProfile(); | ||
| 784 | } else { | ||
| 785 | nonICCSrc = false; | ||
| 786 | srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile(); | ||
| 787 | } | ||
| 788 | if (!(dstColorSpace instanceof ICC_ColorSpace)) { | ||
| 789 | nonICCDst = true; | ||
| 790 | dstProfile = ciespace.getProfile(); | ||
| 791 | } else { | ||
| 792 | nonICCDst = false; | ||
| 793 | dstProfile = ((ICC_ColorSpace) dstColorSpace).getProfile(); | ||
| 794 | } | ||
| 795 | /* make a new transform if needed */ | ||
| 796 | if ((thisTransform == null) || (thisSrcProfile != srcProfile) || | ||
| 797 | (thisDestProfile != dstProfile) ) { | ||
| 798 | updateBITransform(srcProfile, dstProfile); | ||
| 799 | } | ||
| 800 | // process per scanline | ||
| 801 | float maxNum = 65535.0f; // use 16-bit precision in CMM | ||
| 802 | ColorSpace cs; | ||
| 803 | int iccSrcNumComp; | ||
| 804 | if (nonICCSrc) { | ||
| 805 | cs = ciespace; | ||
| 806 | iccSrcNumComp = 3; | ||
| 807 | } else { | ||
| 808 | cs = srcColorSpace; | ||
| 809 | iccSrcNumComp = srcNumComp; | ||
| 810 | } | ||
| 811 | float[] srcMinVal = new float[iccSrcNumComp]; | ||
| 812 | float[] srcInvDiffMinMax = new float[iccSrcNumComp]; | ||
| 813 | for (int i = 0; i < srcNumComp; i++) { | ||
| 814 | srcMinVal[i] = cs.getMinValue(i); | ||
| 815 | srcInvDiffMinMax[i] = maxNum / (cs.getMaxValue(i) - srcMinVal[i]); | ||
| 816 | } | ||
| 817 | int iccDstNumComp; | ||
| 818 | if (nonICCDst) { | ||
| 819 | cs = ciespace; | ||
| 820 | iccDstNumComp = 3; | ||
| 821 | } else { | ||
| 822 | cs = dstColorSpace; | ||
| 823 | iccDstNumComp = dstNumComp; | ||
| 824 | } | ||
| 825 | float[] dstMinVal = new float[iccDstNumComp]; | ||
| 826 | float[] dstDiffMinMax = new float[iccDstNumComp]; | ||
| 827 | for (int i = 0; i < dstNumComp; i++) { | ||
| 828 | dstMinVal[i] = cs.getMinValue(i); | ||
| 829 | dstDiffMinMax[i] = (cs.getMaxValue(i) - dstMinVal[i]) / maxNum; | ||
| 830 | } | ||
| 831 | float[] dstColor; | ||
| 832 | if (dstHasAlpha) { | ||
| 833 | int size = ((dstNumComp + 1) > 3) ? (dstNumComp + 1) : 3; | ||
| 834 | dstColor = new float[size]; | ||
| 835 | } else { | ||
| 836 | int size = (dstNumComp > 3) ? dstNumComp : 3; | ||
| 837 | dstColor = new float[size]; | ||
| 838 | } | ||
| 839 | short[] srcLine = new short[w * iccSrcNumComp]; | ||
| 840 | short[] dstLine = new short[w * iccDstNumComp]; | ||
| 841 | Object pixel; | ||
| 842 | float[] color; | ||
| 843 | float[] alpha = null; | ||
| 844 | if (needSrcAlpha) { | ||
| 845 | alpha = new float[w]; | ||
| 846 | } | ||
| 847 | int idx; | ||
| 848 | // process each scanline | ||
| 849 | for (int y = 0; y < h; y++) { | ||
| 850 | // convert src scanline | ||
| 851 | pixel = null; | ||
| 852 | color = null; | ||
| 853 | idx = 0; | ||
| 854 | for (int x = 0; x < w; x++) { | ||
| 855 | pixel = srcRas.getDataElements(x, y, pixel); | ||
| 856 | color = srcCM.getNormalizedComponents(pixel, color, 0); | ||
| 857 | if (needSrcAlpha) { | ||
| 858 | alpha[x] = color[srcNumComp]; | ||
| 859 | } | ||
| 860 | if (nonICCSrc) { | ||
| 861 | color = srcColorSpace.toCIEXYZ(color); | ||
| 862 | } | ||
| 863 | for (int i = 0; i < iccSrcNumComp; i++) { | ||
| 864 | srcLine[idx++] = (short) | ||
| 865 | ((color[i] - srcMinVal[i]) * srcInvDiffMinMax[i] + | ||
| 866 | 0.5f); | ||
| 867 | } | ||
| 868 | } | ||
| 869 | // color convert srcLine to dstLine | ||
| 870 | thisTransform.colorConvert(srcLine, dstLine); | ||
| 871 | // convert dst scanline | ||
| 872 | pixel = null; | ||
| 873 | idx = 0; | ||
| 874 | for (int x = 0; x < w; x++) { | ||
| 875 | for (int i = 0; i < iccDstNumComp; i++) { | ||
| 876 | dstColor[i] = ((float) (dstLine[idx++] & 0xffff)) * | ||
| 877 | dstDiffMinMax[i] + dstMinVal[i]; | ||
| 878 | } | ||
| 879 | if (nonICCDst) { | ||
| 880 | color = srcColorSpace.fromCIEXYZ(dstColor); | ||
| 881 | for (int i = 0; i < dstNumComp; i++) { | ||
| 882 | dstColor[i] = color[i]; | ||
| 883 | } | ||
| 884 | } | ||
| 885 | if (needSrcAlpha) { | ||
| 886 | dstColor[dstNumComp] = alpha[x]; | ||
| 887 | } else if (dstHasAlpha) { | ||
| 888 | dstColor[dstNumComp] = 1.0f; | ||
| 889 | } | ||
| 890 | pixel = dstCM.getDataElements(dstColor, 0, pixel); | ||
| 891 | dstRas.setDataElements(x, y, pixel); | ||
| 892 | } | ||
| 893 | } | ||
| 894 | } else { | ||
| 895 | /* possible non-ICC src, possible CSList, possible non-ICC dst */ | ||
| 896 | // process per pixel | ||
| 897 | int numCS; | ||
| 898 | if (CSList == null) { | ||
| 899 | numCS = 0; | ||
| 900 | } else { | ||
| 901 | numCS = CSList.length; | ||
| 902 | } | ||
| 903 | float[] dstColor; | ||
| 904 | if (dstHasAlpha) { | ||
| 905 | dstColor = new float[dstNumComp + 1]; | ||
| 906 | } else { | ||
| 907 | dstColor = new float[dstNumComp]; | ||
| 908 | } | ||
| 909 | Object spixel = null; | ||
| 910 | Object dpixel = null; | ||
| 911 | float[] color = null; | ||
| 912 | float[] tmpColor; | ||
| 913 | // process each pixel | ||
| 914 | for (int y = 0; y < h; y++) { | ||
| 915 | for (int x = 0; x < w; x++) { | ||
| 916 | spixel = srcRas.getDataElements(x, y, spixel); | ||
| 917 | color = srcCM.getNormalizedComponents(spixel, color, 0); | ||
| 918 | tmpColor = srcColorSpace.toCIEXYZ(color); | ||
| 919 | for (int i = 0; i < numCS; i++) { | ||
| 920 | tmpColor = CSList[i].fromCIEXYZ(tmpColor); | ||
| 921 | tmpColor = CSList[i].toCIEXYZ(tmpColor); | ||
| 922 | } | ||
| 923 | tmpColor = dstColorSpace.fromCIEXYZ(tmpColor); | ||
| 924 | for (int i = 0; i < dstNumComp; i++) { | ||
| 925 | dstColor[i] = tmpColor[i]; | ||
| 926 | } | ||
| 927 | if (needSrcAlpha) { | ||
| 928 | dstColor[dstNumComp] = color[srcNumComp]; | ||
| 929 | } else if (dstHasAlpha) { | ||
| 930 | dstColor[dstNumComp] = 1.0f; | ||
| 931 | } | ||
| 932 | dpixel = dstCM.getDataElements(dstColor, 0, dpixel); | ||
| 933 | dstRas.setDataElements(x, y, dpixel); | ||
| 934 | |||
| 935 | } | ||
| 936 | } | ||
| 937 | } | ||
| 938 | |||
| 939 | return dst; | ||
| 940 | } | ||
| 941 | |||
| 942 | /* color convert a Raster - handles byte, ushort, int, short, float, | ||
| 943 | or double transferTypes */ | ||
| 944 | private final WritableRaster nonICCRasterFilter(Raster src, | ||
| 945 | WritableRaster dst) { | ||
| 946 | |||
| 947 | if (CSList.length != 2) { | ||
| 948 | throw new IllegalArgumentException( | ||
| 949 | "Destination ColorSpace is undefined"); | ||
| 950 | } | ||
| 951 | if (src.getNumBands() != CSList[0].getNumComponents()) { | ||
| 952 | throw new IllegalArgumentException( | ||
| 953 | "Numbers of source Raster bands and source color space " + | ||
| 954 | "components do not match"); | ||
| 955 | } | ||
| 956 | if (dst == null) { | ||
| 957 | dst = createCompatibleDestRaster(src); | ||
| 958 | } else { | ||
| 959 | if (src.getHeight() != dst.getHeight() || | ||
| 960 | src.getWidth() != dst.getWidth()) { | ||
| 961 | throw new IllegalArgumentException( | ||
| 962 | "Width or height of Rasters do not match"); | ||
| 963 | } | ||
| 964 | if (dst.getNumBands() != CSList[1].getNumComponents()) { | ||
| 965 | throw new IllegalArgumentException( | ||
| 966 | "Numbers of destination Raster bands and destination " + | ||
| 967 | "color space components do not match"); | ||
| 968 | } | ||
| 969 | } | ||
| 970 | |||
| 971 | if (srcMinVals == null) { | ||
| 972 | getMinMaxValsFromColorSpaces(CSList[0], CSList[1]); | ||
| 973 | } | ||
| 974 | |||
| 975 | SampleModel srcSM = src.getSampleModel(); | ||
| 976 | SampleModel dstSM = dst.getSampleModel(); | ||
| 977 | boolean srcIsFloat, dstIsFloat; | ||
| 978 | int srcTransferType = src.getTransferType(); | ||
| 979 | int dstTransferType = dst.getTransferType(); | ||
| 980 | if ((srcTransferType == DataBuffer.TYPE_FLOAT) || | ||
| 981 | (srcTransferType == DataBuffer.TYPE_DOUBLE)) { | ||
| 982 | srcIsFloat = true; | ||
| 983 | } else { | ||
| 984 | srcIsFloat = false; | ||
| 985 | } | ||
| 986 | if ((dstTransferType == DataBuffer.TYPE_FLOAT) || | ||
| 987 | (dstTransferType == DataBuffer.TYPE_DOUBLE)) { | ||
| 988 | dstIsFloat = true; | ||
| 989 | } else { | ||
| 990 | dstIsFloat = false; | ||
| 991 | } | ||
| 992 | int w = src.getWidth(); | ||
| 993 | int h = src.getHeight(); | ||
| 994 | int srcNumBands = src.getNumBands(); | ||
| 995 | int dstNumBands = dst.getNumBands(); | ||
| 996 | float[] srcScaleFactor = null; | ||
| 997 | float[] dstScaleFactor = null; | ||
| 998 | if (!srcIsFloat) { | ||
| 999 | srcScaleFactor = new float[srcNumBands]; | ||
| 1000 | for (int i = 0; i < srcNumBands; i++) { | ||
| 1001 | if (srcTransferType == DataBuffer.TYPE_SHORT) { | ||
| 1002 | srcScaleFactor[i] = (srcMaxVals[i] - srcMinVals[i]) / | ||
| 1003 | 32767.0f; | ||
| 1004 | } else { | ||
| 1005 | srcScaleFactor[i] = (srcMaxVals[i] - srcMinVals[i]) / | ||
| 1006 | ((float) ((1 << srcSM.getSampleSize(i)) - 1)); | ||
| 1007 | } | ||
| 1008 | } | ||
| 1009 | } | ||
| 1010 | if (!dstIsFloat) { | ||
| 1011 | dstScaleFactor = new float[dstNumBands]; | ||
| 1012 | for (int i = 0; i < dstNumBands; i++) { | ||
| 1013 | if (dstTransferType == DataBuffer.TYPE_SHORT) { | ||
| 1014 | dstScaleFactor[i] = 32767.0f / | ||
| 1015 | (dstMaxVals[i] - dstMinVals[i]); | ||
| 1016 | } else { | ||
| 1017 | dstScaleFactor[i] = | ||
| 1018 | ((float) ((1 << dstSM.getSampleSize(i)) - 1)) / | ||
| 1019 | (dstMaxVals[i] - dstMinVals[i]); | ||
| 1020 | } | ||
| 1021 | } | ||
| 1022 | } | ||
| 1023 | int ys = src.getMinY(); | ||
| 1024 | int yd = dst.getMinY(); | ||
| 1025 | int xs, xd; | ||
| 1026 | float sample; | ||
| 1027 | float[] color = new float[srcNumBands]; | ||
| 1028 | float[] tmpColor; | ||
| 1029 | ColorSpace srcColorSpace = CSList[0]; | ||
| 1030 | ColorSpace dstColorSpace = CSList[1]; | ||
| 1031 | // process each pixel | ||
| 1032 | for (int y = 0; y < h; y++, ys++, yd++) { | ||
| 1033 | // get src scanline | ||
| 1034 | xs = src.getMinX(); | ||
| 1035 | xd = dst.getMinX(); | ||
| 1036 | for (int x = 0; x < w; x++, xs++, xd++) { | ||
| 1037 | for (int i = 0; i < srcNumBands; i++) { | ||
| 1038 | sample = src.getSampleFloat(xs, ys, i); | ||
| 1039 | if (!srcIsFloat) { | ||
| 1040 | sample = sample * srcScaleFactor[i] + srcMinVals[i]; | ||
| 1041 | } | ||
| 1042 | color[i] = sample; | ||
| 1043 | } | ||
| 1044 | tmpColor = srcColorSpace.toCIEXYZ(color); | ||
| 1045 | tmpColor = dstColorSpace.fromCIEXYZ(tmpColor); | ||
| 1046 | for (int i = 0; i < dstNumBands; i++) { | ||
| 1047 | sample = tmpColor[i]; | ||
| 1048 | if (!dstIsFloat) { | ||
| 1049 | sample = (sample - dstMinVals[i]) * dstScaleFactor[i]; | ||
| 1050 | } | ||
| 1051 | dst.setSample(xd, yd, i, sample); | ||
| 1052 | } | ||
| 1053 | } | ||
| 1054 | } | ||
| 1055 | return dst; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | private void getMinMaxValsFromProfiles(ICC_Profile srcProfile, | ||
| 1059 | ICC_Profile dstProfile) { | ||
| 1060 | int type = srcProfile.getColorSpaceType(); | ||
| 1061 | int nc = srcProfile.getNumComponents(); | ||
| 1062 | srcMinVals = new float[nc]; | ||
| 1063 | srcMaxVals = new float[nc]; | ||
| 1064 | setMinMax(type, nc, srcMinVals, srcMaxVals); | ||
| 1065 | type = dstProfile.getColorSpaceType(); | ||
| 1066 | nc = dstProfile.getNumComponents(); | ||
| 1067 | dstMinVals = new float[nc]; | ||
| 1068 | dstMaxVals = new float[nc]; | ||
| 1069 | setMinMax(type, nc, dstMinVals, dstMaxVals); | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | private void setMinMax(int type, int nc, float[] minVals, float[] maxVals) { | ||
| 1073 | if (type == ColorSpace.TYPE_Lab) { | ||
| 1074 | minVals[0] = 0.0f; // L | ||
| 1075 | maxVals[0] = 100.0f; | ||
| 1076 | minVals[1] = -128.0f; // a | ||
| 1077 | maxVals[1] = 127.0f; | ||
| 1078 | minVals[2] = -128.0f; // b | ||
| 1079 | maxVals[2] = 127.0f; | ||
| 1080 | } else if (type == ColorSpace.TYPE_XYZ) { | ||
| 1081 | minVals[0] = minVals[1] = minVals[2] = 0.0f; // X, Y, Z | ||
| 1082 | maxVals[0] = maxVals[1] = maxVals[2] = 1.0f + (32767.0f/ 32768.0f); | ||
| 1083 | } else { | ||
| 1084 | for (int i = 0; i < nc; i++) { | ||
| 1085 | minVals[i] = 0.0f; | ||
| 1086 | maxVals[i] = 1.0f; | ||
| 1087 | } | ||
| 1088 | } | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | private void getMinMaxValsFromColorSpaces(ColorSpace srcCspace, | ||
| 1092 | ColorSpace dstCspace) { | ||
| 1093 | int nc = srcCspace.getNumComponents(); | ||
| 1094 | srcMinVals = new float[nc]; | ||
| 1095 | srcMaxVals = new float[nc]; | ||
| 1096 | for (int i = 0; i < nc; i++) { | ||
| 1097 | srcMinVals[i] = srcCspace.getMinValue(i); | ||
| 1098 | srcMaxVals[i] = srcCspace.getMaxValue(i); | ||
| 1099 | } | ||
| 1100 | nc = dstCspace.getNumComponents(); | ||
| 1101 | dstMinVals = new float[nc]; | ||
| 1102 | dstMaxVals = new float[nc]; | ||
| 1103 | for (int i = 0; i < nc; i++) { | ||
| 1104 | dstMinVals[i] = dstCspace.getMinValue(i); | ||
| 1105 | dstMaxVals[i] = dstCspace.getMaxValue(i); | ||
| 1106 | } | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | } | ||
Binary file not shown.
| @@ -0,0 +1,1959 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.Transparency; | ||
| 29 | import java.awt.color.ColorSpace; | ||
| 30 | import java.awt.color.ICC_ColorSpace; | ||
| 31 | import sun.java2d.cmm.CMSManager; | ||
| 32 | import sun.java2d.cmm.ColorTransform; | ||
| 33 | import sun.java2d.cmm.PCMM; | ||
| 34 | import java.awt.Toolkit; | ||
| 35 | import java.util.Collections; | ||
| 36 | import java.util.Map; | ||
| 37 | import java.util.WeakHashMap; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * The <code>ColorModel</code> abstract class encapsulates the | ||
| 41 | * methods for translating a pixel value to color components | ||
| 42 | * (for example, red, green, and blue) and an alpha component. | ||
| 43 | * In order to render an image to the screen, a printer, or another | ||
| 44 | * image, pixel values must be converted to color and alpha components. | ||
| 45 | * As arguments to or return values from methods of this class, | ||
| 46 | * pixels are represented as 32-bit ints or as arrays of primitive types. | ||
| 47 | * The number, order, and interpretation of color components for a | ||
| 48 | * <code>ColorModel</code> is specified by its <code>ColorSpace</code>. | ||
| 49 | * A <code>ColorModel</code> used with pixel data that does not include | ||
| 50 | * alpha information treats all pixels as opaque, which is an alpha | ||
| 51 | * value of 1.0. | ||
| 52 | * <p> | ||
| 53 | * This <code>ColorModel</code> class supports two representations of | ||
| 54 | * pixel values. A pixel value can be a single 32-bit int or an | ||
| 55 | * array of primitive types. The Java(tm) Platform 1.0 and 1.1 APIs | ||
| 56 | * represented pixels as single <code>byte</code> or single | ||
| 57 | * <code>int</code> values. For purposes of the <code>ColorModel</code> | ||
| 58 | * class, pixel value arguments were passed as ints. The Java(tm) 2 | ||
| 59 | * Platform API introduced additional classes for representing images. | ||
| 60 | * With {@link BufferedImage} or {@link RenderedImage} | ||
| 61 | * objects, based on {@link Raster} and {@link SampleModel} classes, pixel | ||
| 62 | * values might not be conveniently representable as a single int. | ||
| 63 | * Consequently, <code>ColorModel</code> now has methods that accept | ||
| 64 | * pixel values represented as arrays of primitive types. The primitive | ||
| 65 | * type used by a particular <code>ColorModel</code> object is called its | ||
| 66 | * transfer type. | ||
| 67 | * <p> | ||
| 68 | * <code>ColorModel</code> objects used with images for which pixel values | ||
| 69 | * are not conveniently representable as a single int throw an | ||
| 70 | * {@link IllegalArgumentException} when methods taking a single int pixel | ||
| 71 | * argument are called. Subclasses of <code>ColorModel</code> must | ||
| 72 | * specify the conditions under which this occurs. This does not | ||
| 73 | * occur with {@link DirectColorModel} or {@link IndexColorModel} objects. | ||
| 74 | * <p> | ||
| 75 | * Currently, the transfer types supported by the Java 2D(tm) API are | ||
| 76 | * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, | ||
| 77 | * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, and DataBuffer.TYPE_DOUBLE. | ||
| 78 | * Most rendering operations will perform much faster when using ColorModels | ||
| 79 | * and images based on the first three of these types. In addition, some | ||
| 80 | * image filtering operations are not supported for ColorModels and | ||
| 81 | * images based on the latter three types. | ||
| 82 | * The transfer type for a particular <code>ColorModel</code> object is | ||
| 83 | * specified when the object is created, either explicitly or by default. | ||
| 84 | * All subclasses of <code>ColorModel</code> must specify what the | ||
| 85 | * possible transfer types are and how the number of elements in the | ||
| 86 | * primitive arrays representing pixels is determined. | ||
| 87 | * <p> | ||
| 88 | * For <code>BufferedImages</code>, the transfer type of its | ||
| 89 | * <code>Raster</code> and of the <code>Raster</code> object's | ||
| 90 | * <code>SampleModel</code> (available from the | ||
| 91 | * <code>getTransferType</code> methods of these classes) must match that | ||
| 92 | * of the <code>ColorModel</code>. The number of elements in an array | ||
| 93 | * representing a pixel for the <code>Raster</code> and | ||
| 94 | * <code>SampleModel</code> (available from the | ||
| 95 | * <code>getNumDataElements</code> methods of these classes) must match | ||
| 96 | * that of the <code>ColorModel</code>. | ||
| 97 | * <p> | ||
| 98 | * The algorithm used to convert from pixel values to color and alpha | ||
| 99 | * components varies by subclass. For example, there is not necessarily | ||
| 100 | * a one-to-one correspondence between samples obtained from the | ||
| 101 | * <code>SampleModel</code> of a <code>BufferedImage</code> object's | ||
| 102 | * <code>Raster</code> and color/alpha components. Even when | ||
| 103 | * there is such a correspondence, the number of bits in a sample is not | ||
| 104 | * necessarily the same as the number of bits in the corresponding color/alpha | ||
| 105 | * component. Each subclass must specify how the translation from | ||
| 106 | * pixel values to color/alpha components is done. | ||
| 107 | * <p> | ||
| 108 | * Methods in the <code>ColorModel</code> class use two different | ||
| 109 | * representations of color and alpha components - a normalized form | ||
| 110 | * and an unnormalized form. In the normalized form, each component is a | ||
| 111 | * <code>float</code> value between some minimum and maximum values. For | ||
| 112 | * the alpha component, the minimum is 0.0 and the maximum is 1.0. For | ||
| 113 | * color components the minimum and maximum values for each component can | ||
| 114 | * be obtained from the <code>ColorSpace</code> object. These values | ||
| 115 | * will often be 0.0 and 1.0 (e.g. normalized component values for the | ||
| 116 | * default sRGB color space range from 0.0 to 1.0), but some color spaces | ||
| 117 | * have component values with different upper and lower limits. These | ||
| 118 | * limits can be obtained using the <code>getMinValue</code> and | ||
| 119 | * <code>getMaxValue</code> methods of the <code>ColorSpace</code> | ||
| 120 | * class. Normalized color component values are not premultiplied. | ||
| 121 | * All <code>ColorModels</code> must support the normalized form. | ||
| 122 | * <p> | ||
| 123 | * In the unnormalized | ||
| 124 | * form, each component is an unsigned integral value between 0 and | ||
| 125 | * 2<sup>n</sup> - 1, where n is the number of significant bits for a | ||
| 126 | * particular component. If pixel values for a particular | ||
| 127 | * <code>ColorModel</code> represent color samples premultiplied by | ||
| 128 | * the alpha sample, unnormalized color component values are | ||
| 129 | * also premultiplied. The unnormalized form is used only with instances | ||
| 130 | * of <code>ColorModel</code> whose <code>ColorSpace</code> has minimum | ||
| 131 | * component values of 0.0 for all components and maximum values of | ||
| 132 | * 1.0 for all components. | ||
| 133 | * The unnormalized form for color and alpha components can be a convenient | ||
| 134 | * representation for <code>ColorModels</code> whose normalized component | ||
| 135 | * values all lie | ||
| 136 | * between 0.0 and 1.0. In such cases the integral value 0 maps to 0.0 and | ||
| 137 | * the value 2<sup>n</sup> - 1 maps to 1.0. In other cases, such as | ||
| 138 | * when the normalized component values can be either negative or positive, | ||
| 139 | * the unnormalized form is not convenient. Such <code>ColorModel</code> | ||
| 140 | * objects throw an {@link IllegalArgumentException} when methods involving | ||
| 141 | * an unnormalized argument are called. Subclasses of <code>ColorModel</code> | ||
| 142 | * must specify the conditions under which this occurs. | ||
| 143 | * | ||
| 144 | * @see IndexColorModel | ||
| 145 | * @see ComponentColorModel | ||
| 146 | * @see PackedColorModel | ||
| 147 | * @see DirectColorModel | ||
| 148 | * @see java.awt.Image | ||
| 149 | * @see BufferedImage | ||
| 150 | * @see RenderedImage | ||
| 151 | * @see java.awt.color.ColorSpace | ||
| 152 | * @see SampleModel | ||
| 153 | * @see Raster | ||
| 154 | * @see DataBuffer | ||
| 155 | */ | ||
| 156 | public abstract class ColorModel implements Transparency{ | ||
| 157 | private long pData; // Placeholder for data for native functions | ||
| 158 | |||
| 159 | /** | ||
| 160 | * The total number of bits in the pixel. | ||
| 161 | */ | ||
| 162 | protected int pixel_bits; | ||
| 163 | int nBits[]; | ||
| 164 | int transparency = Transparency.TRANSLUCENT; | ||
| 165 | boolean supportsAlpha = true; | ||
| 166 | boolean isAlphaPremultiplied = false; | ||
| 167 | int numComponents = -1; | ||
| 168 | int numColorComponents = -1; | ||
| 169 | ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); | ||
| 170 | int colorSpaceType = ColorSpace.TYPE_RGB; | ||
| 171 | int maxBits; | ||
| 172 | boolean is_sRGB = true; | ||
| 173 | |||
| 174 | /** | ||
| 175 | * Data type of the array used to represent pixel values. | ||
| 176 | */ | ||
| 177 | protected int transferType; | ||
| 178 | |||
| 179 | /** | ||
| 180 | * This is copied from java.awt.Toolkit since we need the library | ||
| 181 | * loaded in java.awt.image also: | ||
| 182 | * | ||
| 183 | * WARNING: This is a temporary workaround for a problem in the | ||
| 184 | * way the AWT loads native libraries. A number of classes in the | ||
| 185 | * AWT package have a native method, initIDs(), which initializes | ||
| 186 | * the JNI field and method ids used in the native portion of | ||
| 187 | * their implementation. | ||
| 188 | * | ||
| 189 | * Since the use and storage of these ids is done by the | ||
| 190 | * implementation libraries, the implementation of these method is | ||
| 191 | * provided by the particular AWT implementations (for example, | ||
| 192 | * "Toolkit"s/Peer), such as Motif, Microsoft Windows, or Tiny. The | ||
| 193 | * problem is that this means that the native libraries must be | ||
| 194 | * loaded by the java.* classes, which do not necessarily know the | ||
| 195 | * names of the libraries to load. A better way of doing this | ||
| 196 | * would be to provide a separate library which defines java.awt.* | ||
| 197 | * initIDs, and exports the relevant symbols out to the | ||
| 198 | * implementation libraries. | ||
| 199 | * | ||
| 200 | * For now, we know it's done by the implementation, and we assume | ||
| 201 | * that the name of the library is "awt". -br. | ||
| 202 | */ | ||
| 203 | private static boolean loaded = false; | ||
| 204 | static void loadLibraries() { | ||
| 205 | if (!loaded) { | ||
| 206 | java.security.AccessController.doPrivileged( | ||
| 207 | new sun.security.action.LoadLibraryAction("awt")); | ||
| 208 | loaded = true; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | private static native void initIDs(); | ||
| 212 | static { | ||
| 213 | /* ensure that the proper libraries are loaded */ | ||
| 214 | loadLibraries(); | ||
| 215 | initIDs(); | ||
| 216 | } | ||
| 217 | private static ColorModel RGBdefault; | ||
| 218 | |||
| 219 | /** | ||
| 220 | * Returns a <code>DirectColorModel</code> that describes the default | ||
| 221 | * format for integer RGB values used in many of the methods in the | ||
| 222 | * AWT image interfaces for the convenience of the programmer. | ||
| 223 | * The color space is the default {@link ColorSpace}, sRGB. | ||
| 224 | * The format for the RGB values is an integer with 8 bits | ||
| 225 | * each of alpha, red, green, and blue color components ordered | ||
| 226 | * correspondingly from the most significant byte to the least | ||
| 227 | * significant byte, as in: 0xAARRGGBB. Color components are | ||
| 228 | * not premultiplied by the alpha component. This format does not | ||
| 229 | * necessarily represent the native or the most efficient | ||
| 230 | * <code>ColorModel</code> for a particular device or for all images. | ||
| 231 | * It is merely used as a common color model format. | ||
| 232 | * @return a <code>DirectColorModel</code>object describing default | ||
| 233 | * RGB values. | ||
| 234 | */ | ||
| 235 | public static ColorModel getRGBdefault() { | ||
| 236 | if (RGBdefault == null) { | ||
| 237 | RGBdefault = new DirectColorModel(32, | ||
| 238 | 0x00ff0000, // Red | ||
| 239 | 0x0000ff00, // Green | ||
| 240 | 0x000000ff, // Blue | ||
| 241 | 0xff000000 // Alpha | ||
| 242 | ); | ||
| 243 | } | ||
| 244 | return RGBdefault; | ||
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | * Constructs a <code>ColorModel</code> that translates pixels of the | ||
| 249 | * specified number of bits to color/alpha components. The color | ||
| 250 | * space is the default RGB <code>ColorSpace</code>, which is sRGB. | ||
| 251 | * Pixel values are assumed to include alpha information. If color | ||
| 252 | * and alpha information are represented in the pixel value as | ||
| 253 | * separate spatial bands, the color bands are assumed not to be | ||
| 254 | * premultiplied with the alpha value. The transparency type is | ||
| 255 | * java.awt.Transparency.TRANSLUCENT. The transfer type will be the | ||
| 256 | * smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, | ||
| 257 | * or DataBuffer.TYPE_INT that can hold a single pixel | ||
| 258 | * (or DataBuffer.TYPE_UNDEFINED if bits is greater | ||
| 259 | * than 32). Since this constructor has no information about the | ||
| 260 | * number of bits per color and alpha component, any subclass calling | ||
| 261 | * this constructor should override any method that requires this | ||
| 262 | * information. | ||
| 263 | * @param bits the number of bits of a pixel | ||
| 264 | * @throws IllegalArgumentException if the number | ||
| 265 | * of bits in <code>bits</code> is less than 1 | ||
| 266 | */ | ||
| 267 | public ColorModel(int bits) { | ||
| 268 | pixel_bits = bits; | ||
| 269 | if (bits < 1) { | ||
| 270 | throw new IllegalArgumentException("Number of bits must be > 0"); | ||
| 271 | } | ||
| 272 | numComponents = 4; | ||
| 273 | numColorComponents = 3; | ||
| 274 | maxBits = bits; | ||
| 275 | // REMIND: make sure transferType is set correctly | ||
| 276 | transferType = ColorModel.getDefaultTransferType(bits); | ||
| 277 | } | ||
| 278 | |||
| 279 | /** | ||
| 280 | * Constructs a <code>ColorModel</code> that translates pixel values | ||
| 281 | * to color/alpha components. Color components will be in the | ||
| 282 | * specified <code>ColorSpace</code>. <code>pixel_bits</code> is the | ||
| 283 | * number of bits in the pixel values. The bits array | ||
| 284 | * specifies the number of significant bits per color and alpha component. | ||
| 285 | * Its length should be the number of components in the | ||
| 286 | * <code>ColorSpace</code> if there is no alpha information in the | ||
| 287 | * pixel values, or one more than this number if there is alpha | ||
| 288 | * information. <code>hasAlpha</code> indicates whether or not alpha | ||
| 289 | * information is present. The <code>boolean</code> | ||
| 290 | * <code>isAlphaPremultiplied</code> specifies how to interpret pixel | ||
| 291 | * values in which color and alpha information are represented as | ||
| 292 | * separate spatial bands. If the <code>boolean</code> | ||
| 293 | * is <code>true</code>, color samples are assumed to have been | ||
| 294 | * multiplied by the alpha sample. The <code>transparency</code> | ||
| 295 | * specifies what alpha values can be represented by this color model. | ||
| 296 | * The transfer type is the type of primitive array used to represent | ||
| 297 | * pixel values. Note that the bits array contains the number of | ||
| 298 | * significant bits per color/alpha component after the translation | ||
| 299 | * from pixel values. For example, for an | ||
| 300 | * <code>IndexColorModel</code> with <code>pixel_bits</code> equal to | ||
| 301 | * 16, the bits array might have four elements with each element set | ||
| 302 | * to 8. | ||
| 303 | * @param pixel_bits the number of bits in the pixel values | ||
| 304 | * @param bits array that specifies the number of significant bits | ||
| 305 | * per color and alpha component | ||
| 306 | * @param cspace the specified <code>ColorSpace</code> | ||
| 307 | * @param hasAlpha <code>true</code> if alpha information is present; | ||
| 308 | * <code>false</code> otherwise | ||
| 309 | * @param isAlphaPremultiplied <code>true</code> if color samples are | ||
| 310 | * assumed to be premultiplied by the alpha samples; | ||
| 311 | * <code>false</code> otherwise | ||
| 312 | * @param transparency what alpha values can be represented by this | ||
| 313 | * color model | ||
| 314 | * @param transferType the type of the array used to represent pixel | ||
| 315 | * values | ||
| 316 | * @throws IllegalArgumentException if the length of | ||
| 317 | * the bit array is less than the number of color or alpha | ||
| 318 | * components in this <code>ColorModel</code>, or if the | ||
| 319 | * transparency is not a valid value. | ||
| 320 | * @throws IllegalArgumentException if the sum of the number | ||
| 321 | * of bits in <code>bits</code> is less than 1 or if | ||
| 322 | * any of the elements in <code>bits</code> is less than 0. | ||
| 323 | * @see java.awt.Transparency | ||
| 324 | */ | ||
| 325 | protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace, | ||
| 326 | boolean hasAlpha, | ||
| 327 | boolean isAlphaPremultiplied, | ||
| 328 | int transparency, | ||
| 329 | int transferType) { | ||
| 330 | colorSpace = cspace; | ||
| 331 | colorSpaceType = cspace.getType(); | ||
| 332 | numColorComponents = cspace.getNumComponents(); | ||
| 333 | numComponents = numColorComponents + (hasAlpha ? 1 : 0); | ||
| 334 | supportsAlpha = hasAlpha; | ||
| 335 | if (bits.length < numComponents) { | ||
| 336 | throw new IllegalArgumentException("Number of color/alpha "+ | ||
| 337 | "components should be "+ | ||
| 338 | numComponents+ | ||
| 339 | " but length of bits array is "+ | ||
| 340 | bits.length); | ||
| 341 | } | ||
| 342 | |||
| 343 | // 4186669 | ||
| 344 | if (transparency < Transparency.OPAQUE || | ||
| 345 | transparency > Transparency.TRANSLUCENT) | ||
| 346 | { | ||
| 347 | throw new IllegalArgumentException("Unknown transparency: "+ | ||
| 348 | transparency); | ||
| 349 | } | ||
| 350 | |||
| 351 | if (supportsAlpha == false) { | ||
| 352 | this.isAlphaPremultiplied = false; | ||
| 353 | this.transparency = Transparency.OPAQUE; | ||
| 354 | } | ||
| 355 | else { | ||
| 356 | this.isAlphaPremultiplied = isAlphaPremultiplied; | ||
| 357 | this.transparency = transparency; | ||
| 358 | } | ||
| 359 | |||
| 360 | nBits = (int[]) bits.clone(); | ||
| 361 | this.pixel_bits = pixel_bits; | ||
| 362 | if (pixel_bits <= 0) { | ||
| 363 | throw new IllegalArgumentException("Number of pixel bits must "+ | ||
| 364 | "be > 0"); | ||
| 365 | } | ||
| 366 | // Check for bits < 0 | ||
| 367 | maxBits = 0; | ||
| 368 | for (int i=0; i < bits.length; i++) { | ||
| 369 | // bug 4304697 | ||
| 370 | if (bits[i] < 0) { | ||
| 371 | throw new | ||
| 372 | IllegalArgumentException("Number of bits must be >= 0"); | ||
| 373 | } | ||
| 374 | if (maxBits < bits[i]) { | ||
| 375 | maxBits = bits[i]; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | // Make sure that we don't have all 0-bit components | ||
| 380 | if (maxBits == 0) { | ||
| 381 | throw new IllegalArgumentException("There must be at least "+ | ||
| 382 | "one component with > 0 "+ | ||
| 383 | "pixel bits."); | ||
| 384 | } | ||
| 385 | |||
| 386 | // Save this since we always need to check if it is the default CS | ||
| 387 | if (cspace != ColorSpace.getInstance(ColorSpace.CS_sRGB)) { | ||
| 388 | is_sRGB = false; | ||
| 389 | } | ||
| 390 | |||
| 391 | // Save the transfer type | ||
| 392 | this.transferType = transferType; | ||
| 393 | } | ||
| 394 | |||
| 395 | /** | ||
| 396 | * Returns whether or not alpha is supported in this | ||
| 397 | * <code>ColorModel</code>. | ||
| 398 | * @return <code>true</code> if alpha is supported in this | ||
| 399 | * <code>ColorModel</code>; <code>false</code> otherwise. | ||
| 400 | */ | ||
| 401 | final public boolean hasAlpha() { | ||
| 402 | return supportsAlpha; | ||
| 403 | } | ||
| 404 | |||
| 405 | /** | ||
| 406 | * Returns whether or not the alpha has been premultiplied in the | ||
| 407 | * pixel values to be translated by this <code>ColorModel</code>. | ||
| 408 | * If the boolean is <code>true</code>, this <code>ColorModel</code> | ||
| 409 | * is to be used to interpret pixel values in which color and alpha | ||
| 410 | * information are represented as separate spatial bands, and color | ||
| 411 | * samples are assumed to have been multiplied by the | ||
| 412 | * alpha sample. | ||
| 413 | * @return <code>true</code> if the alpha values are premultiplied | ||
| 414 | * in the pixel values to be translated by this | ||
| 415 | * <code>ColorModel</code>; <code>false</code> otherwise. | ||
| 416 | */ | ||
| 417 | final public boolean isAlphaPremultiplied() { | ||
| 418 | return isAlphaPremultiplied; | ||
| 419 | } | ||
| 420 | |||
| 421 | /** | ||
| 422 | * Returns the transfer type of this <code>ColorModel</code>. | ||
| 423 | * The transfer type is the type of primitive array used to represent | ||
| 424 | * pixel values as arrays. | ||
| 425 | * @return the transfer type. | ||
| 426 | * @since 1.3 | ||
| 427 | */ | ||
| 428 | final public int getTransferType() { | ||
| 429 | return transferType; | ||
| 430 | } | ||
| 431 | |||
| 432 | /** | ||
| 433 | * Returns the number of bits per pixel described by this | ||
| 434 | * <code>ColorModel</code>. | ||
| 435 | * @return the number of bits per pixel. | ||
| 436 | */ | ||
| 437 | public int getPixelSize() { | ||
| 438 | return pixel_bits; | ||
| 439 | } | ||
| 440 | |||
| 441 | /** | ||
| 442 | * Returns the number of bits for the specified color/alpha component. | ||
| 443 | * Color components are indexed in the order specified by the | ||
| 444 | * <code>ColorSpace</code>. Typically, this order reflects the name | ||
| 445 | * of the color space type. For example, for TYPE_RGB, index 0 | ||
| 446 | * corresponds to red, index 1 to green, and index 2 | ||
| 447 | * to blue. If this <code>ColorModel</code> supports alpha, the alpha | ||
| 448 | * component corresponds to the index following the last color | ||
| 449 | * component. | ||
| 450 | * @param componentIdx the index of the color/alpha component | ||
| 451 | * @return the number of bits for the color/alpha component at the | ||
| 452 | * specified index. | ||
| 453 | * @throws ArrayIndexOutOfBoundsException if <code>componentIdx</code> | ||
| 454 | * is greater than the number of components or | ||
| 455 | * less than zero | ||
| 456 | * @throws NullPointerException if the number of bits array is | ||
| 457 | * <code>null</code> | ||
| 458 | */ | ||
| 459 | public int getComponentSize(int componentIdx) { | ||
| 460 | // REMIND: | ||
| 461 | if (nBits == null) { | ||
| 462 | throw new NullPointerException("Number of bits array is null."); | ||
| 463 | } | ||
| 464 | |||
| 465 | return nBits[componentIdx]; | ||
| 466 | } | ||
| 467 | |||
| 468 | /** | ||
| 469 | * Returns an array of the number of bits per color/alpha component. | ||
| 470 | * The array contains the color components in the order specified by the | ||
| 471 | * <code>ColorSpace</code>, followed by the alpha component, if | ||
| 472 | * present. | ||
| 473 | * @return an array of the number of bits per color/alpha component | ||
| 474 | */ | ||
| 475 | public int[] getComponentSize() { | ||
| 476 | if (nBits != null) { | ||
| 477 | return (int[]) nBits.clone(); | ||
| 478 | } | ||
| 479 | |||
| 480 | return null; | ||
| 481 | } | ||
| 482 | |||
| 483 | /** | ||
| 484 | * Returns the transparency. Returns either OPAQUE, BITMASK, | ||
| 485 | * or TRANSLUCENT. | ||
| 486 | * @return the transparency of this <code>ColorModel</code>. | ||
| 487 | * @see Transparency#OPAQUE | ||
| 488 | * @see Transparency#BITMASK | ||
| 489 | * @see Transparency#TRANSLUCENT | ||
| 490 | */ | ||
| 491 | public int getTransparency() { | ||
| 492 | return transparency; | ||
| 493 | } | ||
| 494 | |||
| 495 | /** | ||
| 496 | * Returns the number of components, including alpha, in this | ||
| 497 | * <code>ColorModel</code>. This is equal to the number of color | ||
| 498 | * components, optionally plus one, if there is an alpha component. | ||
| 499 | * @return the number of components in this <code>ColorModel</code> | ||
| 500 | */ | ||
| 501 | public int getNumComponents() { | ||
| 502 | return numComponents; | ||
| 503 | } | ||
| 504 | |||
| 505 | /** | ||
| 506 | * Returns the number of color components in this | ||
| 507 | * <code>ColorModel</code>. | ||
| 508 | * This is the number of components returned by | ||
| 509 | * {@link ColorSpace#getNumComponents}. | ||
| 510 | * @return the number of color components in this | ||
| 511 | * <code>ColorModel</code>. | ||
| 512 | * @see ColorSpace#getNumComponents | ||
| 513 | */ | ||
| 514 | public int getNumColorComponents() { | ||
| 515 | return numColorComponents; | ||
| 516 | } | ||
| 517 | |||
| 518 | /** | ||
| 519 | * Returns the red color component for the specified pixel, scaled | ||
| 520 | * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion | ||
| 521 | * is done if necessary. The pixel value is specified as an int. | ||
| 522 | * An <code>IllegalArgumentException</code> is thrown if pixel | ||
| 523 | * values for this <code>ColorModel</code> are not conveniently | ||
| 524 | * representable as a single int. The returned value is not a | ||
| 525 | * pre-multiplied value. For example, if the | ||
| 526 | * alpha is premultiplied, this method divides it out before returning | ||
| 527 | * the value. If the alpha value is 0, the red value is 0. | ||
| 528 | * @param pixel a specified pixel | ||
| 529 | * @return the value of the red component of the specified pixel. | ||
| 530 | */ | ||
| 531 | public abstract int getRed(int pixel); | ||
| 532 | |||
| 533 | /** | ||
| 534 | * Returns the green color component for the specified pixel, scaled | ||
| 535 | * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion | ||
| 536 | * is done if necessary. The pixel value is specified as an int. | ||
| 537 | * An <code>IllegalArgumentException</code> is thrown if pixel | ||
| 538 | * values for this <code>ColorModel</code> are not conveniently | ||
| 539 | * representable as a single int. The returned value is a non | ||
| 540 | * pre-multiplied value. For example, if the alpha is premultiplied, | ||
| 541 | * this method divides it out before returning | ||
| 542 | * the value. If the alpha value is 0, the green value is 0. | ||
| 543 | * @param pixel the specified pixel | ||
| 544 | * @return the value of the green component of the specified pixel. | ||
| 545 | */ | ||
| 546 | public abstract int getGreen(int pixel); | ||
| 547 | |||
| 548 | /** | ||
| 549 | * Returns the blue color component for the specified pixel, scaled | ||
| 550 | * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion | ||
| 551 | * is done if necessary. The pixel value is specified as an int. | ||
| 552 | * An <code>IllegalArgumentException</code> is thrown if pixel values | ||
| 553 | * for this <code>ColorModel</code> are not conveniently representable | ||
| 554 | * as a single int. The returned value is a non pre-multiplied | ||
| 555 | * value, for example, if the alpha is premultiplied, this method | ||
| 556 | * divides it out before returning the value. If the alpha value is | ||
| 557 | * 0, the blue value is 0. | ||
| 558 | * @param pixel the specified pixel | ||
| 559 | * @return the value of the blue component of the specified pixel. | ||
| 560 | */ | ||
| 561 | public abstract int getBlue(int pixel); | ||
| 562 | |||
| 563 | /** | ||
| 564 | * Returns the alpha component for the specified pixel, scaled | ||
| 565 | * from 0 to 255. The pixel value is specified as an int. | ||
| 566 | * An <code>IllegalArgumentException</code> is thrown if pixel | ||
| 567 | * values for this <code>ColorModel</code> are not conveniently | ||
| 568 | * representable as a single int. | ||
| 569 | * @param pixel the specified pixel | ||
| 570 | * @return the value of alpha component of the specified pixel. | ||
| 571 | */ | ||
| 572 | public abstract int getAlpha(int pixel); | ||
| 573 | |||
| 574 | /** | ||
| 575 | * Returns the color/alpha components of the pixel in the default | ||
| 576 | * RGB color model format. A color conversion is done if necessary. | ||
| 577 | * The pixel value is specified as an int. | ||
| 578 | * An <code>IllegalArgumentException</code> thrown if pixel values | ||
| 579 | * for this <code>ColorModel</code> are not conveniently representable | ||
| 580 | * as a single int. The returned value is in a non | ||
| 581 | * pre-multiplied format. For example, if the alpha is premultiplied, | ||
| 582 | * this method divides it out of the color components. If the alpha | ||
| 583 | * value is 0, the color values are 0. | ||
| 584 | * @param pixel the specified pixel | ||
| 585 | * @return the RGB value of the color/alpha components of the | ||
| 586 | * specified pixel. | ||
| 587 | * @see ColorModel#getRGBdefault | ||
| 588 | */ | ||
| 589 | public int getRGB(int pixel) { | ||
| 590 | return (getAlpha(pixel) << 24) | ||
| 591 | | (getRed(pixel) << 16) | ||
| 592 | | (getGreen(pixel) << 8) | ||
| 593 | | (getBlue(pixel) << 0); | ||
| 594 | } | ||
| 595 | |||
| 596 | /** | ||
| 597 | * Returns the red color component for the specified pixel, scaled | ||
| 598 | * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A | ||
| 599 | * color conversion is done if necessary. The pixel value is | ||
| 600 | * specified by an array of data elements of type transferType passed | ||
| 601 | * in as an object reference. The returned value is a non | ||
| 602 | * pre-multiplied value. For example, if alpha is premultiplied, | ||
| 603 | * this method divides it out before returning | ||
| 604 | * the value. If the alpha value is 0, the red value is 0. | ||
| 605 | * If <code>inData</code> is not a primitive array of type | ||
| 606 | * transferType, a <code>ClassCastException</code> is thrown. An | ||
| 607 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 608 | * <code>inData</code> is not large enough to hold a pixel value for | ||
| 609 | * this <code>ColorModel</code>. | ||
| 610 | * If this <code>transferType</code> is not supported, a | ||
| 611 | * <code>UnsupportedOperationException</code> will be | ||
| 612 | * thrown. Since | ||
| 613 | * <code>ColorModel</code> is an abstract class, any instance | ||
| 614 | * must be an instance of a subclass. Subclasses inherit the | ||
| 615 | * implementation of this method and if they don't override it, this | ||
| 616 | * method throws an exception if the subclass uses a | ||
| 617 | * <code>transferType</code> other than | ||
| 618 | * <code>DataBuffer.TYPE_BYTE</code>, | ||
| 619 | * <code>DataBuffer.TYPE_USHORT</code>, or | ||
| 620 | * <code>DataBuffer.TYPE_INT</code>. | ||
| 621 | * @param inData an array of pixel values | ||
| 622 | * @return the value of the red component of the specified pixel. | ||
| 623 | * @throws ClassCastException if <code>inData</code> | ||
| 624 | * is not a primitive array of type <code>transferType</code> | ||
| 625 | * @throws ArrayIndexOutOfBoundsException if | ||
| 626 | * <code>inData</code> is not large enough to hold a pixel value | ||
| 627 | * for this <code>ColorModel</code> | ||
| 628 | * @throws UnsupportedOperationException if this | ||
| 629 | * <code>tranferType</code> is not supported by this | ||
| 630 | * <code>ColorModel</code> | ||
| 631 | */ | ||
| 632 | public int getRed(Object inData) { | ||
| 633 | int pixel=0,length=0; | ||
| 634 | switch (transferType) { | ||
| 635 | case DataBuffer.TYPE_BYTE: | ||
| 636 | byte bdata[] = (byte[])inData; | ||
| 637 | pixel = bdata[0] & 0xff; | ||
| 638 | length = bdata.length; | ||
| 639 | break; | ||
| 640 | case DataBuffer.TYPE_USHORT: | ||
| 641 | short sdata[] = (short[])inData; | ||
| 642 | pixel = sdata[0] & 0xffff; | ||
| 643 | length = sdata.length; | ||
| 644 | break; | ||
| 645 | case DataBuffer.TYPE_INT: | ||
| 646 | int idata[] = (int[])inData; | ||
| 647 | pixel = idata[0]; | ||
| 648 | length = idata.length; | ||
| 649 | break; | ||
| 650 | default: | ||
| 651 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 652 | "implemented for transferType " + transferType); | ||
| 653 | } | ||
| 654 | if (length == 1) { | ||
| 655 | return getRed(pixel); | ||
| 656 | } | ||
| 657 | else { | ||
| 658 | throw new UnsupportedOperationException | ||
| 659 | ("This method is not supported by this color model"); | ||
| 660 | } | ||
| 661 | } | ||
| 662 | |||
| 663 | /** | ||
| 664 | * Returns the green color component for the specified pixel, scaled | ||
| 665 | * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A | ||
| 666 | * color conversion is done if necessary. The pixel value is | ||
| 667 | * specified by an array of data elements of type transferType passed | ||
| 668 | * in as an object reference. The returned value will be a non | ||
| 669 | * pre-multiplied value. For example, if the alpha is premultiplied, | ||
| 670 | * this method divides it out before returning the value. If the | ||
| 671 | * alpha value is 0, the green value is 0. If <code>inData</code> is | ||
| 672 | * not a primitive array of type transferType, a | ||
| 673 | * <code>ClassCastException</code> is thrown. An | ||
| 674 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 675 | * <code>inData</code> is not large enough to hold a pixel value for | ||
| 676 | * this <code>ColorModel</code>. | ||
| 677 | * If this <code>transferType</code> is not supported, a | ||
| 678 | * <code>UnsupportedOperationException</code> will be | ||
| 679 | * thrown. Since | ||
| 680 | * <code>ColorModel</code> is an abstract class, any instance | ||
| 681 | * must be an instance of a subclass. Subclasses inherit the | ||
| 682 | * implementation of this method and if they don't override it, this | ||
| 683 | * method throws an exception if the subclass uses a | ||
| 684 | * <code>transferType</code> other than | ||
| 685 | * <code>DataBuffer.TYPE_BYTE</code>, | ||
| 686 | * <code>DataBuffer.TYPE_USHORT</code>, or | ||
| 687 | * <code>DataBuffer.TYPE_INT</code>. | ||
| 688 | * @param inData an array of pixel values | ||
| 689 | * @return the value of the green component of the specified pixel. | ||
| 690 | * @throws <code>ClassCastException</code> if <code>inData</code> | ||
| 691 | * is not a primitive array of type <code>transferType</code> | ||
| 692 | * @throws <code>ArrayIndexOutOfBoundsException</code> if | ||
| 693 | * <code>inData</code> is not large enough to hold a pixel value | ||
| 694 | * for this <code>ColorModel</code> | ||
| 695 | * @throws <code>UnsupportedOperationException</code> if this | ||
| 696 | * <code>tranferType</code> is not supported by this | ||
| 697 | * <code>ColorModel</code> | ||
| 698 | */ | ||
| 699 | public int getGreen(Object inData) { | ||
| 700 | int pixel=0,length=0; | ||
| 701 | switch (transferType) { | ||
| 702 | case DataBuffer.TYPE_BYTE: | ||
| 703 | byte bdata[] = (byte[])inData; | ||
| 704 | pixel = bdata[0] & 0xff; | ||
| 705 | length = bdata.length; | ||
| 706 | break; | ||
| 707 | case DataBuffer.TYPE_USHORT: | ||
| 708 | short sdata[] = (short[])inData; | ||
| 709 | pixel = sdata[0] & 0xffff; | ||
| 710 | length = sdata.length; | ||
| 711 | break; | ||
| 712 | case DataBuffer.TYPE_INT: | ||
| 713 | int idata[] = (int[])inData; | ||
| 714 | pixel = idata[0]; | ||
| 715 | length = idata.length; | ||
| 716 | break; | ||
| 717 | default: | ||
| 718 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 719 | "implemented for transferType " + transferType); | ||
| 720 | } | ||
| 721 | if (length == 1) { | ||
| 722 | return getGreen(pixel); | ||
| 723 | } | ||
| 724 | else { | ||
| 725 | throw new UnsupportedOperationException | ||
| 726 | ("This method is not supported by this color model"); | ||
| 727 | } | ||
| 728 | } | ||
| 729 | |||
| 730 | /** | ||
| 731 | * Returns the blue color component for the specified pixel, scaled | ||
| 732 | * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A | ||
| 733 | * color conversion is done if necessary. The pixel value is | ||
| 734 | * specified by an array of data elements of type transferType passed | ||
| 735 | * in as an object reference. The returned value is a non | ||
| 736 | * pre-multiplied value. For example, if the alpha is premultiplied, | ||
| 737 | * this method divides it out before returning the value. If the | ||
| 738 | * alpha value is 0, the blue value will be 0. If | ||
| 739 | * <code>inData</code> is not a primitive array of type transferType, | ||
| 740 | * a <code>ClassCastException</code> is thrown. An | ||
| 741 | * <code>ArrayIndexOutOfBoundsException</code> is | ||
| 742 | * thrown if <code>inData</code> is not large enough to hold a pixel | ||
| 743 | * value for this <code>ColorModel</code>. | ||
| 744 | * If this <code>transferType</code> is not supported, a | ||
| 745 | * <code>UnsupportedOperationException</code> will be | ||
| 746 | * thrown. Since | ||
| 747 | * <code>ColorModel</code> is an abstract class, any instance | ||
| 748 | * must be an instance of a subclass. Subclasses inherit the | ||
| 749 | * implementation of this method and if they don't override it, this | ||
| 750 | * method throws an exception if the subclass uses a | ||
| 751 | * <code>transferType</code> other than | ||
| 752 | * <code>DataBuffer.TYPE_BYTE</code>, | ||
| 753 | * <code>DataBuffer.TYPE_USHORT</code>, or | ||
| 754 | * <code>DataBuffer.TYPE_INT</code>. | ||
| 755 | * @param inData an array of pixel values | ||
| 756 | * @return the value of the blue component of the specified pixel. | ||
| 757 | * @throws ClassCastException if <code>inData</code> | ||
| 758 | * is not a primitive array of type <code>transferType</code> | ||
| 759 | * @throws ArrayIndexOutOfBoundsException if | ||
| 760 | * <code>inData</code> is not large enough to hold a pixel value | ||
| 761 | * for this <code>ColorModel</code> | ||
| 762 | * @throws UnsupportedOperationException if this | ||
| 763 | * <code>tranferType</code> is not supported by this | ||
| 764 | * <code>ColorModel</code> | ||
| 765 | */ | ||
| 766 | public int getBlue(Object inData) { | ||
| 767 | int pixel=0,length=0; | ||
| 768 | switch (transferType) { | ||
| 769 | case DataBuffer.TYPE_BYTE: | ||
| 770 | byte bdata[] = (byte[])inData; | ||
| 771 | pixel = bdata[0] & 0xff; | ||
| 772 | length = bdata.length; | ||
| 773 | break; | ||
| 774 | case DataBuffer.TYPE_USHORT: | ||
| 775 | short sdata[] = (short[])inData; | ||
| 776 | pixel = sdata[0] & 0xffff; | ||
| 777 | length = sdata.length; | ||
| 778 | break; | ||
| 779 | case DataBuffer.TYPE_INT: | ||
| 780 | int idata[] = (int[])inData; | ||
| 781 | pixel = idata[0]; | ||
| 782 | length = idata.length; | ||
| 783 | break; | ||
| 784 | default: | ||
| 785 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 786 | "implemented for transferType " + transferType); | ||
| 787 | } | ||
| 788 | if (length == 1) { | ||
| 789 | return getBlue(pixel); | ||
| 790 | } | ||
| 791 | else { | ||
| 792 | throw new UnsupportedOperationException | ||
| 793 | ("This method is not supported by this color model"); | ||
| 794 | } | ||
| 795 | } | ||
| 796 | |||
| 797 | /** | ||
| 798 | * Returns the alpha component for the specified pixel, scaled | ||
| 799 | * from 0 to 255. The pixel value is specified by an array of data | ||
| 800 | * elements of type transferType passed in as an object reference. | ||
| 801 | * If inData is not a primitive array of type transferType, a | ||
| 802 | * <code>ClassCastException</code> is thrown. An | ||
| 803 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 804 | * <code>inData</code> is not large enough to hold a pixel value for | ||
| 805 | * this <code>ColorModel</code>. | ||
| 806 | * If this <code>transferType</code> is not supported, a | ||
| 807 | * <code>UnsupportedOperationException</code> will be | ||
| 808 | * thrown. Since | ||
| 809 | * <code>ColorModel</code> is an abstract class, any instance | ||
| 810 | * must be an instance of a subclass. Subclasses inherit the | ||
| 811 | * implementation of this method and if they don't override it, this | ||
| 812 | * method throws an exception if the subclass uses a | ||
| 813 | * <code>transferType</code> other than | ||
| 814 | * <code>DataBuffer.TYPE_BYTE</code>, | ||
| 815 | * <code>DataBuffer.TYPE_USHORT</code>, or | ||
| 816 | * <code>DataBuffer.TYPE_INT</code>. | ||
| 817 | * @param inData the specified pixel | ||
| 818 | * @return the alpha component of the specified pixel, scaled from | ||
| 819 | * 0 to 255. | ||
| 820 | * @throws ClassCastException if <code>inData</code> | ||
| 821 | * is not a primitive array of type <code>transferType</code> | ||
| 822 | * @throws ArrayIndexOutOfBoundsException if | ||
| 823 | * <code>inData</code> is not large enough to hold a pixel value | ||
| 824 | * for this <code>ColorModel</code> | ||
| 825 | * @throws UnsupportedOperationException if this | ||
| 826 | * <code>tranferType</code> is not supported by this | ||
| 827 | * <code>ColorModel</code> | ||
| 828 | */ | ||
| 829 | public int getAlpha(Object inData) { | ||
| 830 | int pixel=0,length=0; | ||
| 831 | switch (transferType) { | ||
| 832 | case DataBuffer.TYPE_BYTE: | ||
| 833 | byte bdata[] = (byte[])inData; | ||
| 834 | pixel = bdata[0] & 0xff; | ||
| 835 | length = bdata.length; | ||
| 836 | break; | ||
| 837 | case DataBuffer.TYPE_USHORT: | ||
| 838 | short sdata[] = (short[])inData; | ||
| 839 | pixel = sdata[0] & 0xffff; | ||
| 840 | length = sdata.length; | ||
| 841 | break; | ||
| 842 | case DataBuffer.TYPE_INT: | ||
| 843 | int idata[] = (int[])inData; | ||
| 844 | pixel = idata[0]; | ||
| 845 | length = idata.length; | ||
| 846 | break; | ||
| 847 | default: | ||
| 848 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 849 | "implemented for transferType " + transferType); | ||
| 850 | } | ||
| 851 | if (length == 1) { | ||
| 852 | return getAlpha(pixel); | ||
| 853 | } | ||
| 854 | else { | ||
| 855 | throw new UnsupportedOperationException | ||
| 856 | ("This method is not supported by this color model"); | ||
| 857 | } | ||
| 858 | } | ||
| 859 | |||
| 860 | /** | ||
| 861 | * Returns the color/alpha components for the specified pixel in the | ||
| 862 | * default RGB color model format. A color conversion is done if | ||
| 863 | * necessary. The pixel value is specified by an array of data | ||
| 864 | * elements of type transferType passed in as an object reference. | ||
| 865 | * If inData is not a primitive array of type transferType, a | ||
| 866 | * <code>ClassCastException</code> is thrown. An | ||
| 867 | * <code>ArrayIndexOutOfBoundsException</code> is | ||
| 868 | * thrown if <code>inData</code> is not large enough to hold a pixel | ||
| 869 | * value for this <code>ColorModel</code>. | ||
| 870 | * The returned value will be in a non pre-multiplied format, i.e. if | ||
| 871 | * the alpha is premultiplied, this method will divide it out of the | ||
| 872 | * color components (if the alpha value is 0, the color values will be 0). | ||
| 873 | * @param inData the specified pixel | ||
| 874 | * @return the color and alpha components of the specified pixel. | ||
| 875 | * @see ColorModel#getRGBdefault | ||
| 876 | */ | ||
| 877 | public int getRGB(Object inData) { | ||
| 878 | return (getAlpha(inData) << 24) | ||
| 879 | | (getRed(inData) << 16) | ||
| 880 | | (getGreen(inData) << 8) | ||
| 881 | | (getBlue(inData) << 0); | ||
| 882 | } | ||
| 883 | |||
| 884 | /** | ||
| 885 | * Returns a data element array representation of a pixel in this | ||
| 886 | * <code>ColorModel</code>, given an integer pixel representation in | ||
| 887 | * the default RGB color model. | ||
| 888 | * This array can then be passed to the | ||
| 889 | * {@link WritableRaster#setDataElements} method of | ||
| 890 | * a {@link WritableRaster} object. If the pixel variable is | ||
| 891 | * <code>null</code>, a new array will be allocated. If | ||
| 892 | * <code>pixel</code> is not | ||
| 893 | * <code>null</code>, it must be a primitive array of type | ||
| 894 | * <code>transferType</code>; otherwise, a | ||
| 895 | * <code>ClassCastException</code> is thrown. An | ||
| 896 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 897 | * <code>pixel</code> is | ||
| 898 | * not large enough to hold a pixel value for this | ||
| 899 | * <code>ColorModel</code>. The pixel array is returned. | ||
| 900 | * If this <code>transferType</code> is not supported, a | ||
| 901 | * <code>UnsupportedOperationException</code> will be | ||
| 902 | * thrown. Since <code>ColorModel</code> is an abstract class, | ||
| 903 | * any instance is an instance of a subclass. Subclasses must | ||
| 904 | * override this method since the implementation in this abstract | ||
| 905 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 906 | * @param rgb the integer pixel representation in the default RGB | ||
| 907 | * color model | ||
| 908 | * @param pixel the specified pixel | ||
| 909 | * @return an array representation of the specified pixel in this | ||
| 910 | * <code>ColorModel</code>. | ||
| 911 | * @throws ClassCastException if <code>pixel</code> | ||
| 912 | * is not a primitive array of type <code>transferType</code> | ||
| 913 | * @throws ArrayIndexOutOfBoundsException if | ||
| 914 | * <code>pixel</code> is not large enough to hold a pixel value | ||
| 915 | * for this <code>ColorModel</code> | ||
| 916 | * @throws UnsupportedOperationException if this | ||
| 917 | * method is not supported by this <code>ColorModel</code> | ||
| 918 | * @see WritableRaster#setDataElements | ||
| 919 | * @see SampleModel#setDataElements | ||
| 920 | */ | ||
| 921 | public Object getDataElements(int rgb, Object pixel) { | ||
| 922 | throw new UnsupportedOperationException | ||
| 923 | ("This method is not supported by this color model."); | ||
| 924 | } | ||
| 925 | |||
| 926 | /** | ||
| 927 | * Returns an array of unnormalized color/alpha components given a pixel | ||
| 928 | * in this <code>ColorModel</code>. The pixel value is specified as | ||
| 929 | * an <code>int</code>. An <code>IllegalArgumentException</code> | ||
| 930 | * will be thrown if pixel values for this <code>ColorModel</code> are | ||
| 931 | * not conveniently representable as a single <code>int</code> or if | ||
| 932 | * color component values for this <code>ColorModel</code> are not | ||
| 933 | * conveniently representable in the unnormalized form. | ||
| 934 | * For example, this method can be used to retrieve the | ||
| 935 | * components for a specific pixel value in a | ||
| 936 | * <code>DirectColorModel</code>. If the components array is | ||
| 937 | * <code>null</code>, a new array will be allocated. The | ||
| 938 | * components array will be returned. Color/alpha components are | ||
| 939 | * stored in the components array starting at <code>offset</code> | ||
| 940 | * (even if the array is allocated by this method). An | ||
| 941 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if the | ||
| 942 | * components array is not <code>null</code> and is not large | ||
| 943 | * enough to hold all the color and alpha components (starting at offset). | ||
| 944 | * Since <code>ColorModel</code> is an abstract class, | ||
| 945 | * any instance is an instance of a subclass. Subclasses must | ||
| 946 | * override this method since the implementation in this abstract | ||
| 947 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 948 | * @param pixel the specified pixel | ||
| 949 | * @param components the array to receive the color and alpha | ||
| 950 | * components of the specified pixel | ||
| 951 | * @param offset the offset into the <code>components</code> array at | ||
| 952 | * which to start storing the color and alpha components | ||
| 953 | * @return an array containing the color and alpha components of the | ||
| 954 | * specified pixel starting at the specified offset. | ||
| 955 | * @throws UnsupportedOperationException if this | ||
| 956 | * method is not supported by this <code>ColorModel</code> | ||
| 957 | */ | ||
| 958 | public int[] getComponents(int pixel, int[] components, int offset) { | ||
| 959 | throw new UnsupportedOperationException | ||
| 960 | ("This method is not supported by this color model."); | ||
| 961 | } | ||
| 962 | |||
| 963 | /** | ||
| 964 | * Returns an array of unnormalized color/alpha components given a pixel | ||
| 965 | * in this <code>ColorModel</code>. The pixel value is specified by | ||
| 966 | * an array of data elements of type transferType passed in as an | ||
| 967 | * object reference. If <code>pixel</code> is not a primitive array | ||
| 968 | * of type transferType, a <code>ClassCastException</code> is thrown. | ||
| 969 | * An <code>IllegalArgumentException</code> will be thrown if color | ||
| 970 | * component values for this <code>ColorModel</code> are not | ||
| 971 | * conveniently representable in the unnormalized form. | ||
| 972 | * An <code>ArrayIndexOutOfBoundsException</code> is | ||
| 973 | * thrown if <code>pixel</code> is not large enough to hold a pixel | ||
| 974 | * value for this <code>ColorModel</code>. | ||
| 975 | * This method can be used to retrieve the components for a specific | ||
| 976 | * pixel value in any <code>ColorModel</code>. If the components | ||
| 977 | * array is <code>null</code>, a new array will be allocated. The | ||
| 978 | * components array will be returned. Color/alpha components are | ||
| 979 | * stored in the <code>components</code> array starting at | ||
| 980 | * <code>offset</code> (even if the array is allocated by this | ||
| 981 | * method). An <code>ArrayIndexOutOfBoundsException</code> | ||
| 982 | * is thrown if the components array is not <code>null</code> and is | ||
| 983 | * not large enough to hold all the color and alpha components | ||
| 984 | * (starting at <code>offset</code>). | ||
| 985 | * Since <code>ColorModel</code> is an abstract class, | ||
| 986 | * any instance is an instance of a subclass. Subclasses must | ||
| 987 | * override this method since the implementation in this abstract | ||
| 988 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 989 | * @param pixel the specified pixel | ||
| 990 | * @param components an array that receives the color and alpha | ||
| 991 | * components of the specified pixel | ||
| 992 | * @param offset the index into the <code>components</code> array at | ||
| 993 | * which to begin storing the color and alpha components of the | ||
| 994 | * specified pixel | ||
| 995 | * @return an array containing the color and alpha components of the | ||
| 996 | * specified pixel starting at the specified offset. | ||
| 997 | * @throws UnsupportedOperationException if this | ||
| 998 | * method is not supported by this <code>ColorModel</code> | ||
| 999 | */ | ||
| 1000 | public int[] getComponents(Object pixel, int[] components, int offset) { | ||
| 1001 | throw new UnsupportedOperationException | ||
| 1002 | ("This method is not supported by this color model."); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | /** | ||
| 1006 | * Returns an array of all of the color/alpha components in unnormalized | ||
| 1007 | * form, given a normalized component array. Unnormalized components | ||
| 1008 | * are unsigned integral values between 0 and 2<sup>n</sup> - 1, where | ||
| 1009 | * n is the number of bits for a particular component. Normalized | ||
| 1010 | * components are float values between a per component minimum and | ||
| 1011 | * maximum specified by the <code>ColorSpace</code> object for this | ||
| 1012 | * <code>ColorModel</code>. An <code>IllegalArgumentException</code> | ||
| 1013 | * will be thrown if color component values for this | ||
| 1014 | * <code>ColorModel</code> are not conveniently representable in the | ||
| 1015 | * unnormalized form. If the | ||
| 1016 | * <code>components</code> array is <code>null</code>, a new array | ||
| 1017 | * will be allocated. The <code>components</code> array will | ||
| 1018 | * be returned. Color/alpha components are stored in the | ||
| 1019 | * <code>components</code> array starting at <code>offset</code> (even | ||
| 1020 | * if the array is allocated by this method). An | ||
| 1021 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if the | ||
| 1022 | * <code>components</code> array is not <code>null</code> and is not | ||
| 1023 | * large enough to hold all the color and alpha | ||
| 1024 | * components (starting at <code>offset</code>). An | ||
| 1025 | * <code>IllegalArgumentException</code> is thrown if the | ||
| 1026 | * <code>normComponents</code> array is not large enough to hold | ||
| 1027 | * all the color and alpha components starting at | ||
| 1028 | * <code>normOffset</code>. | ||
| 1029 | * @param normComponents an array containing normalized components | ||
| 1030 | * @param normOffset the offset into the <code>normComponents</code> | ||
| 1031 | * array at which to start retrieving normalized components | ||
| 1032 | * @param components an array that receives the components from | ||
| 1033 | * <code>normComponents</code> | ||
| 1034 | * @param offset the index into <code>components</code> at which to | ||
| 1035 | * begin storing normalized components from | ||
| 1036 | * <code>normComponents</code> | ||
| 1037 | * @return an array containing unnormalized color and alpha | ||
| 1038 | * components. | ||
| 1039 | * @throws IllegalArgumentException If the component values for this | ||
| 1040 | * <CODE>ColorModel</CODE> are not conveniently representable in the | ||
| 1041 | * unnormalized form. | ||
| 1042 | * @throws IllegalArgumentException if the length of | ||
| 1043 | * <code>normComponents</code> minus <code>normOffset</code> | ||
| 1044 | * is less than <code>numComponents</code> | ||
| 1045 | * @throws UnsupportedOperationException if the | ||
| 1046 | * constructor of this <code>ColorModel</code> called the | ||
| 1047 | * <code>super(bits)</code> constructor, but did not | ||
| 1048 | * override this method. See the constructor, | ||
| 1049 | * {@link #ColorModel(int)}. | ||
| 1050 | */ | ||
| 1051 | public int[] getUnnormalizedComponents(float[] normComponents, | ||
| 1052 | int normOffset, | ||
| 1053 | int[] components, int offset) { | ||
| 1054 | // Make sure that someone isn't using a custom color model | ||
| 1055 | // that called the super(bits) constructor. | ||
| 1056 | if (colorSpace == null) { | ||
| 1057 | throw new UnsupportedOperationException("This method is not supported "+ | ||
| 1058 | "by this color model."); | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | if (nBits == null) { | ||
| 1062 | throw new UnsupportedOperationException ("This method is not supported. "+ | ||
| 1063 | "Unable to determine #bits per "+ | ||
| 1064 | "component."); | ||
| 1065 | } | ||
| 1066 | if ((normComponents.length - normOffset) < numComponents) { | ||
| 1067 | throw new | ||
| 1068 | IllegalArgumentException( | ||
| 1069 | "Incorrect number of components. Expecting "+ | ||
| 1070 | numComponents); | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | if (components == null) { | ||
| 1074 | components = new int[offset+numComponents]; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | if (supportsAlpha && isAlphaPremultiplied) { | ||
| 1078 | float normAlpha = normComponents[normOffset+numColorComponents]; | ||
| 1079 | for (int i=0; i < numColorComponents; i++) { | ||
| 1080 | components[offset+i] = (int) (normComponents[normOffset+i] | ||
| 1081 | * ((1<<nBits[i]) - 1) | ||
| 1082 | * normAlpha + 0.5f); | ||
| 1083 | } | ||
| 1084 | components[offset+numColorComponents] = (int) | ||
| 1085 | (normAlpha * ((1<<nBits[numColorComponents]) - 1) + 0.5f); | ||
| 1086 | } | ||
| 1087 | else { | ||
| 1088 | for (int i=0; i < numComponents; i++) { | ||
| 1089 | components[offset+i] = (int) (normComponents[normOffset+i] | ||
| 1090 | * ((1<<nBits[i]) - 1) + 0.5f); | ||
| 1091 | } | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | return components; | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | /** | ||
| 1098 | * Returns an array of all of the color/alpha components in normalized | ||
| 1099 | * form, given an unnormalized component array. Unnormalized components | ||
| 1100 | * are unsigned integral values between 0 and 2<sup>n</sup> - 1, where | ||
| 1101 | * n is the number of bits for a particular component. Normalized | ||
| 1102 | * components are float values between a per component minimum and | ||
| 1103 | * maximum specified by the <code>ColorSpace</code> object for this | ||
| 1104 | * <code>ColorModel</code>. An <code>IllegalArgumentException</code> | ||
| 1105 | * will be thrown if color component values for this | ||
| 1106 | * <code>ColorModel</code> are not conveniently representable in the | ||
| 1107 | * unnormalized form. If the | ||
| 1108 | * <code>normComponents</code> array is <code>null</code>, a new array | ||
| 1109 | * will be allocated. The <code>normComponents</code> array | ||
| 1110 | * will be returned. Color/alpha components are stored in the | ||
| 1111 | * <code>normComponents</code> array starting at | ||
| 1112 | * <code>normOffset</code> (even if the array is allocated by this | ||
| 1113 | * method). An <code>ArrayIndexOutOfBoundsException</code> is thrown | ||
| 1114 | * if the <code>normComponents</code> array is not <code>null</code> | ||
| 1115 | * and is not large enough to hold all the color and alpha components | ||
| 1116 | * (starting at <code>normOffset</code>). An | ||
| 1117 | * <code>IllegalArgumentException</code> is thrown if the | ||
| 1118 | * <code>components</code> array is not large enough to hold all the | ||
| 1119 | * color and alpha components starting at <code>offset</code>. | ||
| 1120 | * <p> | ||
| 1121 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1122 | * any instance is an instance of a subclass. The default implementation | ||
| 1123 | * of this method in this abstract class assumes that component values | ||
| 1124 | * for this class are conveniently representable in the unnormalized | ||
| 1125 | * form. Therefore, subclasses which may | ||
| 1126 | * have instances which do not support the unnormalized form must | ||
| 1127 | * override this method. | ||
| 1128 | * @param components an array containing unnormalized components | ||
| 1129 | * @param offset the offset into the <code>components</code> array at | ||
| 1130 | * which to start retrieving unnormalized components | ||
| 1131 | * @param normComponents an array that receives the normalized components | ||
| 1132 | * @param normOffset the index into <code>normComponents</code> at | ||
| 1133 | * which to begin storing normalized components | ||
| 1134 | * @return an array containing normalized color and alpha | ||
| 1135 | * components. | ||
| 1136 | * @throws IllegalArgumentException If the component values for this | ||
| 1137 | * <CODE>ColorModel</CODE> are not conveniently representable in the | ||
| 1138 | * unnormalized form. | ||
| 1139 | * @throws UnsupportedOperationException if the | ||
| 1140 | * constructor of this <code>ColorModel</code> called the | ||
| 1141 | * <code>super(bits)</code> constructor, but did not | ||
| 1142 | * override this method. See the constructor, | ||
| 1143 | * {@link #ColorModel(int)}. | ||
| 1144 | * @throws UnsupportedOperationException if this method is unable | ||
| 1145 | * to determine the number of bits per component | ||
| 1146 | */ | ||
| 1147 | public float[] getNormalizedComponents(int[] components, int offset, | ||
| 1148 | float[] normComponents, | ||
| 1149 | int normOffset) { | ||
| 1150 | // Make sure that someone isn't using a custom color model | ||
| 1151 | // that called the super(bits) constructor. | ||
| 1152 | if (colorSpace == null) { | ||
| 1153 | throw new UnsupportedOperationException("This method is not supported by "+ | ||
| 1154 | "this color model."); | ||
| 1155 | } | ||
| 1156 | if (nBits == null) { | ||
| 1157 | throw new UnsupportedOperationException ("This method is not supported. "+ | ||
| 1158 | "Unable to determine #bits per "+ | ||
| 1159 | "component."); | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | if ((components.length - offset) < numComponents) { | ||
| 1163 | throw new | ||
| 1164 | IllegalArgumentException( | ||
| 1165 | "Incorrect number of components. Expecting "+ | ||
| 1166 | numComponents); | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | if (normComponents == null) { | ||
| 1170 | normComponents = new float[numComponents+normOffset]; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | if (supportsAlpha && isAlphaPremultiplied) { | ||
| 1174 | // Normalized coordinates are non premultiplied | ||
| 1175 | float normAlpha = (float)components[offset+numColorComponents]; | ||
| 1176 | normAlpha /= (float) ((1<<nBits[numColorComponents]) - 1); | ||
| 1177 | if (normAlpha != 0.0f) { | ||
| 1178 | for (int i=0; i < numColorComponents; i++) { | ||
| 1179 | normComponents[normOffset+i] = | ||
| 1180 | ((float) components[offset+i]) / | ||
| 1181 | (normAlpha * ((float) ((1<<nBits[i]) - 1))); | ||
| 1182 | } | ||
| 1183 | } else { | ||
| 1184 | for (int i=0; i < numColorComponents; i++) { | ||
| 1185 | normComponents[normOffset+i] = 0.0f; | ||
| 1186 | } | ||
| 1187 | } | ||
| 1188 | normComponents[normOffset+numColorComponents] = normAlpha; | ||
| 1189 | } | ||
| 1190 | else { | ||
| 1191 | for (int i=0; i < numComponents; i++) { | ||
| 1192 | normComponents[normOffset+i] = ((float) components[offset+i]) / | ||
| 1193 | ((float) ((1<<nBits[i]) - 1)); | ||
| 1194 | } | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | return normComponents; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | /** | ||
| 1201 | * Returns a pixel value represented as an <code>int</code> in this | ||
| 1202 | * <code>ColorModel</code>, given an array of unnormalized color/alpha | ||
| 1203 | * components. This method will throw an | ||
| 1204 | * <code>IllegalArgumentException</code> if component values for this | ||
| 1205 | * <code>ColorModel</code> are not conveniently representable as a | ||
| 1206 | * single <code>int</code> or if color component values for this | ||
| 1207 | * <code>ColorModel</code> are not conveniently representable in the | ||
| 1208 | * unnormalized form. An | ||
| 1209 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if the | ||
| 1210 | * <code>components</code> array is not large enough to hold all the | ||
| 1211 | * color and alpha components (starting at <code>offset</code>). | ||
| 1212 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1213 | * any instance is an instance of a subclass. Subclasses must | ||
| 1214 | * override this method since the implementation in this abstract | ||
| 1215 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 1216 | * @param components an array of unnormalized color and alpha | ||
| 1217 | * components | ||
| 1218 | * @param offset the index into <code>components</code> at which to | ||
| 1219 | * begin retrieving the color and alpha components | ||
| 1220 | * @return an <code>int</code> pixel value in this | ||
| 1221 | * <code>ColorModel</code> corresponding to the specified components. | ||
| 1222 | * @throws IllegalArgumentException if | ||
| 1223 | * pixel values for this <code>ColorModel</code> are not | ||
| 1224 | * conveniently representable as a single <code>int</code> | ||
| 1225 | * @throws IllegalArgumentException if | ||
| 1226 | * component values for this <code>ColorModel</code> are not | ||
| 1227 | * conveniently representable in the unnormalized form | ||
| 1228 | * @throws ArrayIndexOutOfBoundsException if | ||
| 1229 | * the <code>components</code> array is not large enough to | ||
| 1230 | * hold all of the color and alpha components starting at | ||
| 1231 | * <code>offset</code> | ||
| 1232 | * @throws UnsupportedOperationException if this | ||
| 1233 | * method is not supported by this <code>ColorModel</code> | ||
| 1234 | */ | ||
| 1235 | public int getDataElement(int[] components, int offset) { | ||
| 1236 | throw new UnsupportedOperationException("This method is not supported "+ | ||
| 1237 | "by this color model."); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | /** | ||
| 1241 | * Returns a data element array representation of a pixel in this | ||
| 1242 | * <code>ColorModel</code>, given an array of unnormalized color/alpha | ||
| 1243 | * components. This array can then be passed to the | ||
| 1244 | * <code>setDataElements</code> method of a <code>WritableRaster</code> | ||
| 1245 | * object. This method will throw an <code>IllegalArgumentException</code> | ||
| 1246 | * if color component values for this <code>ColorModel</code> are not | ||
| 1247 | * conveniently representable in the unnormalized form. | ||
| 1248 | * An <code>ArrayIndexOutOfBoundsException</code> is thrown | ||
| 1249 | * if the <code>components</code> array is not large enough to hold | ||
| 1250 | * all the color and alpha components (starting at | ||
| 1251 | * <code>offset</code>). If the <code>obj</code> variable is | ||
| 1252 | * <code>null</code>, a new array will be allocated. If | ||
| 1253 | * <code>obj</code> is not <code>null</code>, it must be a primitive | ||
| 1254 | * array of type transferType; otherwise, a | ||
| 1255 | * <code>ClassCastException</code> is thrown. An | ||
| 1256 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 1257 | * <code>obj</code> is not large enough to hold a pixel value for this | ||
| 1258 | * <code>ColorModel</code>. | ||
| 1259 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1260 | * any instance is an instance of a subclass. Subclasses must | ||
| 1261 | * override this method since the implementation in this abstract | ||
| 1262 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 1263 | * @param components an array of unnormalized color and alpha | ||
| 1264 | * components | ||
| 1265 | * @param offset the index into <code>components</code> at which to | ||
| 1266 | * begin retrieving color and alpha components | ||
| 1267 | * @param obj the <code>Object</code> representing an array of color | ||
| 1268 | * and alpha components | ||
| 1269 | * @return an <code>Object</code> representing an array of color and | ||
| 1270 | * alpha components. | ||
| 1271 | * @throws ClassCastException if <code>obj</code> | ||
| 1272 | * is not a primitive array of type <code>transferType</code> | ||
| 1273 | * @throws ArrayIndexOutOfBoundsException if | ||
| 1274 | * <code>obj</code> is not large enough to hold a pixel value | ||
| 1275 | * for this <code>ColorModel</code> or the <code>components</code> | ||
| 1276 | * array is not large enough to hold all of the color and alpha | ||
| 1277 | * components starting at <code>offset</code> | ||
| 1278 | * @throws IllegalArgumentException if | ||
| 1279 | * component values for this <code>ColorModel</code> are not | ||
| 1280 | * conveniently representable in the unnormalized form | ||
| 1281 | * @throws UnsupportedOperationException if this | ||
| 1282 | * method is not supported by this <code>ColorModel</code> | ||
| 1283 | * @see WritableRaster#setDataElements | ||
| 1284 | * @see SampleModel#setDataElements | ||
| 1285 | */ | ||
| 1286 | public Object getDataElements(int[] components, int offset, Object obj) { | ||
| 1287 | throw new UnsupportedOperationException("This method has not been implemented "+ | ||
| 1288 | "for this color model."); | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | /** | ||
| 1292 | * Returns a pixel value represented as an <code>int</code> in this | ||
| 1293 | * <code>ColorModel</code>, given an array of normalized color/alpha | ||
| 1294 | * components. This method will throw an | ||
| 1295 | * <code>IllegalArgumentException</code> if pixel values for this | ||
| 1296 | * <code>ColorModel</code> are not conveniently representable as a | ||
| 1297 | * single <code>int</code>. An | ||
| 1298 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if the | ||
| 1299 | * <code>normComponents</code> array is not large enough to hold all the | ||
| 1300 | * color and alpha components (starting at <code>normOffset</code>). | ||
| 1301 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1302 | * any instance is an instance of a subclass. The default implementation | ||
| 1303 | * of this method in this abstract class first converts from the | ||
| 1304 | * normalized form to the unnormalized form and then calls | ||
| 1305 | * <code>getDataElement(int[], int)</code>. Subclasses which may | ||
| 1306 | * have instances which do not support the unnormalized form must | ||
| 1307 | * override this method. | ||
| 1308 | * @param normComponents an array of normalized color and alpha | ||
| 1309 | * components | ||
| 1310 | * @param normOffset the index into <code>normComponents</code> at which to | ||
| 1311 | * begin retrieving the color and alpha components | ||
| 1312 | * @return an <code>int</code> pixel value in this | ||
| 1313 | * <code>ColorModel</code> corresponding to the specified components. | ||
| 1314 | * @throws IllegalArgumentException if | ||
| 1315 | * pixel values for this <code>ColorModel</code> are not | ||
| 1316 | * conveniently representable as a single <code>int</code> | ||
| 1317 | * @throws ArrayIndexOutOfBoundsException if | ||
| 1318 | * the <code>normComponents</code> array is not large enough to | ||
| 1319 | * hold all of the color and alpha components starting at | ||
| 1320 | * <code>normOffset</code> | ||
| 1321 | * @since 1.4 | ||
| 1322 | */ | ||
| 1323 | public int getDataElement(float[] normComponents, int normOffset) { | ||
| 1324 | int components[] = getUnnormalizedComponents(normComponents, | ||
| 1325 | normOffset, null, 0); | ||
| 1326 | return getDataElement(components, 0); | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | /** | ||
| 1330 | * Returns a data element array representation of a pixel in this | ||
| 1331 | * <code>ColorModel</code>, given an array of normalized color/alpha | ||
| 1332 | * components. This array can then be passed to the | ||
| 1333 | * <code>setDataElements</code> method of a <code>WritableRaster</code> | ||
| 1334 | * object. An <code>ArrayIndexOutOfBoundsException</code> is thrown | ||
| 1335 | * if the <code>normComponents</code> array is not large enough to hold | ||
| 1336 | * all the color and alpha components (starting at | ||
| 1337 | * <code>normOffset</code>). If the <code>obj</code> variable is | ||
| 1338 | * <code>null</code>, a new array will be allocated. If | ||
| 1339 | * <code>obj</code> is not <code>null</code>, it must be a primitive | ||
| 1340 | * array of type transferType; otherwise, a | ||
| 1341 | * <code>ClassCastException</code> is thrown. An | ||
| 1342 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 1343 | * <code>obj</code> is not large enough to hold a pixel value for this | ||
| 1344 | * <code>ColorModel</code>. | ||
| 1345 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1346 | * any instance is an instance of a subclass. The default implementation | ||
| 1347 | * of this method in this abstract class first converts from the | ||
| 1348 | * normalized form to the unnormalized form and then calls | ||
| 1349 | * <code>getDataElement(int[], int, Object)</code>. Subclasses which may | ||
| 1350 | * have instances which do not support the unnormalized form must | ||
| 1351 | * override this method. | ||
| 1352 | * @param normComponents an array of normalized color and alpha | ||
| 1353 | * components | ||
| 1354 | * @param normOffset the index into <code>normComponents</code> at which to | ||
| 1355 | * begin retrieving color and alpha components | ||
| 1356 | * @param obj a primitive data array to hold the returned pixel | ||
| 1357 | * @return an <code>Object</code> which is a primitive data array | ||
| 1358 | * representation of a pixel | ||
| 1359 | * @throws ClassCastException if <code>obj</code> | ||
| 1360 | * is not a primitive array of type <code>transferType</code> | ||
| 1361 | * @throws ArrayIndexOutOfBoundsException if | ||
| 1362 | * <code>obj</code> is not large enough to hold a pixel value | ||
| 1363 | * for this <code>ColorModel</code> or the <code>normComponents</code> | ||
| 1364 | * array is not large enough to hold all of the color and alpha | ||
| 1365 | * components starting at <code>normOffset</code> | ||
| 1366 | * @see WritableRaster#setDataElements | ||
| 1367 | * @see SampleModel#setDataElements | ||
| 1368 | * @since 1.4 | ||
| 1369 | */ | ||
| 1370 | public Object getDataElements(float[] normComponents, int normOffset, | ||
| 1371 | Object obj) { | ||
| 1372 | int components[] = getUnnormalizedComponents(normComponents, | ||
| 1373 | normOffset, null, 0); | ||
| 1374 | return getDataElements(components, 0, obj); | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | /** | ||
| 1378 | * Returns an array of all of the color/alpha components in normalized | ||
| 1379 | * form, given a pixel in this <code>ColorModel</code>. The pixel | ||
| 1380 | * value is specified by an array of data elements of type transferType | ||
| 1381 | * passed in as an object reference. If pixel is not a primitive array | ||
| 1382 | * of type transferType, a <code>ClassCastException</code> is thrown. | ||
| 1383 | * An <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 1384 | * <code>pixel</code> is not large enough to hold a pixel value for this | ||
| 1385 | * <code>ColorModel</code>. | ||
| 1386 | * Normalized components are float values between a per component minimum | ||
| 1387 | * and maximum specified by the <code>ColorSpace</code> object for this | ||
| 1388 | * <code>ColorModel</code>. If the | ||
| 1389 | * <code>normComponents</code> array is <code>null</code>, a new array | ||
| 1390 | * will be allocated. The <code>normComponents</code> array | ||
| 1391 | * will be returned. Color/alpha components are stored in the | ||
| 1392 | * <code>normComponents</code> array starting at | ||
| 1393 | * <code>normOffset</code> (even if the array is allocated by this | ||
| 1394 | * method). An <code>ArrayIndexOutOfBoundsException</code> is thrown | ||
| 1395 | * if the <code>normComponents</code> array is not <code>null</code> | ||
| 1396 | * and is not large enough to hold all the color and alpha components | ||
| 1397 | * (starting at <code>normOffset</code>). | ||
| 1398 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1399 | * any instance is an instance of a subclass. The default implementation | ||
| 1400 | * of this method in this abstract class first retrieves color and alpha | ||
| 1401 | * components in the unnormalized form using | ||
| 1402 | * <code>getComponents(Object, int[], int)</code> and then calls | ||
| 1403 | * <code>getNormalizedComponents(int[], int, float[], int)</code>. | ||
| 1404 | * Subclasses which may | ||
| 1405 | * have instances which do not support the unnormalized form must | ||
| 1406 | * override this method. | ||
| 1407 | * @param pixel the specified pixel | ||
| 1408 | * @param normComponents an array to receive the normalized components | ||
| 1409 | * @param normOffset the offset into the <code>normComponents</code> | ||
| 1410 | * array at which to start storing normalized components | ||
| 1411 | * @return an array containing normalized color and alpha | ||
| 1412 | * components. | ||
| 1413 | * @throws ClassCastException if <code>pixel</code> is not a primitive | ||
| 1414 | * array of type transferType | ||
| 1415 | * @throws ArrayIndexOutOfBoundsException if | ||
| 1416 | * <code>normComponents</code> is not large enough to hold all | ||
| 1417 | * color and alpha components starting at <code>normOffset</code> | ||
| 1418 | * @throws ArrayIndexOutOfBoundsException if | ||
| 1419 | * <code>pixel</code> is not large enough to hold a pixel | ||
| 1420 | * value for this <code>ColorModel</code>. | ||
| 1421 | * @throws UnsupportedOperationException if the | ||
| 1422 | * constructor of this <code>ColorModel</code> called the | ||
| 1423 | * <code>super(bits)</code> constructor, but did not | ||
| 1424 | * override this method. See the constructor, | ||
| 1425 | * {@link #ColorModel(int)}. | ||
| 1426 | * @throws UnsupportedOperationException if this method is unable | ||
| 1427 | * to determine the number of bits per component | ||
| 1428 | * @since 1.4 | ||
| 1429 | */ | ||
| 1430 | public float[] getNormalizedComponents(Object pixel, | ||
| 1431 | float[] normComponents, | ||
| 1432 | int normOffset) { | ||
| 1433 | int components[] = getComponents(pixel, null, 0); | ||
| 1434 | return getNormalizedComponents(components, 0, | ||
| 1435 | normComponents, normOffset); | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | /** | ||
| 1439 | * Tests if the specified <code>Object</code> is an instance of | ||
| 1440 | * <code>ColorModel</code> and if it equals this | ||
| 1441 | * <code>ColorModel</code>. | ||
| 1442 | * @param obj the <code>Object</code> to test for equality | ||
| 1443 | * @return <code>true</code> if the specified <code>Object</code> | ||
| 1444 | * is an instance of <code>ColorModel</code> and equals this | ||
| 1445 | * <code>ColorModel</code>; <code>false</code> otherwise. | ||
| 1446 | */ | ||
| 1447 | public boolean equals(Object obj) { | ||
| 1448 | if (!(obj instanceof ColorModel)) { | ||
| 1449 | return false; | ||
| 1450 | } | ||
| 1451 | ColorModel cm = (ColorModel) obj; | ||
| 1452 | |||
| 1453 | if (this == cm) { | ||
| 1454 | return true; | ||
| 1455 | } | ||
| 1456 | if (supportsAlpha != cm.hasAlpha() || | ||
| 1457 | isAlphaPremultiplied != cm.isAlphaPremultiplied() || | ||
| 1458 | pixel_bits != cm.getPixelSize() || | ||
| 1459 | transparency != cm.getTransparency() || | ||
| 1460 | numComponents != cm.getNumComponents()) | ||
| 1461 | { | ||
| 1462 | return false; | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | int[] nb = cm.getComponentSize(); | ||
| 1466 | |||
| 1467 | if ((nBits != null) && (nb != null)) { | ||
| 1468 | for (int i = 0; i < numComponents; i++) { | ||
| 1469 | if (nBits[i] != nb[i]) { | ||
| 1470 | return false; | ||
| 1471 | } | ||
| 1472 | } | ||
| 1473 | } else { | ||
| 1474 | return ((nBits == null) && (nb == null)); | ||
| 1475 | } | ||
| 1476 | |||
| 1477 | return true; | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | /** | ||
| 1481 | * Returns the hash code for this ColorModel. | ||
| 1482 | * | ||
| 1483 | * @return a hash code for this ColorModel. | ||
| 1484 | */ | ||
| 1485 | public int hashCode() { | ||
| 1486 | |||
| 1487 | int result = 0; | ||
| 1488 | |||
| 1489 | result = (supportsAlpha ? 2 : 3) + | ||
| 1490 | (isAlphaPremultiplied ? 4 : 5) + | ||
| 1491 | pixel_bits * 6 + | ||
| 1492 | transparency * 7 + | ||
| 1493 | numComponents * 8; | ||
| 1494 | |||
| 1495 | if (nBits != null) { | ||
| 1496 | for (int i = 0; i < numComponents; i++) { | ||
| 1497 | result = result + nBits[i] * (i + 9); | ||
| 1498 | } | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | return result; | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | /** | ||
| 1505 | * Returns the <code>ColorSpace</code> associated with this | ||
| 1506 | * <code>ColorModel</code>. | ||
| 1507 | * @return the <code>ColorSpace</code> of this | ||
| 1508 | * <code>ColorModel</code>. | ||
| 1509 | */ | ||
| 1510 | final public ColorSpace getColorSpace() { | ||
| 1511 | return colorSpace; | ||
| 1512 | } | ||
| 1513 | |||
| 1514 | /** | ||
| 1515 | * Forces the raster data to match the state specified in the | ||
| 1516 | * <code>isAlphaPremultiplied</code> variable, assuming the data is | ||
| 1517 | * currently correctly described by this <code>ColorModel</code>. It | ||
| 1518 | * may multiply or divide the color raster data by alpha, or do | ||
| 1519 | * nothing if the data is in the correct state. If the data needs to | ||
| 1520 | * be coerced, this method will also return an instance of this | ||
| 1521 | * <code>ColorModel</code> with the <code>isAlphaPremultiplied</code> | ||
| 1522 | * flag set appropriately. This method will throw a | ||
| 1523 | * <code>UnsupportedOperationException</code> if it is not supported | ||
| 1524 | * by this <code>ColorModel</code>. | ||
| 1525 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1526 | * any instance is an instance of a subclass. Subclasses must | ||
| 1527 | * override this method since the implementation in this abstract | ||
| 1528 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 1529 | * @param raster the <code>WritableRaster</code> data | ||
| 1530 | * @param isAlphaPremultiplied <code>true</code> if the alpha is | ||
| 1531 | * premultiplied; <code>false</code> otherwise | ||
| 1532 | * @return a <code>ColorModel</code> object that represents the | ||
| 1533 | * coerced data. | ||
| 1534 | */ | ||
| 1535 | public ColorModel coerceData (WritableRaster raster, | ||
| 1536 | boolean isAlphaPremultiplied) { | ||
| 1537 | throw new UnsupportedOperationException | ||
| 1538 | ("This method is not supported by this color model"); | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | /** | ||
| 1542 | * Returns <code>true</code> if <code>raster</code> is compatible | ||
| 1543 | * with this <code>ColorModel</code> and <code>false</code> if it is | ||
| 1544 | * not. | ||
| 1545 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1546 | * any instance is an instance of a subclass. Subclasses must | ||
| 1547 | * override this method since the implementation in this abstract | ||
| 1548 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 1549 | * @param raster the {@link Raster} object to test for compatibility | ||
| 1550 | * @return <code>true</code> if <code>raster</code> is compatible | ||
| 1551 | * with this <code>ColorModel</code>. | ||
| 1552 | * @throws UnsupportedOperationException if this | ||
| 1553 | * method has not been implemented for this | ||
| 1554 | * <code>ColorModel</code> | ||
| 1555 | */ | ||
| 1556 | public boolean isCompatibleRaster(Raster raster) { | ||
| 1557 | throw new UnsupportedOperationException( | ||
| 1558 | "This method has not been implemented for this ColorModel."); | ||
| 1559 | } | ||
| 1560 | |||
| 1561 | /** | ||
| 1562 | * Creates a <code>WritableRaster</code> with the specified width and | ||
| 1563 | * height that has a data layout (<code>SampleModel</code>) compatible | ||
| 1564 | * with this <code>ColorModel</code>. | ||
| 1565 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1566 | * any instance is an instance of a subclass. Subclasses must | ||
| 1567 | * override this method since the implementation in this abstract | ||
| 1568 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 1569 | * @param w the width to apply to the new <code>WritableRaster</code> | ||
| 1570 | * @param h the height to apply to the new <code>WritableRaster</code> | ||
| 1571 | * @return a <code>WritableRaster</code> object with the specified | ||
| 1572 | * width and height. | ||
| 1573 | * @throws UnsupportedOperationException if this | ||
| 1574 | * method is not supported by this <code>ColorModel</code> | ||
| 1575 | * @see WritableRaster | ||
| 1576 | * @see SampleModel | ||
| 1577 | */ | ||
| 1578 | public WritableRaster createCompatibleWritableRaster(int w, int h) { | ||
| 1579 | throw new UnsupportedOperationException | ||
| 1580 | ("This method is not supported by this color model"); | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | /** | ||
| 1584 | * Creates a <code>SampleModel</code> with the specified width and | ||
| 1585 | * height that has a data layout compatible with this | ||
| 1586 | * <code>ColorModel</code>. | ||
| 1587 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1588 | * any instance is an instance of a subclass. Subclasses must | ||
| 1589 | * override this method since the implementation in this abstract | ||
| 1590 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 1591 | * @param w the width to apply to the new <code>SampleModel</code> | ||
| 1592 | * @param h the height to apply to the new <code>SampleModel</code> | ||
| 1593 | * @return a <code>SampleModel</code> object with the specified | ||
| 1594 | * width and height. | ||
| 1595 | * @throws UnsupportedOperationException if this | ||
| 1596 | * method is not supported by this <code>ColorModel</code> | ||
| 1597 | * @see SampleModel | ||
| 1598 | */ | ||
| 1599 | public SampleModel createCompatibleSampleModel(int w, int h) { | ||
| 1600 | throw new UnsupportedOperationException | ||
| 1601 | ("This method is not supported by this color model"); | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | /** Checks if the <code>SampleModel</code> is compatible with this | ||
| 1605 | * <code>ColorModel</code>. | ||
| 1606 | * Since <code>ColorModel</code> is an abstract class, | ||
| 1607 | * any instance is an instance of a subclass. Subclasses must | ||
| 1608 | * override this method since the implementation in this abstract | ||
| 1609 | * class throws an <code>UnsupportedOperationException</code>. | ||
| 1610 | * @param sm the specified <code>SampleModel</code> | ||
| 1611 | * @return <code>true</code> if the specified <code>SampleModel</code> | ||
| 1612 | * is compatible with this <code>ColorModel</code>; <code>false</code> | ||
| 1613 | * otherwise. | ||
| 1614 | * @throws UnsupportedOperationException if this | ||
| 1615 | * method is not supported by this <code>ColorModel</code> | ||
| 1616 | * @see SampleModel | ||
| 1617 | */ | ||
| 1618 | public boolean isCompatibleSampleModel(SampleModel sm) { | ||
| 1619 | throw new UnsupportedOperationException | ||
| 1620 | ("This method is not supported by this color model"); | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | /** | ||
| 1624 | * Disposes of system resources associated with this | ||
| 1625 | * <code>ColorModel</code> once this <code>ColorModel</code> is no | ||
| 1626 | * longer referenced. | ||
| 1627 | */ | ||
| 1628 | public void finalize() { | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | |||
| 1632 | /** | ||
| 1633 | * Returns a <code>Raster</code> representing the alpha channel of an | ||
| 1634 | * image, extracted from the input <code>Raster</code>, provided that | ||
| 1635 | * pixel values of this <code>ColorModel</code> represent color and | ||
| 1636 | * alpha information as separate spatial bands (e.g. | ||
| 1637 | * {@link ComponentColorModel} and <code>DirectColorModel</code>). | ||
| 1638 | * This method assumes that <code>Raster</code> objects associated | ||
| 1639 | * with such a <code>ColorModel</code> store the alpha band, if | ||
| 1640 | * present, as the last band of image data. Returns <code>null</code> | ||
| 1641 | * if there is no separate spatial alpha channel associated with this | ||
| 1642 | * <code>ColorModel</code>. If this is an | ||
| 1643 | * <code>IndexColorModel</code> which has alpha in the lookup table, | ||
| 1644 | * this method will return <code>null</code> since | ||
| 1645 | * there is no spatially discrete alpha channel. | ||
| 1646 | * This method will create a new <code>Raster</code> (but will share | ||
| 1647 | * the data array). | ||
| 1648 | * Since <code>ColorModel</code> is an abstract class, any instance | ||
| 1649 | * is an instance of a subclass. Subclasses must override this | ||
| 1650 | * method to get any behavior other than returning <code>null</code> | ||
| 1651 | * because the implementation in this abstract class returns | ||
| 1652 | * <code>null</code>. | ||
| 1653 | * @param raster the specified <code>Raster</code> | ||
| 1654 | * @return a <code>Raster</code> representing the alpha channel of | ||
| 1655 | * an image, obtained from the specified <code>Raster</code>. | ||
| 1656 | */ | ||
| 1657 | public WritableRaster getAlphaRaster(WritableRaster raster) { | ||
| 1658 | return null; | ||
| 1659 | } | ||
| 1660 | |||
| 1661 | /** | ||
| 1662 | * Returns the <code>String</code> representation of the contents of | ||
| 1663 | * this <code>ColorModel</code>object. | ||
| 1664 | * @return a <code>String</code> representing the contents of this | ||
| 1665 | * <code>ColorModel</code> object. | ||
| 1666 | */ | ||
| 1667 | public String toString() { | ||
| 1668 | return new String("ColorModel: #pixelBits = "+pixel_bits | ||
| 1669 | + " numComponents = "+numComponents | ||
| 1670 | + " color space = "+colorSpace | ||
| 1671 | + " transparency = "+transparency | ||
| 1672 | + " has alpha = "+supportsAlpha | ||
| 1673 | + " isAlphaPre = "+isAlphaPremultiplied | ||
| 1674 | ); | ||
| 1675 | } | ||
| 1676 | |||
| 1677 | static int getDefaultTransferType(int pixel_bits) { | ||
| 1678 | if (pixel_bits <= 8) { | ||
| 1679 | return DataBuffer.TYPE_BYTE; | ||
| 1680 | } else if (pixel_bits <= 16) { | ||
| 1681 | return DataBuffer.TYPE_USHORT; | ||
| 1682 | } else if (pixel_bits <= 32) { | ||
| 1683 | return DataBuffer.TYPE_INT; | ||
| 1684 | } else { | ||
| 1685 | return DataBuffer.TYPE_UNDEFINED; | ||
| 1686 | } | ||
| 1687 | } | ||
| 1688 | |||
| 1689 | static byte[] l8Tos8 = null; // 8-bit linear to 8-bit non-linear sRGB LUT | ||
| 1690 | static byte[] s8Tol8 = null; // 8-bit non-linear sRGB to 8-bit linear LUT | ||
| 1691 | static byte[] l16Tos8 = null; // 16-bit linear to 8-bit non-linear sRGB LUT | ||
| 1692 | static short[] s8Tol16 = null; // 8-bit non-linear sRGB to 16-bit linear LUT | ||
| 1693 | |||
| 1694 | // Maps to hold LUTs for grayscale conversions | ||
| 1695 | static Map g8Tos8Map = null; // 8-bit gray values to 8-bit sRGB values | ||
| 1696 | static Map lg16Toog8Map = null; // 16-bit linear to 8-bit "other" gray | ||
| 1697 | static Map g16Tos8Map = null; // 16-bit gray values to 8-bit sRGB values | ||
| 1698 | static Map lg16Toog16Map = null; // 16-bit linear to 16-bit "other" gray | ||
| 1699 | |||
| 1700 | static boolean isLinearRGBspace(ColorSpace cs) { | ||
| 1701 | // Note: CMM.LINEAR_RGBspace will be null if the linear | ||
| 1702 | // RGB space has not been created yet. | ||
| 1703 | return (cs == CMSManager.LINEAR_RGBspace); | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | static boolean isLinearGRAYspace(ColorSpace cs) { | ||
| 1707 | // Note: CMM.GRAYspace will be null if the linear | ||
| 1708 | // gray space has not been created yet. | ||
| 1709 | return (cs == CMSManager.GRAYspace); | ||
| 1710 | } | ||
| 1711 | |||
| 1712 | static byte[] getLinearRGB8TosRGB8LUT() { | ||
| 1713 | if (l8Tos8 == null) { | ||
| 1714 | l8Tos8 = new byte[256]; | ||
| 1715 | float input, output; | ||
| 1716 | // algorithm for linear RGB to nonlinear sRGB conversion | ||
| 1717 | // is from the IEC 61966-2-1 International Standard, | ||
| 1718 | // Colour Management - Default RGB colour space - sRGB, | ||
| 1719 | // First Edition, 1999-10, | ||
| 1720 | // avaiable for order at http://www.iec.ch | ||
| 1721 | for (int i = 0; i <= 255; i++) { | ||
| 1722 | input = ((float) i) / 255.0f; | ||
| 1723 | if (input <= 0.0031308f) { | ||
| 1724 | output = input * 12.92f; | ||
| 1725 | } else { | ||
| 1726 | output = 1.055f * ((float) Math.pow(input, (1.0 / 2.4))) | ||
| 1727 | - 0.055f; | ||
| 1728 | } | ||
| 1729 | l8Tos8[i] = (byte) Math.round(output * 255.0f); | ||
| 1730 | } | ||
| 1731 | } | ||
| 1732 | return l8Tos8; | ||
| 1733 | } | ||
| 1734 | |||
| 1735 | static byte[] getsRGB8ToLinearRGB8LUT() { | ||
| 1736 | if (s8Tol8 == null) { | ||
| 1737 | s8Tol8 = new byte[256]; | ||
| 1738 | float input, output; | ||
| 1739 | // algorithm from IEC 61966-2-1 International Standard | ||
| 1740 | for (int i = 0; i <= 255; i++) { | ||
| 1741 | input = ((float) i) / 255.0f; | ||
| 1742 | if (input <= 0.04045f) { | ||
| 1743 | output = input / 12.92f; | ||
| 1744 | } else { | ||
| 1745 | output = (float) Math.pow((input + 0.055f) / 1.055f, 2.4); | ||
| 1746 | } | ||
| 1747 | s8Tol8[i] = (byte) Math.round(output * 255.0f); | ||
| 1748 | } | ||
| 1749 | } | ||
| 1750 | return s8Tol8; | ||
| 1751 | } | ||
| 1752 | |||
| 1753 | static byte[] getLinearRGB16TosRGB8LUT() { | ||
| 1754 | if (l16Tos8 == null) { | ||
| 1755 | l16Tos8 = new byte[65536]; | ||
| 1756 | float input, output; | ||
| 1757 | // algorithm from IEC 61966-2-1 International Standard | ||
| 1758 | for (int i = 0; i <= 65535; i++) { | ||
| 1759 | input = ((float) i) / 65535.0f; | ||
| 1760 | if (input <= 0.0031308f) { | ||
| 1761 | output = input * 12.92f; | ||
| 1762 | } else { | ||
| 1763 | output = 1.055f * ((float) Math.pow(input, (1.0 / 2.4))) | ||
| 1764 | - 0.055f; | ||
| 1765 | } | ||
| 1766 | l16Tos8[i] = (byte) Math.round(output * 255.0f); | ||
| 1767 | } | ||
| 1768 | } | ||
| 1769 | return l16Tos8; | ||
| 1770 | } | ||
| 1771 | |||
| 1772 | static short[] getsRGB8ToLinearRGB16LUT() { | ||
| 1773 | if (s8Tol16 == null) { | ||
| 1774 | s8Tol16 = new short[256]; | ||
| 1775 | float input, output; | ||
| 1776 | // algorithm from IEC 61966-2-1 International Standard | ||
| 1777 | for (int i = 0; i <= 255; i++) { | ||
| 1778 | input = ((float) i) / 255.0f; | ||
| 1779 | if (input <= 0.04045f) { | ||
| 1780 | output = input / 12.92f; | ||
| 1781 | } else { | ||
| 1782 | output = (float) Math.pow((input + 0.055f) / 1.055f, 2.4); | ||
| 1783 | } | ||
| 1784 | s8Tol16[i] = (short) Math.round(output * 65535.0f); | ||
| 1785 | } | ||
| 1786 | } | ||
| 1787 | return s8Tol16; | ||
| 1788 | } | ||
| 1789 | |||
| 1790 | /* | ||
| 1791 | * Return a byte LUT that converts 8-bit gray values in the grayCS | ||
| 1792 | * ColorSpace to the appropriate 8-bit sRGB value. I.e., if lut | ||
| 1793 | * is the byte array returned by this method and sval = lut[gval], | ||
| 1794 | * then the sRGB triple (sval,sval,sval) is the best match to gval. | ||
| 1795 | * Cache references to any computed LUT in a Map. | ||
| 1796 | */ | ||
| 1797 | static byte[] getGray8TosRGB8LUT(ICC_ColorSpace grayCS) { | ||
| 1798 | if (isLinearGRAYspace(grayCS)) { | ||
| 1799 | return getLinearRGB8TosRGB8LUT(); | ||
| 1800 | } | ||
| 1801 | if (g8Tos8Map != null) { | ||
| 1802 | byte[] g8Tos8LUT = (byte []) g8Tos8Map.get(grayCS); | ||
| 1803 | if (g8Tos8LUT != null) { | ||
| 1804 | return g8Tos8LUT; | ||
| 1805 | } | ||
| 1806 | } | ||
| 1807 | byte[] g8Tos8LUT = new byte[256]; | ||
| 1808 | for (int i = 0; i <= 255; i++) { | ||
| 1809 | g8Tos8LUT[i] = (byte) i; | ||
| 1810 | } | ||
| 1811 | ColorTransform[] transformList = new ColorTransform[2]; | ||
| 1812 | PCMM mdl = CMSManager.getModule(); | ||
| 1813 | ICC_ColorSpace srgbCS = | ||
| 1814 | (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB); | ||
| 1815 | transformList[0] = mdl.createTransform( | ||
| 1816 | grayCS.getProfile(), ColorTransform.Any, ColorTransform.In); | ||
| 1817 | transformList[1] = mdl.createTransform( | ||
| 1818 | srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out); | ||
| 1819 | ColorTransform t = mdl.createTransform(transformList); | ||
| 1820 | byte[] tmp = t.colorConvert(g8Tos8LUT, null); | ||
| 1821 | for (int i = 0, j= 2; i <= 255; i++, j += 3) { | ||
| 1822 | // All three components of tmp should be equal, since | ||
| 1823 | // the input color space to colorConvert is a gray scale | ||
| 1824 | // space. However, there are slight anomalies in the results. | ||
| 1825 | // Copy tmp starting at index 2, since colorConvert seems | ||
| 1826 | // to be slightly more accurate for the third component! | ||
| 1827 | g8Tos8LUT[i] = tmp[j]; | ||
| 1828 | } | ||
| 1829 | if (g8Tos8Map == null) { | ||
| 1830 | g8Tos8Map = Collections.synchronizedMap(new WeakHashMap(2)); | ||
| 1831 | } | ||
| 1832 | g8Tos8Map.put(grayCS, g8Tos8LUT); | ||
| 1833 | return g8Tos8LUT; | ||
| 1834 | } | ||
| 1835 | |||
| 1836 | /* | ||
| 1837 | * Return a byte LUT that converts 16-bit gray values in the CS_GRAY | ||
| 1838 | * linear gray ColorSpace to the appropriate 8-bit value in the | ||
| 1839 | * grayCS ColorSpace. Cache references to any computed LUT in a Map. | ||
| 1840 | */ | ||
| 1841 | static byte[] getLinearGray16ToOtherGray8LUT(ICC_ColorSpace grayCS) { | ||
| 1842 | if (lg16Toog8Map != null) { | ||
| 1843 | byte[] lg16Toog8LUT = (byte []) lg16Toog8Map.get(grayCS); | ||
| 1844 | if (lg16Toog8LUT != null) { | ||
| 1845 | return lg16Toog8LUT; | ||
| 1846 | } | ||
| 1847 | } | ||
| 1848 | short[] tmp = new short[65536]; | ||
| 1849 | for (int i = 0; i <= 65535; i++) { | ||
| 1850 | tmp[i] = (short) i; | ||
| 1851 | } | ||
| 1852 | ColorTransform[] transformList = new ColorTransform[2]; | ||
| 1853 | PCMM mdl = CMSManager.getModule(); | ||
| 1854 | ICC_ColorSpace lgCS = | ||
| 1855 | (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_GRAY); | ||
| 1856 | transformList[0] = mdl.createTransform ( | ||
| 1857 | lgCS.getProfile(), ColorTransform.Any, ColorTransform.In); | ||
| 1858 | transformList[1] = mdl.createTransform ( | ||
| 1859 | grayCS.getProfile(), ColorTransform.Any, ColorTransform.Out); | ||
| 1860 | ColorTransform t = mdl.createTransform(transformList); | ||
| 1861 | tmp = t.colorConvert(tmp, null); | ||
| 1862 | byte[] lg16Toog8LUT = new byte[65536]; | ||
| 1863 | for (int i = 0; i <= 65535; i++) { | ||
| 1864 | // scale unsigned short (0 - 65535) to unsigned byte (0 - 255) | ||
| 1865 | lg16Toog8LUT[i] = | ||
| 1866 | (byte) (((float) (tmp[i] & 0xffff)) * (1.0f /257.0f) + 0.5f); | ||
| 1867 | } | ||
| 1868 | if (lg16Toog8Map == null) { | ||
| 1869 | lg16Toog8Map = Collections.synchronizedMap(new WeakHashMap(2)); | ||
| 1870 | } | ||
| 1871 | lg16Toog8Map.put(grayCS, lg16Toog8LUT); | ||
| 1872 | return lg16Toog8LUT; | ||
| 1873 | } | ||
| 1874 | |||
| 1875 | /* | ||
| 1876 | * Return a byte LUT that converts 16-bit gray values in the grayCS | ||
| 1877 | * ColorSpace to the appropriate 8-bit sRGB value. I.e., if lut | ||
| 1878 | * is the byte array returned by this method and sval = lut[gval], | ||
| 1879 | * then the sRGB triple (sval,sval,sval) is the best match to gval. | ||
| 1880 | * Cache references to any computed LUT in a Map. | ||
| 1881 | */ | ||
| 1882 | static byte[] getGray16TosRGB8LUT(ICC_ColorSpace grayCS) { | ||
| 1883 | if (isLinearGRAYspace(grayCS)) { | ||
| 1884 | return getLinearRGB16TosRGB8LUT(); | ||
| 1885 | } | ||
| 1886 | if (g16Tos8Map != null) { | ||
| 1887 | byte[] g16Tos8LUT = (byte []) g16Tos8Map.get(grayCS); | ||
| 1888 | if (g16Tos8LUT != null) { | ||
| 1889 | return g16Tos8LUT; | ||
| 1890 | } | ||
| 1891 | } | ||
| 1892 | short[] tmp = new short[65536]; | ||
| 1893 | for (int i = 0; i <= 65535; i++) { | ||
| 1894 | tmp[i] = (short) i; | ||
| 1895 | } | ||
| 1896 | ColorTransform[] transformList = new ColorTransform[2]; | ||
| 1897 | PCMM mdl = CMSManager.getModule(); | ||
| 1898 | ICC_ColorSpace srgbCS = | ||
| 1899 | (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB); | ||
| 1900 | transformList[0] = mdl.createTransform ( | ||
| 1901 | grayCS.getProfile(), ColorTransform.Any, ColorTransform.In); | ||
| 1902 | transformList[1] = mdl.createTransform ( | ||
| 1903 | srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out); | ||
| 1904 | ColorTransform t = mdl.createTransform(transformList); | ||
| 1905 | tmp = t.colorConvert(tmp, null); | ||
| 1906 | byte[] g16Tos8LUT = new byte[65536]; | ||
| 1907 | for (int i = 0, j= 2; i <= 65535; i++, j += 3) { | ||
| 1908 | // All three components of tmp should be equal, since | ||
| 1909 | // the input color space to colorConvert is a gray scale | ||
| 1910 | // space. However, there are slight anomalies in the results. | ||
| 1911 | // Copy tmp starting at index 2, since colorConvert seems | ||
| 1912 | // to be slightly more accurate for the third component! | ||
| 1913 | |||
| 1914 | // scale unsigned short (0 - 65535) to unsigned byte (0 - 255) | ||
| 1915 | g16Tos8LUT[i] = | ||
| 1916 | (byte) (((float) (tmp[j] & 0xffff)) * (1.0f /257.0f) + 0.5f); | ||
| 1917 | } | ||
| 1918 | if (g16Tos8Map == null) { | ||
| 1919 | g16Tos8Map = Collections.synchronizedMap(new WeakHashMap(2)); | ||
| 1920 | } | ||
| 1921 | g16Tos8Map.put(grayCS, g16Tos8LUT); | ||
| 1922 | return g16Tos8LUT; | ||
| 1923 | } | ||
| 1924 | |||
| 1925 | /* | ||
| 1926 | * Return a short LUT that converts 16-bit gray values in the CS_GRAY | ||
| 1927 | * linear gray ColorSpace to the appropriate 16-bit value in the | ||
| 1928 | * grayCS ColorSpace. Cache references to any computed LUT in a Map. | ||
| 1929 | */ | ||
| 1930 | static short[] getLinearGray16ToOtherGray16LUT(ICC_ColorSpace grayCS) { | ||
| 1931 | if (lg16Toog16Map != null) { | ||
| 1932 | short[] lg16Toog16LUT = (short []) lg16Toog16Map.get(grayCS); | ||
| 1933 | if (lg16Toog16LUT != null) { | ||
| 1934 | return lg16Toog16LUT; | ||
| 1935 | } | ||
| 1936 | } | ||
| 1937 | short[] tmp = new short[65536]; | ||
| 1938 | for (int i = 0; i <= 65535; i++) { | ||
| 1939 | tmp[i] = (short) i; | ||
| 1940 | } | ||
| 1941 | ColorTransform[] transformList = new ColorTransform[2]; | ||
| 1942 | PCMM mdl = CMSManager.getModule(); | ||
| 1943 | ICC_ColorSpace lgCS = | ||
| 1944 | (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_GRAY); | ||
| 1945 | transformList[0] = mdl.createTransform ( | ||
| 1946 | lgCS.getProfile(), ColorTransform.Any, ColorTransform.In); | ||
| 1947 | transformList[1] = mdl.createTransform( | ||
| 1948 | grayCS.getProfile(), ColorTransform.Any, ColorTransform.Out); | ||
| 1949 | ColorTransform t = mdl.createTransform( | ||
| 1950 | transformList); | ||
| 1951 | short[] lg16Toog16LUT = t.colorConvert(tmp, null); | ||
| 1952 | if (lg16Toog16Map == null) { | ||
| 1953 | lg16Toog16Map = Collections.synchronizedMap(new WeakHashMap(2)); | ||
| 1954 | } | ||
| 1955 | lg16Toog16Map.put(grayCS, lg16Toog16LUT); | ||
| 1956 | return lg16Toog16LUT; | ||
| 1957 | } | ||
| 1958 | |||
| 1959 | } | ||
Binary file not shown.
| @@ -0,0 +1,2948 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.color.ColorSpace; | ||
| 29 | import java.awt.color.ICC_ColorSpace; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * A <CODE>ColorModel</CODE> class that works with pixel values that | ||
| 33 | * represent color and alpha information as separate samples and that | ||
| 34 | * store each sample in a separate data element. This class can be | ||
| 35 | * used with an arbitrary <CODE>ColorSpace</CODE>. The number of | ||
| 36 | * color samples in the pixel values must be same as the number of | ||
| 37 | * color components in the <CODE>ColorSpace</CODE>. There may be a | ||
| 38 | * single alpha sample. | ||
| 39 | * <p> | ||
| 40 | * For those methods that use | ||
| 41 | * a primitive array pixel representation of type <CODE>transferType</CODE>, | ||
| 42 | * the array length is the same as the number of color and alpha samples. | ||
| 43 | * Color samples are stored first in the array followed by the alpha | ||
| 44 | * sample, if present. The order of the color samples is specified | ||
| 45 | * by the <CODE>ColorSpace</CODE>. Typically, this order reflects the | ||
| 46 | * name of the color space type. For example, for <CODE>TYPE_RGB</CODE>, | ||
| 47 | * index 0 corresponds to red, index 1 to green, and index 2 to blue. | ||
| 48 | * <p> | ||
| 49 | * The translation from pixel sample values to color/alpha components for | ||
| 50 | * display or processing purposes is based on a one-to-one correspondence of | ||
| 51 | * samples to components. | ||
| 52 | * Depending on the transfer type used to create an instance of | ||
| 53 | * <code>ComponentColorModel</code>, the pixel sample values | ||
| 54 | * represented by that instance may be signed or unsigned and may | ||
| 55 | * be of integral type or float or double (see below for details). | ||
| 56 | * The translation from sample values to normalized color/alpha components | ||
| 57 | * must follow certain rules. For float and double samples, the translation | ||
| 58 | * is an identity, i.e. normalized component values are equal to the | ||
| 59 | * corresponding sample values. For integral samples, the translation | ||
| 60 | * should be only a simple scale and offset, where the scale and offset | ||
| 61 | * constants may be different for each component. The result of | ||
| 62 | * applying the scale and offset constants is a set of color/alpha | ||
| 63 | * component values, which are guaranteed to fall within a certain | ||
| 64 | * range. Typically, the range for a color component will be the range | ||
| 65 | * defined by the <code>getMinValue</code> and <code>getMaxValue</code> | ||
| 66 | * methods of the <code>ColorSpace</code> class. The range for an | ||
| 67 | * alpha component should be 0.0 to 1.0. | ||
| 68 | * <p> | ||
| 69 | * Instances of <code>ComponentColorModel</code> created with transfer types | ||
| 70 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 71 | * and <CODE>DataBuffer.TYPE_INT</CODE> have pixel sample values which | ||
| 72 | * are treated as unsigned integral values. | ||
| 73 | * The number of bits in a color or alpha sample of a pixel value might not | ||
| 74 | * be the same as the number of bits for the corresponding color or alpha | ||
| 75 | * sample passed to the | ||
| 76 | * <code>ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)</code> | ||
| 77 | * constructor. In | ||
| 78 | * that case, this class assumes that the least significant n bits of a sample | ||
| 79 | * value hold the component value, where n is the number of significant bits | ||
| 80 | * for the component passed to the constructor. It also assumes that | ||
| 81 | * any higher-order bits in a sample value are zero. Thus, sample values | ||
| 82 | * range from 0 to 2<sup>n</sup> - 1. This class maps these sample values | ||
| 83 | * to normalized color component values such that 0 maps to the value | ||
| 84 | * obtained from the <code>ColorSpace's</code> <code>getMinValue</code> | ||
| 85 | * method for each component and 2<sup>n</sup> - 1 maps to the value | ||
| 86 | * obtained from <code>getMaxValue</code>. To create a | ||
| 87 | * <code>ComponentColorModel</code> with a different color sample mapping | ||
| 88 | * requires subclassing this class and overriding the | ||
| 89 | * <code>getNormalizedComponents(Object, float[], int)</code> method. | ||
| 90 | * The mapping for an alpha sample always maps 0 to 0.0 and | ||
| 91 | * 2<sup>n</sup> - 1 to 1.0. | ||
| 92 | * <p> | ||
| 93 | * For instances with unsigned sample values, | ||
| 94 | * the unnormalized color/alpha component representation is only | ||
| 95 | * supported if two conditions hold. First, sample value value 0 must | ||
| 96 | * map to normalized component value 0.0 and sample value 2<sup>n</sup> - 1 | ||
| 97 | * to 1.0. Second the min/max range of all color components of the | ||
| 98 | * <code>ColorSpace</code> must be 0.0 to 1.0. In this case, the | ||
| 99 | * component representation is the n least | ||
| 100 | * significant bits of the corresponding sample. Thus each component is | ||
| 101 | * an unsigned integral value between 0 and 2<sup>n</sup> - 1, where | ||
| 102 | * n is the number of significant bits for a particular component. | ||
| 103 | * If these conditions are not met, any method taking an unnormalized | ||
| 104 | * component argument will throw an <code>IllegalArgumentException</code>. | ||
| 105 | * <p> | ||
| 106 | * Instances of <code>ComponentColorModel</code> created with transfer types | ||
| 107 | * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>, and | ||
| 108 | * <CODE>DataBuffer.TYPE_DOUBLE</CODE> have pixel sample values which | ||
| 109 | * are treated as signed short, float, or double values. | ||
| 110 | * Such instances do not support the unnormalized color/alpha component | ||
| 111 | * representation, so any methods taking such a representation as an argument | ||
| 112 | * will throw an <code>IllegalArgumentException</code> when called on one | ||
| 113 | * of these instances. The normalized component values of instances | ||
| 114 | * of this class have a range which depends on the transfer | ||
| 115 | * type as follows: for float samples, the full range of the float data | ||
| 116 | * type; for double samples, the full range of the float data type | ||
| 117 | * (resulting from casting double to float); for short samples, | ||
| 118 | * from approximately -maxVal to +maxVal, where maxVal is the per | ||
| 119 | * component maximum value for the <code>ColorSpace</code> | ||
| 120 | * (-32767 maps to -maxVal, 0 maps to 0.0, and 32767 maps | ||
| 121 | * to +maxVal). A subclass may override the scaling for short sample | ||
| 122 | * values to normalized component values by overriding the | ||
| 123 | * <code>getNormalizedComponents(Object, float[], int)</code> method. | ||
| 124 | * For float and double samples, the normalized component values are | ||
| 125 | * taken to be equal to the corresponding sample values, and subclasses | ||
| 126 | * should not attempt to add any non-identity scaling for these transfer | ||
| 127 | * types. | ||
| 128 | * <p> | ||
| 129 | * Instances of <code>ComponentColorModel</code> created with transfer types | ||
| 130 | * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>, and | ||
| 131 | * <CODE>DataBuffer.TYPE_DOUBLE</CODE> | ||
| 132 | * use all the bits of all sample values. Thus all color/alpha components | ||
| 133 | * have 16 bits when using <CODE>DataBuffer.TYPE_SHORT</CODE>, 32 bits when | ||
| 134 | * using <CODE>DataBuffer.TYPE_FLOAT</CODE>, and 64 bits when using | ||
| 135 | * <CODE>DataBuffer.TYPE_DOUBLE</CODE>. When the | ||
| 136 | * <code>ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)</code> | ||
| 137 | * form of constructor is used with one of these transfer types, the | ||
| 138 | * bits array argument is ignored. | ||
| 139 | * <p> | ||
| 140 | * It is possible to have color/alpha sample values | ||
| 141 | * which cannot be reasonably interpreted as component values for rendering. | ||
| 142 | * This can happen when <code>ComponentColorModel</code> is subclassed to | ||
| 143 | * override the mapping of unsigned sample values to normalized color | ||
| 144 | * component values or when signed sample values outside a certain range | ||
| 145 | * are used. (As an example, specifying an alpha component as a signed | ||
| 146 | * short value outside the range 0 to 32767, normalized range 0.0 to 1.0, can | ||
| 147 | * lead to unexpected results.) It is the | ||
| 148 | * responsibility of applications to appropriately scale pixel data before | ||
| 149 | * rendering such that color components fall within the normalized range | ||
| 150 | * of the <code>ColorSpace</code> (obtained using the <code>getMinValue</code> | ||
| 151 | * and <code>getMaxValue</code> methods of the <code>ColorSpace</code> class) | ||
| 152 | * and the alpha component is between 0.0 and 1.0. If color or alpha | ||
| 153 | * component values fall outside these ranges, rendering results are | ||
| 154 | * indeterminate. | ||
| 155 | * <p> | ||
| 156 | * Methods that use a single int pixel representation throw | ||
| 157 | * an <CODE>IllegalArgumentException</CODE>, unless the number of components | ||
| 158 | * for the <CODE>ComponentColorModel</CODE> is one and the component | ||
| 159 | * value is unsigned -- in other words, a single color component using | ||
| 160 | * a transfer type of <CODE>DataBuffer.TYPE_BYTE</CODE>, | ||
| 161 | * <CODE>DataBuffer.TYPE_USHORT</CODE>, or <CODE>DataBuffer.TYPE_INT</CODE> | ||
| 162 | * and no alpha. | ||
| 163 | * <p> | ||
| 164 | * A <CODE>ComponentColorModel</CODE> can be used in conjunction with a | ||
| 165 | * <CODE>ComponentSampleModel</CODE>, a <CODE>BandedSampleModel</CODE>, | ||
| 166 | * or a <CODE>PixelInterleavedSampleModel</CODE> to construct a | ||
| 167 | * <CODE>BufferedImage</CODE>. | ||
| 168 | * | ||
| 169 | * @see ColorModel | ||
| 170 | * @see ColorSpace | ||
| 171 | * @see ComponentSampleModel | ||
| 172 | * @see BandedSampleModel | ||
| 173 | * @see PixelInterleavedSampleModel | ||
| 174 | * @see BufferedImage | ||
| 175 | * | ||
| 176 | */ | ||
| 177 | public class ComponentColorModel extends ColorModel { | ||
| 178 | |||
| 179 | /** | ||
| 180 | * <code>signed</code> is <code>true</code> for <code>short</code>, | ||
| 181 | * <code>float</code>, and <code>double</code> transfer types; it | ||
| 182 | * is <code>false</code> for <code>byte</code>, <code>ushort</code>, | ||
| 183 | * and <code>int</code> transfer types. | ||
| 184 | */ | ||
| 185 | private boolean signed; // true for transfer types short, float, double | ||
| 186 | // false for byte, ushort, int | ||
| 187 | private boolean is_sRGB_stdScale; | ||
| 188 | private boolean is_LinearRGB_stdScale; | ||
| 189 | private boolean is_LinearGray_stdScale; | ||
| 190 | private boolean is_ICCGray_stdScale; | ||
| 191 | private byte[] tosRGB8LUT; | ||
| 192 | private byte[] fromsRGB8LUT8; | ||
| 193 | private short[] fromsRGB8LUT16; | ||
| 194 | private byte[] fromLinearGray16ToOtherGray8LUT; | ||
| 195 | private short[] fromLinearGray16ToOtherGray16LUT; | ||
| 196 | private boolean needScaleInit; | ||
| 197 | private boolean noUnnorm; | ||
| 198 | private boolean nonStdScale; | ||
| 199 | private float[] min; | ||
| 200 | private float[] diffMinMax; | ||
| 201 | private float[] compOffset; | ||
| 202 | private float[] compScale; | ||
| 203 | |||
| 204 | /** | ||
| 205 | * Constructs a <CODE>ComponentColorModel</CODE> from the specified | ||
| 206 | * parameters. Color components will be in the specified | ||
| 207 | * <CODE>ColorSpace</CODE>. The supported transfer types are | ||
| 208 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 209 | * <CODE>DataBuffer.TYPE_INT</CODE>, | ||
| 210 | * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>, | ||
| 211 | * and <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 212 | * If not null, the <CODE>bits</CODE> array specifies the | ||
| 213 | * number of significant bits per color and alpha component and its | ||
| 214 | * length should be at least the number of components in the | ||
| 215 | * <CODE>ColorSpace</CODE> if there is no alpha | ||
| 216 | * information in the pixel values, or one more than this number if | ||
| 217 | * there is alpha information. When the <CODE>transferType</CODE> is | ||
| 218 | * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>, | ||
| 219 | * or <CODE>DataBuffer.TYPE_DOUBLE</CODE> the <CODE>bits</CODE> array | ||
| 220 | * argument is ignored. <CODE>hasAlpha</CODE> indicates whether alpha | ||
| 221 | * information is present. If <CODE>hasAlpha</CODE> is true, then | ||
| 222 | * the boolean <CODE>isAlphaPremultiplied</CODE> | ||
| 223 | * specifies how to interpret color and alpha samples in pixel values. | ||
| 224 | * If the boolean is true, color samples are assumed to have been | ||
| 225 | * multiplied by the alpha sample. The <CODE>transparency</CODE> | ||
| 226 | * specifies what alpha values can be represented by this color model. | ||
| 227 | * The acceptable <code>transparency</code> values are | ||
| 228 | * <CODE>OPAQUE</CODE>, <CODE>BITMASK</CODE> or <CODE>TRANSLUCENT</CODE>. | ||
| 229 | * The <CODE>transferType</CODE> is the type of primitive array used | ||
| 230 | * to represent pixel values. | ||
| 231 | * | ||
| 232 | * @param colorSpace The <CODE>ColorSpace</CODE> associated | ||
| 233 | * with this color model. | ||
| 234 | * @param bits The number of significant bits per component. | ||
| 235 | * May be null, in which case all bits of all | ||
| 236 | * component samples will be significant. | ||
| 237 | * Ignored if transferType is one of | ||
| 238 | * <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 239 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or | ||
| 240 | * <CODE>DataBuffer.TYPE_DOUBLE</CODE>, | ||
| 241 | * in which case all bits of all component | ||
| 242 | * samples will be significant. | ||
| 243 | * @param hasAlpha If true, this color model supports alpha. | ||
| 244 | * @param isAlphaPremultiplied If true, alpha is premultiplied. | ||
| 245 | * @param transparency Specifies what alpha values can be represented | ||
| 246 | * by this color model. | ||
| 247 | * @param transferType Specifies the type of primitive array used to | ||
| 248 | * represent pixel values. | ||
| 249 | * | ||
| 250 | * @throws IllegalArgumentException If the <CODE>bits</CODE> array | ||
| 251 | * argument is not null, its length is less than the number of | ||
| 252 | * color and alpha components, and transferType is one of | ||
| 253 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, | ||
| 254 | * <CODE>DataBuffer.TYPE_USHORT</CODE>, or | ||
| 255 | * <CODE>DataBuffer.TYPE_INT</CODE>. | ||
| 256 | * @throws IllegalArgumentException If transferType is not one of | ||
| 257 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, | ||
| 258 | * <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 259 | * <CODE>DataBuffer.TYPE_INT</CODE>, | ||
| 260 | * <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 261 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or | ||
| 262 | * <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 263 | * | ||
| 264 | * @see ColorSpace | ||
| 265 | * @see java.awt.Transparency | ||
| 266 | */ | ||
| 267 | public ComponentColorModel (ColorSpace colorSpace, | ||
| 268 | int[] bits, | ||
| 269 | boolean hasAlpha, | ||
| 270 | boolean isAlphaPremultiplied, | ||
| 271 | int transparency, | ||
| 272 | int transferType) { | ||
| 273 | super (bitsHelper(transferType, colorSpace, hasAlpha), | ||
| 274 | bitsArrayHelper(bits, transferType, colorSpace, hasAlpha), | ||
| 275 | colorSpace, hasAlpha, isAlphaPremultiplied, transparency, | ||
| 276 | transferType); | ||
| 277 | switch(transferType) { | ||
| 278 | case DataBuffer.TYPE_BYTE: | ||
| 279 | case DataBuffer.TYPE_USHORT: | ||
| 280 | case DataBuffer.TYPE_INT: | ||
| 281 | signed = false; | ||
| 282 | needScaleInit = true; | ||
| 283 | break; | ||
| 284 | case DataBuffer.TYPE_SHORT: | ||
| 285 | signed = true; | ||
| 286 | needScaleInit = true; | ||
| 287 | break; | ||
| 288 | case DataBuffer.TYPE_FLOAT: | ||
| 289 | case DataBuffer.TYPE_DOUBLE: | ||
| 290 | signed = true; | ||
| 291 | needScaleInit = false; | ||
| 292 | noUnnorm = true; | ||
| 293 | nonStdScale = false; | ||
| 294 | break; | ||
| 295 | default: | ||
| 296 | throw new IllegalArgumentException("This constructor is not "+ | ||
| 297 | "compatible with transferType " + transferType); | ||
| 298 | } | ||
| 299 | setupLUTs(); | ||
| 300 | } | ||
| 301 | |||
| 302 | /** | ||
| 303 | * Constructs a <CODE>ComponentColorModel</CODE> from the specified | ||
| 304 | * parameters. Color components will be in the specified | ||
| 305 | * <CODE>ColorSpace</CODE>. The supported transfer types are | ||
| 306 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 307 | * <CODE>DataBuffer.TYPE_INT</CODE>, | ||
| 308 | * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>, | ||
| 309 | * and <CODE>DataBuffer.TYPE_DOUBLE</CODE>. The number of significant | ||
| 310 | * bits per color and alpha component will be 8, 16, 32, 16, 32, or 64, | ||
| 311 | * respectively. The number of color components will be the | ||
| 312 | * number of components in the <CODE>ColorSpace</CODE>. There will be | ||
| 313 | * an alpha component if <CODE>hasAlpha</CODE> is <CODE>true</CODE>. | ||
| 314 | * If <CODE>hasAlpha</CODE> is true, then | ||
| 315 | * the boolean <CODE>isAlphaPremultiplied</CODE> | ||
| 316 | * specifies how to interpret color and alpha samples in pixel values. | ||
| 317 | * If the boolean is true, color samples are assumed to have been | ||
| 318 | * multiplied by the alpha sample. The <CODE>transparency</CODE> | ||
| 319 | * specifies what alpha values can be represented by this color model. | ||
| 320 | * The acceptable <code>transparency</code> values are | ||
| 321 | * <CODE>OPAQUE</CODE>, <CODE>BITMASK</CODE> or <CODE>TRANSLUCENT</CODE>. | ||
| 322 | * The <CODE>transferType</CODE> is the type of primitive array used | ||
| 323 | * to represent pixel values. | ||
| 324 | * | ||
| 325 | * @param colorSpace The <CODE>ColorSpace</CODE> associated | ||
| 326 | * with this color model. | ||
| 327 | * @param hasAlpha If true, this color model supports alpha. | ||
| 328 | * @param isAlphaPremultiplied If true, alpha is premultiplied. | ||
| 329 | * @param transparency Specifies what alpha values can be represented | ||
| 330 | * by this color model. | ||
| 331 | * @param transferType Specifies the type of primitive array used to | ||
| 332 | * represent pixel values. | ||
| 333 | * | ||
| 334 | * @throws IllegalArgumentException If transferType is not one of | ||
| 335 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, | ||
| 336 | * <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 337 | * <CODE>DataBuffer.TYPE_INT</CODE>, | ||
| 338 | * <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 339 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or | ||
| 340 | * <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 341 | * | ||
| 342 | * @see ColorSpace | ||
| 343 | * @see java.awt.Transparency | ||
| 344 | * @since 1.4 | ||
| 345 | */ | ||
| 346 | public ComponentColorModel (ColorSpace colorSpace, | ||
| 347 | boolean hasAlpha, | ||
| 348 | boolean isAlphaPremultiplied, | ||
| 349 | int transparency, | ||
| 350 | int transferType) { | ||
| 351 | this(colorSpace, null, hasAlpha, isAlphaPremultiplied, | ||
| 352 | transparency, transferType); | ||
| 353 | } | ||
| 354 | |||
| 355 | private static int bitsHelper(int transferType, | ||
| 356 | ColorSpace colorSpace, | ||
| 357 | boolean hasAlpha) { | ||
| 358 | int numBits = DataBuffer.getDataTypeSize(transferType); | ||
| 359 | int numComponents = colorSpace.getNumComponents(); | ||
| 360 | if (hasAlpha) { | ||
| 361 | ++numComponents; | ||
| 362 | } | ||
| 363 | return numBits * numComponents; | ||
| 364 | } | ||
| 365 | |||
| 366 | private static int[] bitsArrayHelper(int[] origBits, | ||
| 367 | int transferType, | ||
| 368 | ColorSpace colorSpace, | ||
| 369 | boolean hasAlpha) { | ||
| 370 | switch(transferType) { | ||
| 371 | case DataBuffer.TYPE_BYTE: | ||
| 372 | case DataBuffer.TYPE_USHORT: | ||
| 373 | case DataBuffer.TYPE_INT: | ||
| 374 | if (origBits != null) { | ||
| 375 | return origBits; | ||
| 376 | } | ||
| 377 | break; | ||
| 378 | default: | ||
| 379 | break; | ||
| 380 | } | ||
| 381 | int numBits = DataBuffer.getDataTypeSize(transferType); | ||
| 382 | int numComponents = colorSpace.getNumComponents(); | ||
| 383 | if (hasAlpha) { | ||
| 384 | ++numComponents; | ||
| 385 | } | ||
| 386 | int[] bits = new int[numComponents]; | ||
| 387 | for (int i = 0; i < numComponents; i++) { | ||
| 388 | bits[i] = numBits; | ||
| 389 | } | ||
| 390 | return bits; | ||
| 391 | } | ||
| 392 | |||
| 393 | private void setupLUTs() { | ||
| 394 | // REMIND: there is potential to accelerate sRGB, LinearRGB, | ||
| 395 | // LinearGray, ICCGray, and non-ICC Gray spaces with non-standard | ||
| 396 | // scaling, if that becomes important | ||
| 397 | // | ||
| 398 | // NOTE: The is_xxx_stdScale and nonStdScale booleans are provisionally | ||
| 399 | // set here when this method is called at construction time. These | ||
| 400 | // variables may be set again when initScale is called later. | ||
| 401 | // When setupLUTs returns, nonStdScale is true if (the transferType | ||
| 402 | // is not float or double) AND (some minimum ColorSpace component | ||
| 403 | // value is not 0.0 OR some maximum ColorSpace component value | ||
| 404 | // is not 1.0). This is correct for the calls to | ||
| 405 | // getNormalizedComponents(Object, float[], int) from initScale(). | ||
| 406 | // initScale() may change the value nonStdScale based on the | ||
| 407 | // return value of getNormalizedComponents() - this will only | ||
| 408 | // happen if getNormalizedComponents() has been overridden by a | ||
| 409 | // subclass to make the mapping of min/max pixel sample values | ||
| 410 | // something different from min/max color component values. | ||
| 411 | if (is_sRGB) { | ||
| 412 | is_sRGB_stdScale = true; | ||
| 413 | nonStdScale = false; | ||
| 414 | } else if (ColorModel.isLinearRGBspace(colorSpace)) { | ||
| 415 | // Note that the built-in Linear RGB space has a normalized | ||
| 416 | // range of 0.0 - 1.0 for each coordinate. Usage of these | ||
| 417 | // LUTs makes that assumption. | ||
| 418 | is_LinearRGB_stdScale = true; | ||
| 419 | nonStdScale = false; | ||
| 420 | if (transferType == DataBuffer.TYPE_BYTE) { | ||
| 421 | tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT(); | ||
| 422 | fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT(); | ||
| 423 | } else { | ||
| 424 | tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT(); | ||
| 425 | fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); | ||
| 426 | } | ||
| 427 | } else if ((colorSpaceType == ColorSpace.TYPE_GRAY) && | ||
| 428 | (colorSpace instanceof ICC_ColorSpace) && | ||
| 429 | (colorSpace.getMinValue(0) == 0.0f) && | ||
| 430 | (colorSpace.getMaxValue(0) == 1.0f)) { | ||
| 431 | // Note that a normalized range of 0.0 - 1.0 for the gray | ||
| 432 | // component is required, because usage of these LUTs makes | ||
| 433 | // that assumption. | ||
| 434 | ICC_ColorSpace ics = (ICC_ColorSpace) colorSpace; | ||
| 435 | is_ICCGray_stdScale = true; | ||
| 436 | nonStdScale = false; | ||
| 437 | fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); | ||
| 438 | if (ColorModel.isLinearGRAYspace(ics)) { | ||
| 439 | is_LinearGray_stdScale = true; | ||
| 440 | if (transferType == DataBuffer.TYPE_BYTE) { | ||
| 441 | tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics); | ||
| 442 | } else { | ||
| 443 | tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics); | ||
| 444 | } | ||
| 445 | } else { | ||
| 446 | if (transferType == DataBuffer.TYPE_BYTE) { | ||
| 447 | tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics); | ||
| 448 | fromLinearGray16ToOtherGray8LUT = | ||
| 449 | ColorModel.getLinearGray16ToOtherGray8LUT(ics); | ||
| 450 | } else { | ||
| 451 | tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics); | ||
| 452 | fromLinearGray16ToOtherGray16LUT = | ||
| 453 | ColorModel.getLinearGray16ToOtherGray16LUT(ics); | ||
| 454 | } | ||
| 455 | } | ||
| 456 | } else if (needScaleInit) { | ||
| 457 | // if transferType is byte, ushort, int, or short and we | ||
| 458 | // don't already know the ColorSpace has minVlaue == 0.0f and | ||
| 459 | // maxValue == 1.0f for all components, we need to check that | ||
| 460 | // now and setup the min[] and diffMinMax[] arrays if necessary. | ||
| 461 | nonStdScale = false; | ||
| 462 | for (int i = 0; i < numColorComponents; i++) { | ||
| 463 | if ((colorSpace.getMinValue(i) != 0.0f) || | ||
| 464 | (colorSpace.getMaxValue(i) != 1.0f)) { | ||
| 465 | nonStdScale = true; | ||
| 466 | break; | ||
| 467 | } | ||
| 468 | } | ||
| 469 | if (nonStdScale) { | ||
| 470 | min = new float[numColorComponents]; | ||
| 471 | diffMinMax = new float[numColorComponents]; | ||
| 472 | for (int i = 0; i < numColorComponents; i++) { | ||
| 473 | min[i] = colorSpace.getMinValue(i); | ||
| 474 | diffMinMax[i] = colorSpace.getMaxValue(i) - min[i]; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | private void initScale() { | ||
| 481 | // This method is called the first time any method which uses | ||
| 482 | // pixel sample value to color component value scaling information | ||
| 483 | // is called if the transferType supports non-standard scaling | ||
| 484 | // as defined above (byte, ushort, int, and short), unless the | ||
| 485 | // method is getNormalizedComponents(Object, float[], int) (that | ||
| 486 | // method must be overridden to use non-standard scaling). This | ||
| 487 | // method also sets up the noUnnorm boolean variable for these | ||
| 488 | // transferTypes. After this method is called, the nonStdScale | ||
| 489 | // variable will be true if getNormalizedComponents() maps a | ||
| 490 | // sample value of 0 to anything other than 0.0f OR maps a | ||
| 491 | // sample value of 2^^n - 1 (2^^15 - 1 for short transferType) | ||
| 492 | // to anything other than 1.0f. Note that this can be independent | ||
| 493 | // of the colorSpace min/max component values, if the | ||
| 494 | // getNormalizedComponents() method has been overridden for some | ||
| 495 | // reason, e.g. to provide greater dynamic range in the sample | ||
| 496 | // values than in the color component values. Unfortunately, | ||
| 497 | // this method can't be called at construction time, since a | ||
| 498 | // subclass may still have uninitialized state that would cause | ||
| 499 | // getNormalizedComponents() to return an incorrect result. | ||
| 500 | needScaleInit = false; // only needs to called once | ||
| 501 | if (nonStdScale || signed) { | ||
| 502 | // The unnormalized form is only supported for unsigned | ||
| 503 | // transferTypes and when the ColorSpace min/max values | ||
| 504 | // are 0.0/1.0. When this method is called nonStdScale is | ||
| 505 | // true if the latter condition does not hold. In addition, | ||
| 506 | // the unnormalized form requires that the full range of | ||
| 507 | // the pixel sample values map to the full 0.0 - 1.0 range | ||
| 508 | // of color component values. That condition is checked | ||
| 509 | // later in this method. | ||
| 510 | noUnnorm = true; | ||
| 511 | } else { | ||
| 512 | noUnnorm = false; | ||
| 513 | } | ||
| 514 | float[] lowVal, highVal; | ||
| 515 | switch (transferType) { | ||
| 516 | case DataBuffer.TYPE_BYTE: | ||
| 517 | { | ||
| 518 | byte[] bpixel = new byte[numComponents]; | ||
| 519 | for (int i = 0; i < numColorComponents; i++) { | ||
| 520 | bpixel[i] = 0; | ||
| 521 | } | ||
| 522 | if (supportsAlpha) { | ||
| 523 | bpixel[numColorComponents] = | ||
| 524 | (byte) ((1 << nBits[numColorComponents]) - 1); | ||
| 525 | } | ||
| 526 | lowVal = getNormalizedComponents(bpixel, null, 0); | ||
| 527 | for (int i = 0; i < numColorComponents; i++) { | ||
| 528 | bpixel[i] = (byte) ((1 << nBits[i]) - 1); | ||
| 529 | } | ||
| 530 | highVal = getNormalizedComponents(bpixel, null, 0); | ||
| 531 | } | ||
| 532 | break; | ||
| 533 | case DataBuffer.TYPE_USHORT: | ||
| 534 | { | ||
| 535 | short[] uspixel = new short[numComponents]; | ||
| 536 | for (int i = 0; i < numColorComponents; i++) { | ||
| 537 | uspixel[i] = 0; | ||
| 538 | } | ||
| 539 | if (supportsAlpha) { | ||
| 540 | uspixel[numColorComponents] = | ||
| 541 | (short) ((1 << nBits[numColorComponents]) - 1); | ||
| 542 | } | ||
| 543 | lowVal = getNormalizedComponents(uspixel, null, 0); | ||
| 544 | for (int i = 0; i < numColorComponents; i++) { | ||
| 545 | uspixel[i] = (short) ((1 << nBits[i]) - 1); | ||
| 546 | } | ||
| 547 | highVal = getNormalizedComponents(uspixel, null, 0); | ||
| 548 | } | ||
| 549 | break; | ||
| 550 | case DataBuffer.TYPE_INT: | ||
| 551 | { | ||
| 552 | int[] ipixel = new int[numComponents]; | ||
| 553 | for (int i = 0; i < numColorComponents; i++) { | ||
| 554 | ipixel[i] = 0; | ||
| 555 | } | ||
| 556 | if (supportsAlpha) { | ||
| 557 | ipixel[numColorComponents] = | ||
| 558 | ((1 << nBits[numColorComponents]) - 1); | ||
| 559 | } | ||
| 560 | lowVal = getNormalizedComponents(ipixel, null, 0); | ||
| 561 | for (int i = 0; i < numColorComponents; i++) { | ||
| 562 | ipixel[i] = ((1 << nBits[i]) - 1); | ||
| 563 | } | ||
| 564 | highVal = getNormalizedComponents(ipixel, null, 0); | ||
| 565 | } | ||
| 566 | break; | ||
| 567 | case DataBuffer.TYPE_SHORT: | ||
| 568 | { | ||
| 569 | short[] spixel = new short[numComponents]; | ||
| 570 | for (int i = 0; i < numColorComponents; i++) { | ||
| 571 | spixel[i] = 0; | ||
| 572 | } | ||
| 573 | if (supportsAlpha) { | ||
| 574 | spixel[numColorComponents] = 32767; | ||
| 575 | } | ||
| 576 | lowVal = getNormalizedComponents(spixel, null, 0); | ||
| 577 | for (int i = 0; i < numColorComponents; i++) { | ||
| 578 | spixel[i] = 32767; | ||
| 579 | } | ||
| 580 | highVal = getNormalizedComponents(spixel, null, 0); | ||
| 581 | } | ||
| 582 | break; | ||
| 583 | default: | ||
| 584 | lowVal = highVal = null; // to keep the compiler from complaining | ||
| 585 | break; | ||
| 586 | } | ||
| 587 | nonStdScale = false; | ||
| 588 | for (int i = 0; i < numColorComponents; i++) { | ||
| 589 | if ((lowVal[i] != 0.0f) || (highVal[i] != 1.0f)) { | ||
| 590 | nonStdScale = true; | ||
| 591 | break; | ||
| 592 | } | ||
| 593 | } | ||
| 594 | if (nonStdScale) { | ||
| 595 | noUnnorm = true; | ||
| 596 | is_sRGB_stdScale = false; | ||
| 597 | is_LinearRGB_stdScale = false; | ||
| 598 | is_LinearGray_stdScale = false; | ||
| 599 | is_ICCGray_stdScale = false; | ||
| 600 | compOffset = new float[numColorComponents]; | ||
| 601 | compScale = new float[numColorComponents]; | ||
| 602 | for (int i = 0; i < numColorComponents; i++) { | ||
| 603 | compOffset[i] = lowVal[i]; | ||
| 604 | compScale[i] = 1.0f / (highVal[i] - lowVal[i]); | ||
| 605 | } | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | private int getRGBComponent(int pixel, int idx) { | ||
| 610 | if (numComponents > 1) { | ||
| 611 | throw new | ||
| 612 | IllegalArgumentException("More than one component per pixel"); | ||
| 613 | } | ||
| 614 | if (signed) { | ||
| 615 | throw new | ||
| 616 | IllegalArgumentException("Component value is signed"); | ||
| 617 | } | ||
| 618 | if (needScaleInit) { | ||
| 619 | initScale(); | ||
| 620 | } | ||
| 621 | // Since there is only 1 component, there is no alpha | ||
| 622 | |||
| 623 | // Normalize the pixel in order to convert it | ||
| 624 | Object opixel = null; | ||
| 625 | switch (transferType) { | ||
| 626 | case DataBuffer.TYPE_BYTE: | ||
| 627 | { | ||
| 628 | byte[] bpixel = { (byte) pixel }; | ||
| 629 | opixel = bpixel; | ||
| 630 | } | ||
| 631 | break; | ||
| 632 | case DataBuffer.TYPE_USHORT: | ||
| 633 | { | ||
| 634 | short[] spixel = { (short) pixel }; | ||
| 635 | opixel = spixel; | ||
| 636 | } | ||
| 637 | break; | ||
| 638 | case DataBuffer.TYPE_INT: | ||
| 639 | { | ||
| 640 | int[] ipixel = { pixel }; | ||
| 641 | opixel = ipixel; | ||
| 642 | } | ||
| 643 | break; | ||
| 644 | } | ||
| 645 | float[] norm = getNormalizedComponents(opixel, null, 0); | ||
| 646 | float[] rgb = colorSpace.toRGB(norm); | ||
| 647 | |||
| 648 | return (int) (rgb[idx] * 255.0f + 0.5f); | ||
| 649 | } | ||
| 650 | |||
| 651 | /** | ||
| 652 | * Returns the red color component for the specified pixel, scaled | ||
| 653 | * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion | ||
| 654 | * is done if necessary. The pixel value is specified as an int. | ||
| 655 | * The returned value will be a non pre-multiplied value. | ||
| 656 | * If the alpha is premultiplied, this method divides | ||
| 657 | * it out before returning the value (if the alpha value is 0, | ||
| 658 | * the red value will be 0). | ||
| 659 | * | ||
| 660 | * @param pixel The pixel from which you want to get the red color component. | ||
| 661 | * | ||
| 662 | * @return The red color component for the specified pixel, as an int. | ||
| 663 | * | ||
| 664 | * @throws IllegalArgumentException If there is more than | ||
| 665 | * one component in this <CODE>ColorModel</CODE>. | ||
| 666 | * @throws IllegalArgumentException If the component value for this | ||
| 667 | * <CODE>ColorModel</CODE> is signed | ||
| 668 | */ | ||
| 669 | public int getRed(int pixel) { | ||
| 670 | return getRGBComponent(pixel, 0); | ||
| 671 | } | ||
| 672 | |||
| 673 | /** | ||
| 674 | * Returns the green color component for the specified pixel, scaled | ||
| 675 | * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion | ||
| 676 | * is done if necessary. The pixel value is specified as an int. | ||
| 677 | * The returned value will be a non | ||
| 678 | * pre-multiplied value. If the alpha is premultiplied, this method | ||
| 679 | * divides it out before returning the value (if the alpha value is 0, | ||
| 680 | * the green value will be 0). | ||
| 681 | * | ||
| 682 | * @param pixel The pixel from which you want to get the green color component. | ||
| 683 | * | ||
| 684 | * @return The green color component for the specified pixel, as an int. | ||
| 685 | * | ||
| 686 | * @throws IllegalArgumentException If there is more than | ||
| 687 | * one component in this <CODE>ColorModel</CODE>. | ||
| 688 | * @throws IllegalArgumentException If the component value for this | ||
| 689 | * <CODE>ColorModel</CODE> is signed | ||
| 690 | */ | ||
| 691 | public int getGreen(int pixel) { | ||
| 692 | return getRGBComponent(pixel, 1); | ||
| 693 | } | ||
| 694 | |||
| 695 | /** | ||
| 696 | * Returns the blue color component for the specified pixel, scaled | ||
| 697 | * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion | ||
| 698 | * is done if necessary. The pixel value is specified as an int. | ||
| 699 | * The returned value will be a non | ||
| 700 | * pre-multiplied value. If the alpha is premultiplied, this method | ||
| 701 | * divides it out before returning the value (if the alpha value is 0, | ||
| 702 | * the blue value will be 0). | ||
| 703 | * | ||
| 704 | * @param pixel The pixel from which you want to get the blue color component. | ||
| 705 | * | ||
| 706 | * @return The blue color component for the specified pixel, as an int. | ||
| 707 | * | ||
| 708 | * @throws IllegalArgumentException If there is more than | ||
| 709 | * one component in this <CODE>ColorModel</CODE>. | ||
| 710 | * @throws IllegalArgumentException If the component value for this | ||
| 711 | * <CODE>ColorModel</CODE> is signed | ||
| 712 | */ | ||
| 713 | public int getBlue(int pixel) { | ||
| 714 | return getRGBComponent(pixel, 2); | ||
| 715 | } | ||
| 716 | |||
| 717 | /** | ||
| 718 | * Returns the alpha component for the specified pixel, scaled | ||
| 719 | * from 0 to 255. The pixel value is specified as an int. | ||
| 720 | * | ||
| 721 | * @param pixel The pixel from which you want to get the alpha component. | ||
| 722 | * | ||
| 723 | * @return The alpha component for the specified pixel, as an int. | ||
| 724 | * | ||
| 725 | * @throws IllegalArgumentException If there is more than | ||
| 726 | * one component in this <CODE>ColorModel</CODE>. | ||
| 727 | * @throws IllegalArgumentException If the component value for this | ||
| 728 | * <CODE>ColorModel</CODE> is signed | ||
| 729 | */ | ||
| 730 | public int getAlpha(int pixel) { | ||
| 731 | if (supportsAlpha == false) { | ||
| 732 | return 255; | ||
| 733 | } | ||
| 734 | if (numComponents > 1) { | ||
| 735 | throw new | ||
| 736 | IllegalArgumentException("More than one component per pixel"); | ||
| 737 | } | ||
| 738 | if (signed) { | ||
| 739 | throw new | ||
| 740 | IllegalArgumentException("Component value is signed"); | ||
| 741 | } | ||
| 742 | |||
| 743 | return (int) ((((float) pixel) / ((1<<nBits[0])-1)) * 255.0f + 0.5f); | ||
| 744 | } | ||
| 745 | |||
| 746 | /** | ||
| 747 | * Returns the color/alpha components of the pixel in the default | ||
| 748 | * RGB color model format. A color conversion is done if necessary. | ||
| 749 | * The returned value will be in a non pre-multiplied format. If | ||
| 750 | * the alpha is premultiplied, this method divides it out of the | ||
| 751 | * color components (if the alpha value is 0, the color values will be 0). | ||
| 752 | * | ||
| 753 | * @param pixel The pixel from which you want to get the color/alpha components. | ||
| 754 | * | ||
| 755 | * @return The color/alpha components for the specified pixel, as an int. | ||
| 756 | * | ||
| 757 | * @throws IllegalArgumentException If there is more than | ||
| 758 | * one component in this <CODE>ColorModel</CODE>. | ||
| 759 | * @throws IllegalArgumentException If the component value for this | ||
| 760 | * <CODE>ColorModel</CODE> is signed | ||
| 761 | */ | ||
| 762 | public int getRGB(int pixel) { | ||
| 763 | if (numComponents > 1) { | ||
| 764 | throw new | ||
| 765 | IllegalArgumentException("More than one component per pixel"); | ||
| 766 | } | ||
| 767 | if (signed) { | ||
| 768 | throw new | ||
| 769 | IllegalArgumentException("Component value is signed"); | ||
| 770 | } | ||
| 771 | |||
| 772 | return (getAlpha(pixel) << 24) | ||
| 773 | | (getRed(pixel) << 16) | ||
| 774 | | (getGreen(pixel) << 8) | ||
| 775 | | (getBlue(pixel) << 0); | ||
| 776 | } | ||
| 777 | |||
| 778 | private int extractComponent(Object inData, int idx, int precision) { | ||
| 779 | // Extract component idx from inData. The precision argument | ||
| 780 | // should be either 8 or 16. If it's 8, this method will return | ||
| 781 | // an 8-bit value. If it's 16, this method will return a 16-bit | ||
| 782 | // value for transferTypes other than TYPE_BYTE. For TYPE_BYTE, | ||
| 783 | // an 8-bit value will be returned. | ||
| 784 | |||
| 785 | // This method maps the input value corresponding to a | ||
| 786 | // normalized ColorSpace component value of 0.0 to 0, and the | ||
| 787 | // input value corresponding to a normalized ColorSpace | ||
| 788 | // component value of 1.0 to 2^n - 1 (where n is 8 or 16), so | ||
| 789 | // it is appropriate only for ColorSpaces with min/max component | ||
| 790 | // values of 0.0/1.0. This will be true for sRGB, the built-in | ||
| 791 | // Linear RGB and Linear Gray spaces, and any other ICC grayscale | ||
| 792 | // spaces for which we have precomputed LUTs. | ||
| 793 | |||
| 794 | boolean needAlpha = (supportsAlpha && isAlphaPremultiplied); | ||
| 795 | int alp = 0; | ||
| 796 | int comp; | ||
| 797 | int mask = (1 << nBits[idx]) - 1; | ||
| 798 | |||
| 799 | switch (transferType) { | ||
| 800 | // Note: we do no clamping of the pixel data here - we | ||
| 801 | // assume that the data is scaled properly | ||
| 802 | case DataBuffer.TYPE_SHORT: { | ||
| 803 | short sdata[] = (short[]) inData; | ||
| 804 | float scalefactor = (float) ((1 << precision) - 1); | ||
| 805 | if (needAlpha) { | ||
| 806 | short s = sdata[numColorComponents]; | ||
| 807 | if (s != (short) 0) { | ||
| 808 | return (int) ((((float) sdata[idx]) / | ||
| 809 | ((float) s)) * scalefactor + 0.5f); | ||
| 810 | } else { | ||
| 811 | return 0; | ||
| 812 | } | ||
| 813 | } else { | ||
| 814 | return (int) ((sdata[idx] / 32767.0f) * scalefactor + 0.5f); | ||
| 815 | } | ||
| 816 | } | ||
| 817 | case DataBuffer.TYPE_FLOAT: { | ||
| 818 | float fdata[] = (float[]) inData; | ||
| 819 | float scalefactor = (float) ((1 << precision) - 1); | ||
| 820 | if (needAlpha) { | ||
| 821 | float f = fdata[numColorComponents]; | ||
| 822 | if (f != 0.0f) { | ||
| 823 | return (int) (((fdata[idx] / f) * scalefactor) + 0.5f); | ||
| 824 | } else { | ||
| 825 | return 0; | ||
| 826 | } | ||
| 827 | } else { | ||
| 828 | return (int) (fdata[idx] * scalefactor + 0.5f); | ||
| 829 | } | ||
| 830 | } | ||
| 831 | case DataBuffer.TYPE_DOUBLE: { | ||
| 832 | double ddata[] = (double[]) inData; | ||
| 833 | double scalefactor = (double) ((1 << precision) - 1); | ||
| 834 | if (needAlpha) { | ||
| 835 | double d = ddata[numColorComponents]; | ||
| 836 | if (d != 0.0) { | ||
| 837 | return (int) (((ddata[idx] / d) * scalefactor) + 0.5); | ||
| 838 | } else { | ||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | } else { | ||
| 842 | return (int) (ddata[idx] * scalefactor + 0.5); | ||
| 843 | } | ||
| 844 | } | ||
| 845 | case DataBuffer.TYPE_BYTE: | ||
| 846 | byte bdata[] = (byte[])inData; | ||
| 847 | comp = bdata[idx] & mask; | ||
| 848 | precision = 8; | ||
| 849 | if (needAlpha) { | ||
| 850 | alp = bdata[numColorComponents] & mask; | ||
| 851 | } | ||
| 852 | break; | ||
| 853 | case DataBuffer.TYPE_USHORT: | ||
| 854 | short usdata[] = (short[])inData; | ||
| 855 | comp = usdata[idx] & mask; | ||
| 856 | if (needAlpha) { | ||
| 857 | alp = usdata[numColorComponents] & mask; | ||
| 858 | } | ||
| 859 | break; | ||
| 860 | case DataBuffer.TYPE_INT: | ||
| 861 | int idata[] = (int[])inData; | ||
| 862 | comp = idata[idx]; | ||
| 863 | if (needAlpha) { | ||
| 864 | alp = idata[numColorComponents]; | ||
| 865 | } | ||
| 866 | break; | ||
| 867 | default: | ||
| 868 | throw new | ||
| 869 | UnsupportedOperationException("This method has not "+ | ||
| 870 | "been implemented for transferType " + transferType); | ||
| 871 | } | ||
| 872 | if (needAlpha) { | ||
| 873 | if (alp != 0) { | ||
| 874 | float scalefactor = (float) ((1 << precision) - 1); | ||
| 875 | float fcomp = ((float) comp) / ((float)mask); | ||
| 876 | float invalp = ((float) ((1<<nBits[numColorComponents]) - 1)) / | ||
| 877 | ((float) alp); | ||
| 878 | return (int) (fcomp * invalp * scalefactor + 0.5f); | ||
| 879 | } else { | ||
| 880 | return 0; | ||
| 881 | } | ||
| 882 | } else { | ||
| 883 | if (nBits[idx] != precision) { | ||
| 884 | float scalefactor = (float) ((1 << precision) - 1); | ||
| 885 | float fcomp = ((float) comp) / ((float)mask); | ||
| 886 | return (int) (fcomp * scalefactor + 0.5f); | ||
| 887 | } | ||
| 888 | return comp; | ||
| 889 | } | ||
| 890 | } | ||
| 891 | |||
| 892 | private int getRGBComponent(Object inData, int idx) { | ||
| 893 | if (needScaleInit) { | ||
| 894 | initScale(); | ||
| 895 | } | ||
| 896 | if (is_sRGB_stdScale) { | ||
| 897 | return extractComponent(inData, idx, 8); | ||
| 898 | } else if (is_LinearRGB_stdScale) { | ||
| 899 | int lutidx = extractComponent(inData, idx, 16); | ||
| 900 | return tosRGB8LUT[lutidx] & 0xff; | ||
| 901 | } else if (is_ICCGray_stdScale) { | ||
| 902 | int lutidx = extractComponent(inData, 0, 16); | ||
| 903 | return tosRGB8LUT[lutidx] & 0xff; | ||
| 904 | } | ||
| 905 | |||
| 906 | // Not CS_sRGB, CS_LINEAR_RGB, or any TYPE_GRAY ICC_ColorSpace | ||
| 907 | float[] norm = getNormalizedComponents(inData, null, 0); | ||
| 908 | // Note that getNormalizedComponents returns non-premultiplied values | ||
| 909 | float[] rgb = colorSpace.toRGB(norm); | ||
| 910 | return (int) (rgb[idx] * 255.0f + 0.5f); | ||
| 911 | } | ||
| 912 | |||
| 913 | /** | ||
| 914 | * Returns the red color component for the specified pixel, scaled | ||
| 915 | * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion | ||
| 916 | * is done if necessary. The <CODE>pixel</CODE> value is specified by an array | ||
| 917 | * of data elements of type <CODE>transferType</CODE> passed in as an object | ||
| 918 | * reference. The returned value will be a non pre-multiplied value. If the | ||
| 919 | * alpha is premultiplied, this method divides it out before returning | ||
| 920 | * the value (if the alpha value is 0, the red value will be 0). Since | ||
| 921 | * <code>ComponentColorModel</code> can be subclassed, subclasses | ||
| 922 | * inherit the implementation of this method and if they don't override | ||
| 923 | * it then they throw an exception if they use an unsupported | ||
| 924 | * <code>transferType</code>. | ||
| 925 | * | ||
| 926 | * @param inData The pixel from which you want to get the red color component, | ||
| 927 | * specified by an array of data elements of type <CODE>transferType</CODE>. | ||
| 928 | * | ||
| 929 | * @return The red color component for the specified pixel, as an int. | ||
| 930 | * | ||
| 931 | * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array | ||
| 932 | * of type <CODE>transferType</CODE>. | ||
| 933 | * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not | ||
| 934 | * large enough to hold a pixel value for this | ||
| 935 | * <CODE>ColorModel</CODE>. | ||
| 936 | * @throws UnsupportedOperationException If the transfer type of | ||
| 937 | * this <CODE>ComponentColorModel</CODE> | ||
| 938 | * is not one of the supported transfer types: | ||
| 939 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 940 | * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 941 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 942 | */ | ||
| 943 | public int getRed(Object inData) { | ||
| 944 | return getRGBComponent(inData, 0); | ||
| 945 | } | ||
| 946 | |||
| 947 | |||
| 948 | /** | ||
| 949 | * Returns the green color component for the specified pixel, scaled | ||
| 950 | * from 0 to 255 in the default RGB <CODE>ColorSpace</CODE>, sRGB. | ||
| 951 | * A color conversion is done if necessary. The <CODE>pixel</CODE> value | ||
| 952 | * is specified by an array of data elements of type <CODE>transferType</CODE> | ||
| 953 | * passed in as an object reference. The returned value is a non pre-multiplied | ||
| 954 | * value. If the alpha is premultiplied, this method divides it out before | ||
| 955 | * returning the value (if the alpha value is 0, the green value will be 0). | ||
| 956 | * Since <code>ComponentColorModel</code> can be subclassed, | ||
| 957 | * subclasses inherit the implementation of this method and if they | ||
| 958 | * don't override it then they throw an exception if they use an | ||
| 959 | * unsupported <code>transferType</code>. | ||
| 960 | * | ||
| 961 | * @param inData The pixel from which you want to get the green color component, | ||
| 962 | * specified by an array of data elements of type <CODE>transferType</CODE>. | ||
| 963 | * | ||
| 964 | * @return The green color component for the specified pixel, as an int. | ||
| 965 | * | ||
| 966 | * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array | ||
| 967 | * of type <CODE>transferType</CODE>. | ||
| 968 | * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not | ||
| 969 | * large enough to hold a pixel value for this | ||
| 970 | * <CODE>ColorModel</CODE>. | ||
| 971 | * @throws UnsupportedOperationException If the transfer type of | ||
| 972 | * this <CODE>ComponentColorModel</CODE> | ||
| 973 | * is not one of the supported transfer types: | ||
| 974 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 975 | * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 976 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 977 | */ | ||
| 978 | public int getGreen(Object inData) { | ||
| 979 | return getRGBComponent(inData, 1); | ||
| 980 | } | ||
| 981 | |||
| 982 | |||
| 983 | /** | ||
| 984 | * Returns the blue color component for the specified pixel, scaled | ||
| 985 | * from 0 to 255 in the default RGB <CODE>ColorSpace</CODE>, sRGB. | ||
| 986 | * A color conversion is done if necessary. The <CODE>pixel</CODE> value is | ||
| 987 | * specified by an array of data elements of type <CODE>transferType</CODE> | ||
| 988 | * passed in as an object reference. The returned value is a non pre-multiplied | ||
| 989 | * value. If the alpha is premultiplied, this method divides it out before | ||
| 990 | * returning the value (if the alpha value is 0, the blue value will be 0). | ||
| 991 | * Since <code>ComponentColorModel</code> can be subclassed, | ||
| 992 | * subclasses inherit the implementation of this method and if they | ||
| 993 | * don't override it then they throw an exception if they use an | ||
| 994 | * unsupported <code>transferType</code>. | ||
| 995 | * | ||
| 996 | * @param inData The pixel from which you want to get the blue color component, | ||
| 997 | * specified by an array of data elements of type <CODE>transferType</CODE>. | ||
| 998 | * | ||
| 999 | * @return The blue color component for the specified pixel, as an int. | ||
| 1000 | * | ||
| 1001 | * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array | ||
| 1002 | * of type <CODE>transferType</CODE>. | ||
| 1003 | * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not | ||
| 1004 | * large enough to hold a pixel value for this | ||
| 1005 | * <CODE>ColorModel</CODE>. | ||
| 1006 | * @throws UnsupportedOperationException If the transfer type of | ||
| 1007 | * this <CODE>ComponentColorModel</CODE> | ||
| 1008 | * is not one of the supported transfer types: | ||
| 1009 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 1010 | * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 1011 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 1012 | */ | ||
| 1013 | public int getBlue(Object inData) { | ||
| 1014 | return getRGBComponent(inData, 2); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | /** | ||
| 1018 | * Returns the alpha component for the specified pixel, scaled from | ||
| 1019 | * 0 to 255. The pixel value is specified by an array of data | ||
| 1020 | * elements of type <CODE>transferType</CODE> passed in as an | ||
| 1021 | * object reference. Since <code>ComponentColorModel</code> can be | ||
| 1022 | * subclassed, subclasses inherit the | ||
| 1023 | * implementation of this method and if they don't override it then | ||
| 1024 | * they throw an exception if they use an unsupported | ||
| 1025 | * <code>transferType</code>. | ||
| 1026 | * | ||
| 1027 | * @param inData The pixel from which you want to get the alpha component, | ||
| 1028 | * specified by an array of data elements of type <CODE>transferType</CODE>. | ||
| 1029 | * | ||
| 1030 | * @return The alpha component for the specified pixel, as an int. | ||
| 1031 | * | ||
| 1032 | * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array | ||
| 1033 | * of type <CODE>transferType</CODE>. | ||
| 1034 | * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not | ||
| 1035 | * large enough to hold a pixel value for this | ||
| 1036 | * <CODE>ColorModel</CODE>. | ||
| 1037 | * @throws UnsupportedOperationException If the transfer type of | ||
| 1038 | * this <CODE>ComponentColorModel</CODE> | ||
| 1039 | * is not one of the supported transfer types: | ||
| 1040 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 1041 | * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 1042 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 1043 | */ | ||
| 1044 | public int getAlpha(Object inData) { | ||
| 1045 | if (supportsAlpha == false) { | ||
| 1046 | return 255; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | int alpha = 0; | ||
| 1050 | int aIdx = numColorComponents; | ||
| 1051 | int mask = (1 << nBits[aIdx]) - 1; | ||
| 1052 | |||
| 1053 | switch (transferType) { | ||
| 1054 | case DataBuffer.TYPE_SHORT: | ||
| 1055 | short sdata[] = (short[])inData; | ||
| 1056 | alpha = (int) ((sdata[aIdx] / 32767.0f) * 255.0f + 0.5f); | ||
| 1057 | return alpha; | ||
| 1058 | case DataBuffer.TYPE_FLOAT: | ||
| 1059 | float fdata[] = (float[])inData; | ||
| 1060 | alpha = (int) (fdata[aIdx] * 255.0f + 0.5f); | ||
| 1061 | return alpha; | ||
| 1062 | case DataBuffer.TYPE_DOUBLE: | ||
| 1063 | double ddata[] = (double[])inData; | ||
| 1064 | alpha = (int) (ddata[aIdx] * 255.0 + 0.5); | ||
| 1065 | return alpha; | ||
| 1066 | case DataBuffer.TYPE_BYTE: | ||
| 1067 | byte bdata[] = (byte[])inData; | ||
| 1068 | alpha = bdata[aIdx] & mask; | ||
| 1069 | break; | ||
| 1070 | case DataBuffer.TYPE_USHORT: | ||
| 1071 | short usdata[] = (short[])inData; | ||
| 1072 | alpha = usdata[aIdx] & mask; | ||
| 1073 | break; | ||
| 1074 | case DataBuffer.TYPE_INT: | ||
| 1075 | int idata[] = (int[])inData; | ||
| 1076 | alpha = idata[aIdx]; | ||
| 1077 | break; | ||
| 1078 | default: | ||
| 1079 | throw new | ||
| 1080 | UnsupportedOperationException("This method has not "+ | ||
| 1081 | "been implemented for transferType " + transferType); | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | if (nBits[aIdx] == 8) { | ||
| 1085 | return alpha; | ||
| 1086 | } else { | ||
| 1087 | return (int) | ||
| 1088 | ((((float) alpha) / ((float) ((1 << nBits[aIdx]) - 1))) * | ||
| 1089 | 255.0f + 0.5f); | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /** | ||
| 1094 | * Returns the color/alpha components for the specified pixel in the | ||
| 1095 | * default RGB color model format. A color conversion is done if | ||
| 1096 | * necessary. The pixel value is specified by an | ||
| 1097 | * array of data elements of type <CODE>transferType</CODE> passed | ||
| 1098 | * in as an object reference. | ||
| 1099 | * The returned value is in a non pre-multiplied format. If | ||
| 1100 | * the alpha is premultiplied, this method divides it out of the | ||
| 1101 | * color components (if the alpha value is 0, the color values will be 0). | ||
| 1102 | * Since <code>ComponentColorModel</code> can be subclassed, | ||
| 1103 | * subclasses inherit the implementation of this method and if they | ||
| 1104 | * don't override it then they throw an exception if they use an | ||
| 1105 | * unsupported <code>transferType</code>. | ||
| 1106 | * | ||
| 1107 | * @param inData The pixel from which you want to get the color/alpha components, | ||
| 1108 | * specified by an array of data elements of type <CODE>transferType</CODE>. | ||
| 1109 | * | ||
| 1110 | * @return The color/alpha components for the specified pixel, as an int. | ||
| 1111 | * | ||
| 1112 | * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array | ||
| 1113 | * of type <CODE>transferType</CODE>. | ||
| 1114 | * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not | ||
| 1115 | * large enough to hold a pixel value for this | ||
| 1116 | * <CODE>ColorModel</CODE>. | ||
| 1117 | * @throws UnsupportedOperationException If the transfer type of | ||
| 1118 | * this <CODE>ComponentColorModel</CODE> | ||
| 1119 | * is not one of the supported transfer types: | ||
| 1120 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 1121 | * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 1122 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 1123 | * @see ColorModel#getRGBdefault | ||
| 1124 | */ | ||
| 1125 | public int getRGB(Object inData) { | ||
| 1126 | if (needScaleInit) { | ||
| 1127 | initScale(); | ||
| 1128 | } | ||
| 1129 | if (is_sRGB_stdScale || is_LinearRGB_stdScale) { | ||
| 1130 | return (getAlpha(inData) << 24) | ||
| 1131 | | (getRed(inData) << 16) | ||
| 1132 | | (getGreen(inData) << 8) | ||
| 1133 | | (getBlue(inData)); | ||
| 1134 | } else if (colorSpaceType == ColorSpace.TYPE_GRAY) { | ||
| 1135 | int gray = getRed(inData); // Red sRGB component should equal | ||
| 1136 | // green and blue components | ||
| 1137 | return (getAlpha(inData) << 24) | ||
| 1138 | | (gray << 16) | ||
| 1139 | | (gray << 8) | ||
| 1140 | | gray; | ||
| 1141 | } | ||
| 1142 | float[] norm = getNormalizedComponents(inData, null, 0); | ||
| 1143 | // Note that getNormalizedComponents returns non-premult values | ||
| 1144 | float[] rgb = colorSpace.toRGB(norm); | ||
| 1145 | return (getAlpha(inData) << 24) | ||
| 1146 | | (((int) (rgb[0] * 255.0f + 0.5f)) << 16) | ||
| 1147 | | (((int) (rgb[1] * 255.0f + 0.5f)) << 8) | ||
| 1148 | | (((int) (rgb[2] * 255.0f + 0.5f)) << 0); | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | /** | ||
| 1152 | * Returns a data element array representation of a pixel in this | ||
| 1153 | * <CODE>ColorModel</CODE>, given an integer pixel representation | ||
| 1154 | * in the default RGB color model. | ||
| 1155 | * This array can then be passed to the <CODE>setDataElements</CODE> | ||
| 1156 | * method of a <CODE>WritableRaster</CODE> object. If the | ||
| 1157 | * <CODE>pixel</CODE> | ||
| 1158 | * parameter is null, a new array is allocated. Since | ||
| 1159 | * <code>ComponentColorModel</code> can be subclassed, subclasses | ||
| 1160 | * inherit the implementation of this method and if they don't | ||
| 1161 | * override it then | ||
| 1162 | * they throw an exception if they use an unsupported | ||
| 1163 | * <code>transferType</code>. | ||
| 1164 | * | ||
| 1165 | * @param rgb the integer representation of the pixel in the RGB | ||
| 1166 | * color model | ||
| 1167 | * @param pixel the specified pixel | ||
| 1168 | * @return The data element array representation of a pixel | ||
| 1169 | * in this <CODE>ColorModel</CODE>. | ||
| 1170 | * @throws ClassCastException If <CODE>pixel</CODE> is not null and | ||
| 1171 | * is not a primitive array of type <CODE>transferType</CODE>. | ||
| 1172 | * @throws ArrayIndexOutOfBoundsException If <CODE>pixel</CODE> is | ||
| 1173 | * not large enough to hold a pixel value for this | ||
| 1174 | * <CODE>ColorModel</CODE>. | ||
| 1175 | * @throws UnsupportedOperationException If the transfer type of | ||
| 1176 | * this <CODE>ComponentColorModel</CODE> | ||
| 1177 | * is not one of the supported transfer types: | ||
| 1178 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 1179 | * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 1180 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 1181 | * | ||
| 1182 | * @see WritableRaster#setDataElements | ||
| 1183 | * @see SampleModel#setDataElements | ||
| 1184 | */ | ||
| 1185 | public Object getDataElements(int rgb, Object pixel) { | ||
| 1186 | // REMIND: Use rendering hints? | ||
| 1187 | |||
| 1188 | int red, grn, blu, alp; | ||
| 1189 | red = (rgb>>16) & 0xff; | ||
| 1190 | grn = (rgb>>8) & 0xff; | ||
| 1191 | blu = rgb & 0xff; | ||
| 1192 | |||
| 1193 | if (needScaleInit) { | ||
| 1194 | initScale(); | ||
| 1195 | } | ||
| 1196 | if (signed) { | ||
| 1197 | // Handle SHORT, FLOAT, & DOUBLE here | ||
| 1198 | |||
| 1199 | switch(transferType) { | ||
| 1200 | case DataBuffer.TYPE_SHORT: | ||
| 1201 | { | ||
| 1202 | short sdata[]; | ||
| 1203 | if (pixel == null) { | ||
| 1204 | sdata = new short[numComponents]; | ||
| 1205 | } else { | ||
| 1206 | sdata = (short[])pixel; | ||
| 1207 | } | ||
| 1208 | float factor; | ||
| 1209 | if (is_sRGB_stdScale || is_LinearRGB_stdScale) { | ||
| 1210 | factor = 32767.0f / 255.0f; | ||
| 1211 | if (is_LinearRGB_stdScale) { | ||
| 1212 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1213 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1214 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1215 | factor = 32767.0f / 65535.0f; | ||
| 1216 | } | ||
| 1217 | if (supportsAlpha) { | ||
| 1218 | alp = (rgb>>24) & 0xff; | ||
| 1219 | sdata[3] = | ||
| 1220 | (short) (alp * (32767.0f / 255.0f) + 0.5f); | ||
| 1221 | if (isAlphaPremultiplied) { | ||
| 1222 | factor = alp * factor * (1.0f / 255.0f); | ||
| 1223 | } | ||
| 1224 | } | ||
| 1225 | sdata[0] = (short) (red * factor + 0.5f); | ||
| 1226 | sdata[1] = (short) (grn * factor + 0.5f); | ||
| 1227 | sdata[2] = (short) (blu * factor + 0.5f); | ||
| 1228 | } else if (is_LinearGray_stdScale) { | ||
| 1229 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1230 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1231 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1232 | float gray = ((0.2125f * red) + | ||
| 1233 | (0.7154f * grn) + | ||
| 1234 | (0.0721f * blu)) / 65535.0f; | ||
| 1235 | factor = 32767.0f; | ||
| 1236 | if (supportsAlpha) { | ||
| 1237 | alp = (rgb>>24) & 0xff; | ||
| 1238 | sdata[1] = | ||
| 1239 | (short) (alp * (32767.0f / 255.0f) + 0.5f); | ||
| 1240 | if (isAlphaPremultiplied) { | ||
| 1241 | factor = alp * factor * (1.0f / 255.0f); | ||
| 1242 | } | ||
| 1243 | } | ||
| 1244 | sdata[0] = (short) (gray * factor + 0.5f); | ||
| 1245 | } else if (is_ICCGray_stdScale) { | ||
| 1246 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1247 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1248 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1249 | int gray = (int) ((0.2125f * red) + | ||
| 1250 | (0.7154f * grn) + | ||
| 1251 | (0.0721f * blu) + 0.5f); | ||
| 1252 | gray = fromLinearGray16ToOtherGray16LUT[gray] & 0xffff; | ||
| 1253 | factor = 32767.0f / 65535.0f; | ||
| 1254 | if (supportsAlpha) { | ||
| 1255 | alp = (rgb>>24) & 0xff; | ||
| 1256 | sdata[1] = | ||
| 1257 | (short) (alp * (32767.0f / 255.0f) + 0.5f); | ||
| 1258 | if (isAlphaPremultiplied) { | ||
| 1259 | factor = alp * factor * (1.0f / 255.0f); | ||
| 1260 | } | ||
| 1261 | } | ||
| 1262 | sdata[0] = (short) (gray * factor + 0.5f); | ||
| 1263 | } else { | ||
| 1264 | factor = 1.0f / 255.0f; | ||
| 1265 | float norm[] = new float[3]; | ||
| 1266 | norm[0] = red * factor; | ||
| 1267 | norm[1] = grn * factor; | ||
| 1268 | norm[2] = blu * factor; | ||
| 1269 | norm = colorSpace.fromRGB(norm); | ||
| 1270 | if (nonStdScale) { | ||
| 1271 | for (int i = 0; i < numColorComponents; i++) { | ||
| 1272 | norm[i] = (norm[i] - compOffset[i]) * | ||
| 1273 | compScale[i]; | ||
| 1274 | // REMIND: need to analyze whether this | ||
| 1275 | // clamping is necessary | ||
| 1276 | if (norm[i] < 0.0f) { | ||
| 1277 | norm[i] = 0.0f; | ||
| 1278 | } | ||
| 1279 | if (norm[i] > 1.0f) { | ||
| 1280 | norm[i] = 1.0f; | ||
| 1281 | } | ||
| 1282 | } | ||
| 1283 | } | ||
| 1284 | factor = 32767.0f; | ||
| 1285 | if (supportsAlpha) { | ||
| 1286 | alp = (rgb>>24) & 0xff; | ||
| 1287 | sdata[numColorComponents] = | ||
| 1288 | (short) (alp * (32767.0f / 255.0f) + 0.5f); | ||
| 1289 | if (isAlphaPremultiplied) { | ||
| 1290 | factor *= alp * (1.0f / 255.0f); | ||
| 1291 | } | ||
| 1292 | } | ||
| 1293 | for (int i = 0; i < numColorComponents; i++) { | ||
| 1294 | sdata[i] = (short) (norm[i] * factor + 0.5f); | ||
| 1295 | } | ||
| 1296 | } | ||
| 1297 | return sdata; | ||
| 1298 | } | ||
| 1299 | case DataBuffer.TYPE_FLOAT: | ||
| 1300 | { | ||
| 1301 | float fdata[]; | ||
| 1302 | if (pixel == null) { | ||
| 1303 | fdata = new float[numComponents]; | ||
| 1304 | } else { | ||
| 1305 | fdata = (float[])pixel; | ||
| 1306 | } | ||
| 1307 | float factor; | ||
| 1308 | if (is_sRGB_stdScale || is_LinearRGB_stdScale) { | ||
| 1309 | if (is_LinearRGB_stdScale) { | ||
| 1310 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1311 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1312 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1313 | factor = 1.0f / 65535.0f; | ||
| 1314 | } else { | ||
| 1315 | factor = 1.0f / 255.0f; | ||
| 1316 | } | ||
| 1317 | if (supportsAlpha) { | ||
| 1318 | alp = (rgb>>24) & 0xff; | ||
| 1319 | fdata[3] = alp * (1.0f / 255.0f); | ||
| 1320 | if (isAlphaPremultiplied) { | ||
| 1321 | factor *= fdata[3]; | ||
| 1322 | } | ||
| 1323 | } | ||
| 1324 | fdata[0] = red * factor; | ||
| 1325 | fdata[1] = grn * factor; | ||
| 1326 | fdata[2] = blu * factor; | ||
| 1327 | } else if (is_LinearGray_stdScale) { | ||
| 1328 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1329 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1330 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1331 | fdata[0] = ((0.2125f * red) + | ||
| 1332 | (0.7154f * grn) + | ||
| 1333 | (0.0721f * blu)) / 65535.0f; | ||
| 1334 | if (supportsAlpha) { | ||
| 1335 | alp = (rgb>>24) & 0xff; | ||
| 1336 | fdata[1] = alp * (1.0f / 255.0f); | ||
| 1337 | if (isAlphaPremultiplied) { | ||
| 1338 | fdata[0] *= fdata[1]; | ||
| 1339 | } | ||
| 1340 | } | ||
| 1341 | } else if (is_ICCGray_stdScale) { | ||
| 1342 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1343 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1344 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1345 | int gray = (int) ((0.2125f * red) + | ||
| 1346 | (0.7154f * grn) + | ||
| 1347 | (0.0721f * blu) + 0.5f); | ||
| 1348 | fdata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & | ||
| 1349 | 0xffff) / 65535.0f; | ||
| 1350 | if (supportsAlpha) { | ||
| 1351 | alp = (rgb>>24) & 0xff; | ||
| 1352 | fdata[1] = alp * (1.0f / 255.0f); | ||
| 1353 | if (isAlphaPremultiplied) { | ||
| 1354 | fdata[0] *= fdata[1]; | ||
| 1355 | } | ||
| 1356 | } | ||
| 1357 | } else { | ||
| 1358 | float norm[] = new float[3]; | ||
| 1359 | factor = 1.0f / 255.0f; | ||
| 1360 | norm[0] = red * factor; | ||
| 1361 | norm[1] = grn * factor; | ||
| 1362 | norm[2] = blu * factor; | ||
| 1363 | norm = colorSpace.fromRGB(norm); | ||
| 1364 | if (supportsAlpha) { | ||
| 1365 | alp = (rgb>>24) & 0xff; | ||
| 1366 | fdata[numColorComponents] = alp * factor; | ||
| 1367 | if (isAlphaPremultiplied) { | ||
| 1368 | factor *= alp; | ||
| 1369 | for (int i = 0; i < numColorComponents; i++) { | ||
| 1370 | norm[i] *= factor; | ||
| 1371 | } | ||
| 1372 | } | ||
| 1373 | } | ||
| 1374 | for (int i = 0; i < numColorComponents; i++) { | ||
| 1375 | fdata[i] = norm[i]; | ||
| 1376 | } | ||
| 1377 | } | ||
| 1378 | return fdata; | ||
| 1379 | } | ||
| 1380 | case DataBuffer.TYPE_DOUBLE: | ||
| 1381 | { | ||
| 1382 | double ddata[]; | ||
| 1383 | if (pixel == null) { | ||
| 1384 | ddata = new double[numComponents]; | ||
| 1385 | } else { | ||
| 1386 | ddata = (double[])pixel; | ||
| 1387 | } | ||
| 1388 | if (is_sRGB_stdScale || is_LinearRGB_stdScale) { | ||
| 1389 | double factor; | ||
| 1390 | if (is_LinearRGB_stdScale) { | ||
| 1391 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1392 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1393 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1394 | factor = 1.0 / 65535.0; | ||
| 1395 | } else { | ||
| 1396 | factor = 1.0 / 255.0; | ||
| 1397 | } | ||
| 1398 | if (supportsAlpha) { | ||
| 1399 | alp = (rgb>>24) & 0xff; | ||
| 1400 | ddata[3] = alp * (1.0 / 255.0); | ||
| 1401 | if (isAlphaPremultiplied) { | ||
| 1402 | factor *= ddata[3]; | ||
| 1403 | } | ||
| 1404 | } | ||
| 1405 | ddata[0] = red * factor; | ||
| 1406 | ddata[1] = grn * factor; | ||
| 1407 | ddata[2] = blu * factor; | ||
| 1408 | } else if (is_LinearGray_stdScale) { | ||
| 1409 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1410 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1411 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1412 | ddata[0] = ((0.2125 * red) + | ||
| 1413 | (0.7154 * grn) + | ||
| 1414 | (0.0721 * blu)) / 65535.0; | ||
| 1415 | if (supportsAlpha) { | ||
| 1416 | alp = (rgb>>24) & 0xff; | ||
| 1417 | ddata[1] = alp * (1.0 / 255.0); | ||
| 1418 | if (isAlphaPremultiplied) { | ||
| 1419 | ddata[0] *= ddata[1]; | ||
| 1420 | } | ||
| 1421 | } | ||
| 1422 | } else if (is_ICCGray_stdScale) { | ||
| 1423 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1424 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1425 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1426 | int gray = (int) ((0.2125f * red) + | ||
| 1427 | (0.7154f * grn) + | ||
| 1428 | (0.0721f * blu) + 0.5f); | ||
| 1429 | ddata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & | ||
| 1430 | 0xffff) / 65535.0; | ||
| 1431 | if (supportsAlpha) { | ||
| 1432 | alp = (rgb>>24) & 0xff; | ||
| 1433 | ddata[1] = alp * (1.0 / 255.0); | ||
| 1434 | if (isAlphaPremultiplied) { | ||
| 1435 | ddata[0] *= ddata[1]; | ||
| 1436 | } | ||
| 1437 | } | ||
| 1438 | } else { | ||
| 1439 | float factor = 1.0f / 255.0f; | ||
| 1440 | float norm[] = new float[3]; | ||
| 1441 | norm[0] = red * factor; | ||
| 1442 | norm[1] = grn * factor; | ||
| 1443 | norm[2] = blu * factor; | ||
| 1444 | norm = colorSpace.fromRGB(norm); | ||
| 1445 | if (supportsAlpha) { | ||
| 1446 | alp = (rgb>>24) & 0xff; | ||
| 1447 | ddata[numColorComponents] = alp * (1.0 / 255.0); | ||
| 1448 | if (isAlphaPremultiplied) { | ||
| 1449 | factor *= alp; | ||
| 1450 | for (int i = 0; i < numColorComponents; i++) { | ||
| 1451 | norm[i] *= factor; | ||
| 1452 | } | ||
| 1453 | } | ||
| 1454 | } | ||
| 1455 | for (int i = 0; i < numColorComponents; i++) { | ||
| 1456 | ddata[i] = norm[i]; | ||
| 1457 | } | ||
| 1458 | } | ||
| 1459 | return ddata; | ||
| 1460 | } | ||
| 1461 | } | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | // Handle BYTE, USHORT, & INT here | ||
| 1465 | //REMIND: maybe more efficient not to use int array for | ||
| 1466 | //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT | ||
| 1467 | int intpixel[]; | ||
| 1468 | if (transferType == DataBuffer.TYPE_INT && | ||
| 1469 | pixel != null) { | ||
| 1470 | intpixel = (int[])pixel; | ||
| 1471 | } else { | ||
| 1472 | intpixel = new int[numComponents]; | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | if (is_sRGB_stdScale || is_LinearRGB_stdScale) { | ||
| 1476 | int precision; | ||
| 1477 | float factor; | ||
| 1478 | if (is_LinearRGB_stdScale) { | ||
| 1479 | if (transferType == DataBuffer.TYPE_BYTE) { | ||
| 1480 | red = fromsRGB8LUT8[red] & 0xff; | ||
| 1481 | grn = fromsRGB8LUT8[grn] & 0xff; | ||
| 1482 | blu = fromsRGB8LUT8[blu] & 0xff; | ||
| 1483 | precision = 8; | ||
| 1484 | factor = 1.0f / 255.0f; | ||
| 1485 | } else { | ||
| 1486 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1487 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1488 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1489 | precision = 16; | ||
| 1490 | factor = 1.0f / 65535.0f; | ||
| 1491 | } | ||
| 1492 | } else { | ||
| 1493 | precision = 8; | ||
| 1494 | factor = 1.0f / 255.0f; | ||
| 1495 | } | ||
| 1496 | if (supportsAlpha) { | ||
| 1497 | alp = (rgb>>24)&0xff; | ||
| 1498 | if (nBits[3] == 8) { | ||
| 1499 | intpixel[3] = alp; | ||
| 1500 | } | ||
| 1501 | else { | ||
| 1502 | intpixel[3] = (int) | ||
| 1503 | (alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1) + 0.5f); | ||
| 1504 | } | ||
| 1505 | if (isAlphaPremultiplied) { | ||
| 1506 | factor *= (alp * (1.0f / 255.0f)); | ||
| 1507 | precision = -1; // force component calculations below | ||
| 1508 | } | ||
| 1509 | } | ||
| 1510 | if (nBits[0] == precision) { | ||
| 1511 | intpixel[0] = red; | ||
| 1512 | } | ||
| 1513 | else { | ||
| 1514 | intpixel[0] = (int) (red * factor * ((1<<nBits[0]) - 1) + 0.5f); | ||
| 1515 | } | ||
| 1516 | if (nBits[1] == precision) { | ||
| 1517 | intpixel[1] = (int)(grn); | ||
| 1518 | } | ||
| 1519 | else { | ||
| 1520 | intpixel[1] = (int) (grn * factor * ((1<<nBits[1]) - 1) + 0.5f); | ||
| 1521 | } | ||
| 1522 | if (nBits[2] == precision) { | ||
| 1523 | intpixel[2] = (int)(blu); | ||
| 1524 | } | ||
| 1525 | else { | ||
| 1526 | intpixel[2] = (int) (blu * factor * ((1<<nBits[2]) - 1) + 0.5f); | ||
| 1527 | } | ||
| 1528 | } else if (is_LinearGray_stdScale) { | ||
| 1529 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1530 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1531 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1532 | float gray = ((0.2125f * red) + | ||
| 1533 | (0.7154f * grn) + | ||
| 1534 | (0.0721f * blu)) / 65535.0f; | ||
| 1535 | if (supportsAlpha) { | ||
| 1536 | alp = (rgb>>24) & 0xff; | ||
| 1537 | if (nBits[1] == 8) { | ||
| 1538 | intpixel[1] = alp; | ||
| 1539 | } else { | ||
| 1540 | intpixel[1] = (int) (alp * (1.0f / 255.0f) * | ||
| 1541 | ((1 << nBits[1]) - 1) + 0.5f); | ||
| 1542 | } | ||
| 1543 | if (isAlphaPremultiplied) { | ||
| 1544 | gray *= (alp * (1.0f / 255.0f)); | ||
| 1545 | } | ||
| 1546 | } | ||
| 1547 | intpixel[0] = (int) (gray * ((1 << nBits[0]) - 1) + 0.5f); | ||
| 1548 | } else if (is_ICCGray_stdScale) { | ||
| 1549 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 1550 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 1551 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 1552 | int gray16 = (int) ((0.2125f * red) + | ||
| 1553 | (0.7154f * grn) + | ||
| 1554 | (0.0721f * blu) + 0.5f); | ||
| 1555 | float gray = (fromLinearGray16ToOtherGray16LUT[gray16] & | ||
| 1556 | 0xffff) / 65535.0f; | ||
| 1557 | if (supportsAlpha) { | ||
| 1558 | alp = (rgb>>24) & 0xff; | ||
| 1559 | if (nBits[1] == 8) { | ||
| 1560 | intpixel[1] = alp; | ||
| 1561 | } else { | ||
| 1562 | intpixel[1] = (int) (alp * (1.0f / 255.0f) * | ||
| 1563 | ((1 << nBits[1]) - 1) + 0.5f); | ||
| 1564 | } | ||
| 1565 | if (isAlphaPremultiplied) { | ||
| 1566 | gray *= (alp * (1.0f / 255.0f)); | ||
| 1567 | } | ||
| 1568 | } | ||
| 1569 | intpixel[0] = (int) (gray * ((1 << nBits[0]) - 1) + 0.5f); | ||
| 1570 | } else { | ||
| 1571 | // Need to convert the color | ||
| 1572 | float[] norm = new float[3]; | ||
| 1573 | float factor = 1.0f / 255.0f; | ||
| 1574 | norm[0] = red * factor; | ||
| 1575 | norm[1] = grn * factor; | ||
| 1576 | norm[2] = blu * factor; | ||
| 1577 | norm = colorSpace.fromRGB(norm); | ||
| 1578 | if (nonStdScale) { | ||
| 1579 | for (int i = 0; i < numColorComponents; i++) { | ||
| 1580 | norm[i] = (norm[i] - compOffset[i]) * | ||
| 1581 | compScale[i]; | ||
| 1582 | // REMIND: need to analyze whether this | ||
| 1583 | // clamping is necessary | ||
| 1584 | if (norm[i] < 0.0f) { | ||
| 1585 | norm[i] = 0.0f; | ||
| 1586 | } | ||
| 1587 | if (norm[i] > 1.0f) { | ||
| 1588 | norm[i] = 1.0f; | ||
| 1589 | } | ||
| 1590 | } | ||
| 1591 | } | ||
| 1592 | if (supportsAlpha) { | ||
| 1593 | alp = (rgb>>24) & 0xff; | ||
| 1594 | if (nBits[numColorComponents] == 8) { | ||
| 1595 | intpixel[numColorComponents] = alp; | ||
| 1596 | } | ||
| 1597 | else { | ||
| 1598 | intpixel[numColorComponents] = | ||
| 1599 | (int) (alp * factor * | ||
| 1600 | ((1<<nBits[numColorComponents]) - 1) + 0.5f); | ||
| 1601 | } | ||
| 1602 | if (isAlphaPremultiplied) { | ||
| 1603 | factor *= alp; | ||
| 1604 | for (int i = 0; i < numColorComponents; i++) { | ||
| 1605 | norm[i] *= factor; | ||
| 1606 | } | ||
| 1607 | } | ||
| 1608 | } | ||
| 1609 | for (int i = 0; i < numColorComponents; i++) { | ||
| 1610 | intpixel[i] = (int) (norm[i] * ((1<<nBits[i]) - 1) + 0.5f); | ||
| 1611 | } | ||
| 1612 | } | ||
| 1613 | |||
| 1614 | switch (transferType) { | ||
| 1615 | case DataBuffer.TYPE_BYTE: { | ||
| 1616 | byte bdata[]; | ||
| 1617 | if (pixel == null) { | ||
| 1618 | bdata = new byte[numComponents]; | ||
| 1619 | } else { | ||
| 1620 | bdata = (byte[])pixel; | ||
| 1621 | } | ||
| 1622 | for (int i = 0; i < numComponents; i++) { | ||
| 1623 | bdata[i] = (byte)(0xff&intpixel[i]); | ||
| 1624 | } | ||
| 1625 | return bdata; | ||
| 1626 | } | ||
| 1627 | case DataBuffer.TYPE_USHORT:{ | ||
| 1628 | short sdata[]; | ||
| 1629 | if (pixel == null) { | ||
| 1630 | sdata = new short[numComponents]; | ||
| 1631 | } else { | ||
| 1632 | sdata = (short[])pixel; | ||
| 1633 | } | ||
| 1634 | for (int i = 0; i < numComponents; i++) { | ||
| 1635 | sdata[i] = (short)(intpixel[i]&0xffff); | ||
| 1636 | } | ||
| 1637 | return sdata; | ||
| 1638 | } | ||
| 1639 | case DataBuffer.TYPE_INT: | ||
| 1640 | if (maxBits > 23) { | ||
| 1641 | // fix 4412670 - for components of 24 or more bits | ||
| 1642 | // some calculations done above with float precision | ||
| 1643 | // may lose enough precision that the integer result | ||
| 1644 | // overflows nBits, so we need to clamp. | ||
| 1645 | for (int i = 0; i < numComponents; i++) { | ||
| 1646 | if (intpixel[i] > ((1<<nBits[i]) - 1)) { | ||
| 1647 | intpixel[i] = (1<<nBits[i]) - 1; | ||
| 1648 | } | ||
| 1649 | } | ||
| 1650 | } | ||
| 1651 | return intpixel; | ||
| 1652 | } | ||
| 1653 | throw new IllegalArgumentException("This method has not been "+ | ||
| 1654 | "implemented for transferType " + transferType); | ||
| 1655 | } | ||
| 1656 | |||
| 1657 | /** Returns an array of unnormalized color/alpha components given a pixel | ||
| 1658 | * in this <CODE>ColorModel</CODE>. | ||
| 1659 | * An IllegalArgumentException is thrown if the component value for this | ||
| 1660 | * <CODE>ColorModel</CODE> is not conveniently representable in the | ||
| 1661 | * unnormalized form. Color/alpha components are stored | ||
| 1662 | * in the <CODE>components</CODE> array starting at <CODE>offset</CODE> | ||
| 1663 | * (even if the array is allocated by this method). | ||
| 1664 | * | ||
| 1665 | * @param pixel The pixel value specified as an integer. | ||
| 1666 | * @param components An integer array in which to store the unnormalized | ||
| 1667 | * color/alpha components. If the <CODE>components</CODE> array is null, | ||
| 1668 | * a new array is allocated. | ||
| 1669 | * @param offset An offset into the <CODE>components</CODE> array. | ||
| 1670 | * | ||
| 1671 | * @return The components array. | ||
| 1672 | * | ||
| 1673 | * @throws IllegalArgumentException If there is more than one | ||
| 1674 | * component in this <CODE>ColorModel</CODE>. | ||
| 1675 | * @throws IllegalArgumentException If this | ||
| 1676 | * <CODE>ColorModel</CODE> does not support the unnormalized form | ||
| 1677 | * @throws ArrayIndexOutOfBoundsException If the <CODE>components</CODE> | ||
| 1678 | * array is not null and is not large enough to hold all the color and | ||
| 1679 | * alpha components (starting at offset). | ||
| 1680 | */ | ||
| 1681 | public int[] getComponents(int pixel, int[] components, int offset) { | ||
| 1682 | if (numComponents > 1) { | ||
| 1683 | throw new | ||
| 1684 | IllegalArgumentException("More than one component per pixel"); | ||
| 1685 | } | ||
| 1686 | if (needScaleInit) { | ||
| 1687 | initScale(); | ||
| 1688 | } | ||
| 1689 | if (noUnnorm) { | ||
| 1690 | throw new | ||
| 1691 | IllegalArgumentException( | ||
| 1692 | "This ColorModel does not support the unnormalized form"); | ||
| 1693 | } | ||
| 1694 | if (components == null) { | ||
| 1695 | components = new int[offset+1]; | ||
| 1696 | } | ||
| 1697 | |||
| 1698 | components[offset+0] = (pixel & ((1<<nBits[0]) - 1)); | ||
| 1699 | return components; | ||
| 1700 | } | ||
| 1701 | |||
| 1702 | /** | ||
| 1703 | * Returns an array of unnormalized color/alpha components given a pixel | ||
| 1704 | * in this <CODE>ColorModel</CODE>. The pixel value is specified by an | ||
| 1705 | * array of data elements of type <CODE>transferType</CODE> passed in as | ||
| 1706 | * an object reference. | ||
| 1707 | * An IllegalArgumentException is thrown if the component values for this | ||
| 1708 | * <CODE>ColorModel</CODE> are not conveniently representable in the | ||
| 1709 | * unnormalized form. | ||
| 1710 | * Color/alpha components are stored in the <CODE>components</CODE> array | ||
| 1711 | * starting at <CODE>offset</CODE> (even if the array is allocated by | ||
| 1712 | * this method). Since <code>ComponentColorModel</code> can be | ||
| 1713 | * subclassed, subclasses inherit the | ||
| 1714 | * implementation of this method and if they don't override it then | ||
| 1715 | * this method might throw an exception if they use an unsupported | ||
| 1716 | * <code>transferType</code>. | ||
| 1717 | * | ||
| 1718 | * @param pixel A pixel value specified by an array of data elements of | ||
| 1719 | * type <CODE>transferType</CODE>. | ||
| 1720 | * @param components An integer array in which to store the unnormalized | ||
| 1721 | * color/alpha components. If the <CODE>components</CODE> array is null, | ||
| 1722 | * a new array is allocated. | ||
| 1723 | * @param offset An offset into the <CODE>components</CODE> array. | ||
| 1724 | * | ||
| 1725 | * @return The <CODE>components</CODE> array. | ||
| 1726 | * | ||
| 1727 | * @throws IllegalArgumentException If this | ||
| 1728 | * <CODE>ComponentColorModel</CODE> does not support the unnormalized form | ||
| 1729 | * @throws UnsupportedOperationException in some cases iff the | ||
| 1730 | * transfer type of this <CODE>ComponentColorModel</CODE> | ||
| 1731 | * is not one of the following transfer types: | ||
| 1732 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 1733 | * or <CODE>DataBuffer.TYPE_INT</CODE>. | ||
| 1734 | * @throws ClassCastException If <CODE>pixel</CODE> is not a primitive | ||
| 1735 | * array of type <CODE>transferType</CODE>. | ||
| 1736 | * @throws IllegalArgumentException If the <CODE>components</CODE> array is | ||
| 1737 | * not null and is not large enough to hold all the color and alpha | ||
| 1738 | * components (starting at offset), or if <CODE>pixel</CODE> is not large | ||
| 1739 | * enough to hold a pixel value for this ColorModel. | ||
| 1740 | */ | ||
| 1741 | public int[] getComponents(Object pixel, int[] components, int offset) { | ||
| 1742 | int intpixel[]; | ||
| 1743 | if (needScaleInit) { | ||
| 1744 | initScale(); | ||
| 1745 | } | ||
| 1746 | if (noUnnorm) { | ||
| 1747 | throw new | ||
| 1748 | IllegalArgumentException( | ||
| 1749 | "This ColorModel does not support the unnormalized form"); | ||
| 1750 | } | ||
| 1751 | if (pixel instanceof int[]) { | ||
| 1752 | intpixel = (int[])pixel; | ||
| 1753 | } else { | ||
| 1754 | intpixel = DataBuffer.toIntArray(pixel); | ||
| 1755 | if (intpixel == null) { | ||
| 1756 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 1757 | "implemented for transferType " + transferType); | ||
| 1758 | } | ||
| 1759 | } | ||
| 1760 | if (intpixel.length < numComponents) { | ||
| 1761 | throw new IllegalArgumentException | ||
| 1762 | ("Length of pixel array < number of components in model"); | ||
| 1763 | } | ||
| 1764 | if (components == null) { | ||
| 1765 | components = new int[offset+numComponents]; | ||
| 1766 | } | ||
| 1767 | else if ((components.length-offset) < numComponents) { | ||
| 1768 | throw new IllegalArgumentException | ||
| 1769 | ("Length of components array < number of components in model"); | ||
| 1770 | } | ||
| 1771 | System.arraycopy(intpixel, 0, components, offset, numComponents); | ||
| 1772 | |||
| 1773 | return components; | ||
| 1774 | } | ||
| 1775 | |||
| 1776 | /** | ||
| 1777 | * Returns an array of all of the color/alpha components in unnormalized | ||
| 1778 | * form, given a normalized component array. Unnormalized components | ||
| 1779 | * are unsigned integral values between 0 and 2<sup>n</sup> - 1, where | ||
| 1780 | * n is the number of bits for a particular component. Normalized | ||
| 1781 | * components are float values between a per component minimum and | ||
| 1782 | * maximum specified by the <code>ColorSpace</code> object for this | ||
| 1783 | * <code>ColorModel</code>. An <code>IllegalArgumentException</code> | ||
| 1784 | * will be thrown if color component values for this | ||
| 1785 | * <code>ColorModel</code> are not conveniently representable in the | ||
| 1786 | * unnormalized form. If the | ||
| 1787 | * <code>components</code> array is <code>null</code>, a new array | ||
| 1788 | * will be allocated. The <code>components</code> array will | ||
| 1789 | * be returned. Color/alpha components are stored in the | ||
| 1790 | * <code>components</code> array starting at <code>offset</code> (even | ||
| 1791 | * if the array is allocated by this method). An | ||
| 1792 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if the | ||
| 1793 | * <code>components</code> array is not <code>null</code> and is not | ||
| 1794 | * large enough to hold all the color and alpha | ||
| 1795 | * components (starting at <code>offset</code>). An | ||
| 1796 | * <code>IllegalArgumentException</code> is thrown if the | ||
| 1797 | * <code>normComponents</code> array is not large enough to hold | ||
| 1798 | * all the color and alpha components starting at | ||
| 1799 | * <code>normOffset</code>. | ||
| 1800 | * @param normComponents an array containing normalized components | ||
| 1801 | * @param normOffset the offset into the <code>normComponents</code> | ||
| 1802 | * array at which to start retrieving normalized components | ||
| 1803 | * @param components an array that receives the components from | ||
| 1804 | * <code>normComponents</code> | ||
| 1805 | * @param offset the index into <code>components</code> at which to | ||
| 1806 | * begin storing normalized components from | ||
| 1807 | * <code>normComponents</code> | ||
| 1808 | * @return an array containing unnormalized color and alpha | ||
| 1809 | * components. | ||
| 1810 | * @throws IllegalArgumentException If this | ||
| 1811 | * <CODE>ComponentColorModel</CODE> does not support the unnormalized form | ||
| 1812 | * @throws IllegalArgumentException if the length of | ||
| 1813 | * <code>normComponents</code> minus <code>normOffset</code> | ||
| 1814 | * is less than <code>numComponents</code> | ||
| 1815 | */ | ||
| 1816 | public int[] getUnnormalizedComponents(float[] normComponents, | ||
| 1817 | int normOffset, | ||
| 1818 | int[] components, int offset) { | ||
| 1819 | if (needScaleInit) { | ||
| 1820 | initScale(); | ||
| 1821 | } | ||
| 1822 | if (noUnnorm) { | ||
| 1823 | throw new | ||
| 1824 | IllegalArgumentException( | ||
| 1825 | "This ColorModel does not support the unnormalized form"); | ||
| 1826 | } | ||
| 1827 | return super.getUnnormalizedComponents(normComponents, normOffset, | ||
| 1828 | components, offset); | ||
| 1829 | } | ||
| 1830 | |||
| 1831 | /** | ||
| 1832 | * Returns an array of all of the color/alpha components in normalized | ||
| 1833 | * form, given an unnormalized component array. Unnormalized components | ||
| 1834 | * are unsigned integral values between 0 and 2<sup>n</sup> - 1, where | ||
| 1835 | * n is the number of bits for a particular component. Normalized | ||
| 1836 | * components are float values between a per component minimum and | ||
| 1837 | * maximum specified by the <code>ColorSpace</code> object for this | ||
| 1838 | * <code>ColorModel</code>. An <code>IllegalArgumentException</code> | ||
| 1839 | * will be thrown if color component values for this | ||
| 1840 | * <code>ColorModel</code> are not conveniently representable in the | ||
| 1841 | * unnormalized form. If the | ||
| 1842 | * <code>normComponents</code> array is <code>null</code>, a new array | ||
| 1843 | * will be allocated. The <code>normComponents</code> array | ||
| 1844 | * will be returned. Color/alpha components are stored in the | ||
| 1845 | * <code>normComponents</code> array starting at | ||
| 1846 | * <code>normOffset</code> (even if the array is allocated by this | ||
| 1847 | * method). An <code>ArrayIndexOutOfBoundsException</code> is thrown | ||
| 1848 | * if the <code>normComponents</code> array is not <code>null</code> | ||
| 1849 | * and is not large enough to hold all the color and alpha components | ||
| 1850 | * (starting at <code>normOffset</code>). An | ||
| 1851 | * <code>IllegalArgumentException</code> is thrown if the | ||
| 1852 | * <code>components</code> array is not large enough to hold all the | ||
| 1853 | * color and alpha components starting at <code>offset</code>. | ||
| 1854 | * @param components an array containing unnormalized components | ||
| 1855 | * @param offset the offset into the <code>components</code> array at | ||
| 1856 | * which to start retrieving unnormalized components | ||
| 1857 | * @param normComponents an array that receives the normalized components | ||
| 1858 | * @param normOffset the index into <code>normComponents</code> at | ||
| 1859 | * which to begin storing normalized components | ||
| 1860 | * @return an array containing normalized color and alpha | ||
| 1861 | * components. | ||
| 1862 | * @throws IllegalArgumentException If this | ||
| 1863 | * <CODE>ComponentColorModel</CODE> does not support the unnormalized form | ||
| 1864 | */ | ||
| 1865 | public float[] getNormalizedComponents(int[] components, int offset, | ||
| 1866 | float[] normComponents, | ||
| 1867 | int normOffset) { | ||
| 1868 | if (needScaleInit) { | ||
| 1869 | initScale(); | ||
| 1870 | } | ||
| 1871 | if (noUnnorm) { | ||
| 1872 | throw new | ||
| 1873 | IllegalArgumentException( | ||
| 1874 | "This ColorModel does not support the unnormalized form"); | ||
| 1875 | } | ||
| 1876 | return super.getNormalizedComponents(components, offset, | ||
| 1877 | normComponents, normOffset); | ||
| 1878 | } | ||
| 1879 | |||
| 1880 | /** | ||
| 1881 | * Returns a pixel value represented as an int in this <CODE>ColorModel</CODE>, | ||
| 1882 | * given an array of unnormalized color/alpha components. | ||
| 1883 | * | ||
| 1884 | * @param components An array of unnormalized color/alpha components. | ||
| 1885 | * @param offset An offset into the <CODE>components</CODE> array. | ||
| 1886 | * | ||
| 1887 | * @return A pixel value represented as an int. | ||
| 1888 | * | ||
| 1889 | * @throws IllegalArgumentException If there is more than one component | ||
| 1890 | * in this <CODE>ColorModel</CODE>. | ||
| 1891 | * @throws IllegalArgumentException If this | ||
| 1892 | * <CODE>ComponentColorModel</CODE> does not support the unnormalized form | ||
| 1893 | */ | ||
| 1894 | public int getDataElement(int[] components, int offset) { | ||
| 1895 | if (needScaleInit) { | ||
| 1896 | initScale(); | ||
| 1897 | } | ||
| 1898 | if (numComponents == 1) { | ||
| 1899 | if (noUnnorm) { | ||
| 1900 | throw new | ||
| 1901 | IllegalArgumentException( | ||
| 1902 | "This ColorModel does not support the unnormalized form"); | ||
| 1903 | } | ||
| 1904 | return components[offset+0]; | ||
| 1905 | } | ||
| 1906 | throw new IllegalArgumentException("This model returns "+ | ||
| 1907 | numComponents+ | ||
| 1908 | " elements in the pixel array."); | ||
| 1909 | } | ||
| 1910 | |||
| 1911 | /** | ||
| 1912 | * Returns a data element array representation of a pixel in this | ||
| 1913 | * <CODE>ColorModel</CODE>, given an array of unnormalized color/alpha | ||
| 1914 | * components. This array can then be passed to the <CODE>setDataElements</CODE> | ||
| 1915 | * method of a <CODE>WritableRaster</CODE> object. | ||
| 1916 | * | ||
| 1917 | * @param components An array of unnormalized color/alpha components. | ||
| 1918 | * @param offset The integer offset into the <CODE>components</CODE> array. | ||
| 1919 | * @param obj The object in which to store the data element array | ||
| 1920 | * representation of the pixel. If <CODE>obj</CODE> variable is null, | ||
| 1921 | * a new array is allocated. If <CODE>obj</CODE> is not null, it must | ||
| 1922 | * be a primitive array of type <CODE>transferType</CODE>. An | ||
| 1923 | * <CODE>ArrayIndexOutOfBoundsException</CODE> is thrown if | ||
| 1924 | * <CODE>obj</CODE> is not large enough to hold a pixel value | ||
| 1925 | * for this <CODE>ColorModel</CODE>. Since | ||
| 1926 | * <code>ComponentColorModel</code> can be subclassed, subclasses | ||
| 1927 | * inherit the implementation of this method and if they don't | ||
| 1928 | * override it then they throw an exception if they use an | ||
| 1929 | * unsupported <code>transferType</code>. | ||
| 1930 | * | ||
| 1931 | * @return The data element array representation of a pixel | ||
| 1932 | * in this <CODE>ColorModel</CODE>. | ||
| 1933 | * | ||
| 1934 | * @throws IllegalArgumentException If the components array | ||
| 1935 | * is not large enough to hold all the color and alpha components | ||
| 1936 | * (starting at offset). | ||
| 1937 | * @throws ClassCastException If <CODE>obj</CODE> is not null and is not a | ||
| 1938 | * primitive array of type <CODE>transferType</CODE>. | ||
| 1939 | * @throws ArrayIndexOutOfBoundsException If <CODE>obj</CODE> is not large | ||
| 1940 | * enough to hold a pixel value for this <CODE>ColorModel</CODE>. | ||
| 1941 | * @throws IllegalArgumentException If this | ||
| 1942 | * <CODE>ComponentColorModel</CODE> does not support the unnormalized form | ||
| 1943 | * @throws UnsupportedOperationException If the transfer type of | ||
| 1944 | * this <CODE>ComponentColorModel</CODE> | ||
| 1945 | * is not one of the following transfer types: | ||
| 1946 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 1947 | * or <CODE>DataBuffer.TYPE_INT</CODE>. | ||
| 1948 | * | ||
| 1949 | * @see WritableRaster#setDataElements | ||
| 1950 | * @see SampleModel#setDataElements | ||
| 1951 | */ | ||
| 1952 | public Object getDataElements(int[] components, int offset, Object obj) { | ||
| 1953 | if (needScaleInit) { | ||
| 1954 | initScale(); | ||
| 1955 | } | ||
| 1956 | if (noUnnorm) { | ||
| 1957 | throw new | ||
| 1958 | IllegalArgumentException( | ||
| 1959 | "This ColorModel does not support the unnormalized form"); | ||
| 1960 | } | ||
| 1961 | if ((components.length-offset) < numComponents) { | ||
| 1962 | throw new IllegalArgumentException("Component array too small"+ | ||
| 1963 | " (should be "+numComponents); | ||
| 1964 | } | ||
| 1965 | switch(transferType) { | ||
| 1966 | case DataBuffer.TYPE_INT: | ||
| 1967 | { | ||
| 1968 | int[] pixel; | ||
| 1969 | if (obj == null) { | ||
| 1970 | pixel = new int[numComponents]; | ||
| 1971 | } | ||
| 1972 | else { | ||
| 1973 | pixel = (int[]) obj; | ||
| 1974 | } | ||
| 1975 | System.arraycopy(components, offset, pixel, 0, | ||
| 1976 | numComponents); | ||
| 1977 | return pixel; | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | case DataBuffer.TYPE_BYTE: | ||
| 1981 | { | ||
| 1982 | byte[] pixel; | ||
| 1983 | if (obj == null) { | ||
| 1984 | pixel = new byte[numComponents]; | ||
| 1985 | } | ||
| 1986 | else { | ||
| 1987 | pixel = (byte[]) obj; | ||
| 1988 | } | ||
| 1989 | for (int i=0; i < numComponents; i++) { | ||
| 1990 | pixel[i] = (byte) (components[offset+i]&0xff); | ||
| 1991 | } | ||
| 1992 | return pixel; | ||
| 1993 | } | ||
| 1994 | |||
| 1995 | case DataBuffer.TYPE_USHORT: | ||
| 1996 | { | ||
| 1997 | short[] pixel; | ||
| 1998 | if (obj == null) { | ||
| 1999 | pixel = new short[numComponents]; | ||
| 2000 | } | ||
| 2001 | else { | ||
| 2002 | pixel = (short[]) obj; | ||
| 2003 | } | ||
| 2004 | for (int i=0; i < numComponents; i++) { | ||
| 2005 | pixel[i] = (short) (components[offset+i]&0xffff); | ||
| 2006 | } | ||
| 2007 | return pixel; | ||
| 2008 | } | ||
| 2009 | |||
| 2010 | default: | ||
| 2011 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 2012 | "implemented for transferType " + | ||
| 2013 | transferType); | ||
| 2014 | } | ||
| 2015 | } | ||
| 2016 | |||
| 2017 | /** | ||
| 2018 | * Returns a pixel value represented as an <code>int</code> in this | ||
| 2019 | * <code>ColorModel</code>, given an array of normalized color/alpha | ||
| 2020 | * components. This method will throw an | ||
| 2021 | * <code>IllegalArgumentException</code> if pixel values for this | ||
| 2022 | * <code>ColorModel</code> are not conveniently representable as a | ||
| 2023 | * single <code>int</code>. An | ||
| 2024 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if the | ||
| 2025 | * <code>normComponents</code> array is not large enough to hold all the | ||
| 2026 | * color and alpha components (starting at <code>normOffset</code>). | ||
| 2027 | * @param normComponents an array of normalized color and alpha | ||
| 2028 | * components | ||
| 2029 | * @param normOffset the index into <code>normComponents</code> at which to | ||
| 2030 | * begin retrieving the color and alpha components | ||
| 2031 | * @return an <code>int</code> pixel value in this | ||
| 2032 | * <code>ColorModel</code> corresponding to the specified components. | ||
| 2033 | * @throws IllegalArgumentException if | ||
| 2034 | * pixel values for this <code>ColorModel</code> are not | ||
| 2035 | * conveniently representable as a single <code>int</code> | ||
| 2036 | * @throws ArrayIndexOutOfBoundsException if | ||
| 2037 | * the <code>normComponents</code> array is not large enough to | ||
| 2038 | * hold all of the color and alpha components starting at | ||
| 2039 | * <code>normOffset</code> | ||
| 2040 | * @since 1.4 | ||
| 2041 | */ | ||
| 2042 | public int getDataElement(float[] normComponents, int normOffset) { | ||
| 2043 | if (numComponents > 1) { | ||
| 2044 | throw new | ||
| 2045 | IllegalArgumentException("More than one component per pixel"); | ||
| 2046 | } | ||
| 2047 | if (signed) { | ||
| 2048 | throw new | ||
| 2049 | IllegalArgumentException("Component value is signed"); | ||
| 2050 | } | ||
| 2051 | if (needScaleInit) { | ||
| 2052 | initScale(); | ||
| 2053 | } | ||
| 2054 | Object pixel = getDataElements(normComponents, normOffset, null); | ||
| 2055 | switch (transferType) { | ||
| 2056 | case DataBuffer.TYPE_BYTE: | ||
| 2057 | { | ||
| 2058 | byte bpixel[] = (byte[]) pixel; | ||
| 2059 | return bpixel[0] & 0xff; | ||
| 2060 | } | ||
| 2061 | case DataBuffer.TYPE_USHORT: | ||
| 2062 | { | ||
| 2063 | short[] uspixel = (short[]) pixel; | ||
| 2064 | return uspixel[0] & 0xffff; | ||
| 2065 | } | ||
| 2066 | case DataBuffer.TYPE_INT: | ||
| 2067 | { | ||
| 2068 | int[] ipixel = (int[]) pixel; | ||
| 2069 | return ipixel[0]; | ||
| 2070 | } | ||
| 2071 | default: | ||
| 2072 | throw new UnsupportedOperationException("This method has not been " | ||
| 2073 | + "implemented for transferType " + transferType); | ||
| 2074 | } | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | /** | ||
| 2078 | * Returns a data element array representation of a pixel in this | ||
| 2079 | * <code>ColorModel</code>, given an array of normalized color/alpha | ||
| 2080 | * components. This array can then be passed to the | ||
| 2081 | * <code>setDataElements</code> method of a <code>WritableRaster</code> | ||
| 2082 | * object. An <code>ArrayIndexOutOfBoundsException</code> is thrown | ||
| 2083 | * if the <code>normComponents</code> array is not large enough to hold | ||
| 2084 | * all the color and alpha components (starting at | ||
| 2085 | * <code>normOffset</code>). If the <code>obj</code> variable is | ||
| 2086 | * <code>null</code>, a new array will be allocated. If | ||
| 2087 | * <code>obj</code> is not <code>null</code>, it must be a primitive | ||
| 2088 | * array of type transferType; otherwise, a | ||
| 2089 | * <code>ClassCastException</code> is thrown. An | ||
| 2090 | * <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 2091 | * <code>obj</code> is not large enough to hold a pixel value for this | ||
| 2092 | * <code>ColorModel</code>. | ||
| 2093 | * @param normComponents an array of normalized color and alpha | ||
| 2094 | * components | ||
| 2095 | * @param normOffset the index into <code>normComponents</code> at which to | ||
| 2096 | * begin retrieving color and alpha components | ||
| 2097 | * @param obj a primitive data array to hold the returned pixel | ||
| 2098 | * @return an <code>Object</code> which is a primitive data array | ||
| 2099 | * representation of a pixel | ||
| 2100 | * @throws ClassCastException if <code>obj</code> | ||
| 2101 | * is not a primitive array of type <code>transferType</code> | ||
| 2102 | * @throws ArrayIndexOutOfBoundsException if | ||
| 2103 | * <code>obj</code> is not large enough to hold a pixel value | ||
| 2104 | * for this <code>ColorModel</code> or the <code>normComponents</code> | ||
| 2105 | * array is not large enough to hold all of the color and alpha | ||
| 2106 | * components starting at <code>normOffset</code> | ||
| 2107 | * @see WritableRaster#setDataElements | ||
| 2108 | * @see SampleModel#setDataElements | ||
| 2109 | * @since 1.4 | ||
| 2110 | */ | ||
| 2111 | public Object getDataElements(float[] normComponents, int normOffset, | ||
| 2112 | Object obj) { | ||
| 2113 | boolean needAlpha = supportsAlpha && isAlphaPremultiplied; | ||
| 2114 | float[] stdNormComponents; | ||
| 2115 | if (needScaleInit) { | ||
| 2116 | initScale(); | ||
| 2117 | } | ||
| 2118 | if (nonStdScale) { | ||
| 2119 | stdNormComponents = new float[numComponents]; | ||
| 2120 | for (int c = 0, nc = normOffset; c < numColorComponents; | ||
| 2121 | c++, nc++) { | ||
| 2122 | stdNormComponents[c] = (normComponents[nc] - compOffset[c]) * | ||
| 2123 | compScale[c]; | ||
| 2124 | // REMIND: need to analyze whether this | ||
| 2125 | // clamping is necessary | ||
| 2126 | if (stdNormComponents[c] < 0.0f) { | ||
| 2127 | stdNormComponents[c] = 0.0f; | ||
| 2128 | } | ||
| 2129 | if (stdNormComponents[c] > 1.0f) { | ||
| 2130 | stdNormComponents[c] = 1.0f; | ||
| 2131 | } | ||
| 2132 | } | ||
| 2133 | if (supportsAlpha) { | ||
| 2134 | stdNormComponents[numColorComponents] = | ||
| 2135 | normComponents[numColorComponents + normOffset]; | ||
| 2136 | } | ||
| 2137 | normOffset = 0; | ||
| 2138 | } else { | ||
| 2139 | stdNormComponents = normComponents; | ||
| 2140 | } | ||
| 2141 | switch (transferType) { | ||
| 2142 | case DataBuffer.TYPE_BYTE: | ||
| 2143 | byte[] bpixel; | ||
| 2144 | if (obj == null) { | ||
| 2145 | bpixel = new byte[numComponents]; | ||
| 2146 | } else { | ||
| 2147 | bpixel = (byte[]) obj; | ||
| 2148 | } | ||
| 2149 | if (needAlpha) { | ||
| 2150 | float alpha = | ||
| 2151 | stdNormComponents[numColorComponents + normOffset]; | ||
| 2152 | for (int c = 0, nc = normOffset; c < numColorComponents; | ||
| 2153 | c++, nc++) { | ||
| 2154 | bpixel[c] = (byte) ((stdNormComponents[nc] * alpha) * | ||
| 2155 | ((float) ((1 << nBits[c]) - 1)) + 0.5f); | ||
| 2156 | } | ||
| 2157 | bpixel[numColorComponents] = | ||
| 2158 | (byte) (alpha * | ||
| 2159 | ((float) ((1 << nBits[numColorComponents]) - 1)) + | ||
| 2160 | 0.5f); | ||
| 2161 | } else { | ||
| 2162 | for (int c = 0, nc = normOffset; c < numComponents; | ||
| 2163 | c++, nc++) { | ||
| 2164 | bpixel[c] = (byte) (stdNormComponents[nc] * | ||
| 2165 | ((float) ((1 << nBits[c]) - 1)) + 0.5f); | ||
| 2166 | } | ||
| 2167 | } | ||
| 2168 | return bpixel; | ||
| 2169 | case DataBuffer.TYPE_USHORT: | ||
| 2170 | short[] uspixel; | ||
| 2171 | if (obj == null) { | ||
| 2172 | uspixel = new short[numComponents]; | ||
| 2173 | } else { | ||
| 2174 | uspixel = (short[]) obj; | ||
| 2175 | } | ||
| 2176 | if (needAlpha) { | ||
| 2177 | float alpha = | ||
| 2178 | stdNormComponents[numColorComponents + normOffset]; | ||
| 2179 | for (int c = 0, nc = normOffset; c < numColorComponents; | ||
| 2180 | c++, nc++) { | ||
| 2181 | uspixel[c] = (short) ((stdNormComponents[nc] * alpha) * | ||
| 2182 | ((float) ((1 << nBits[c]) - 1)) + | ||
| 2183 | 0.5f); | ||
| 2184 | } | ||
| 2185 | uspixel[numColorComponents] = | ||
| 2186 | (short) (alpha * | ||
| 2187 | ((float) ((1 << nBits[numColorComponents]) - 1)) + | ||
| 2188 | 0.5f); | ||
| 2189 | } else { | ||
| 2190 | for (int c = 0, nc = normOffset; c < numComponents; | ||
| 2191 | c++, nc++) { | ||
| 2192 | uspixel[c] = (short) (stdNormComponents[nc] * | ||
| 2193 | ((float) ((1 << nBits[c]) - 1)) + | ||
| 2194 | 0.5f); | ||
| 2195 | } | ||
| 2196 | } | ||
| 2197 | return uspixel; | ||
| 2198 | case DataBuffer.TYPE_INT: | ||
| 2199 | int[] ipixel; | ||
| 2200 | if (obj == null) { | ||
| 2201 | ipixel = new int[numComponents]; | ||
| 2202 | } else { | ||
| 2203 | ipixel = (int[]) obj; | ||
| 2204 | } | ||
| 2205 | if (needAlpha) { | ||
| 2206 | float alpha = | ||
| 2207 | stdNormComponents[numColorComponents + normOffset]; | ||
| 2208 | for (int c = 0, nc = normOffset; c < numColorComponents; | ||
| 2209 | c++, nc++) { | ||
| 2210 | ipixel[c] = (int) ((stdNormComponents[nc] * alpha) * | ||
| 2211 | ((float) ((1 << nBits[c]) - 1)) + 0.5f); | ||
| 2212 | } | ||
| 2213 | ipixel[numColorComponents] = | ||
| 2214 | (int) (alpha * | ||
| 2215 | ((float) ((1 << nBits[numColorComponents]) - 1)) + | ||
| 2216 | 0.5f); | ||
| 2217 | } else { | ||
| 2218 | for (int c = 0, nc = normOffset; c < numComponents; | ||
| 2219 | c++, nc++) { | ||
| 2220 | ipixel[c] = (int) (stdNormComponents[nc] * | ||
| 2221 | ((float) ((1 << nBits[c]) - 1)) + 0.5f); | ||
| 2222 | } | ||
| 2223 | } | ||
| 2224 | return ipixel; | ||
| 2225 | case DataBuffer.TYPE_SHORT: | ||
| 2226 | short[] spixel; | ||
| 2227 | if (obj == null) { | ||
| 2228 | spixel = new short[numComponents]; | ||
| 2229 | } else { | ||
| 2230 | spixel = (short[]) obj; | ||
| 2231 | } | ||
| 2232 | if (needAlpha) { | ||
| 2233 | float alpha = | ||
| 2234 | stdNormComponents[numColorComponents + normOffset]; | ||
| 2235 | for (int c = 0, nc = normOffset; c < numColorComponents; | ||
| 2236 | c++, nc++) { | ||
| 2237 | spixel[c] = (short) | ||
| 2238 | (stdNormComponents[nc] * alpha * 32767.0f + 0.5f); | ||
| 2239 | } | ||
| 2240 | spixel[numColorComponents] = (short) (alpha * 32767.0f + 0.5f); | ||
| 2241 | } else { | ||
| 2242 | for (int c = 0, nc = normOffset; c < numComponents; | ||
| 2243 | c++, nc++) { | ||
| 2244 | spixel[c] = (short) | ||
| 2245 | (stdNormComponents[nc] * 32767.0f + 0.5f); | ||
| 2246 | } | ||
| 2247 | } | ||
| 2248 | return spixel; | ||
| 2249 | case DataBuffer.TYPE_FLOAT: | ||
| 2250 | float[] fpixel; | ||
| 2251 | if (obj == null) { | ||
| 2252 | fpixel = new float[numComponents]; | ||
| 2253 | } else { | ||
| 2254 | fpixel = (float[]) obj; | ||
| 2255 | } | ||
| 2256 | if (needAlpha) { | ||
| 2257 | float alpha = normComponents[numColorComponents + normOffset]; | ||
| 2258 | for (int c = 0, nc = normOffset; c < numColorComponents; | ||
| 2259 | c++, nc++) { | ||
| 2260 | fpixel[c] = normComponents[nc] * alpha; | ||
| 2261 | } | ||
| 2262 | fpixel[numColorComponents] = alpha; | ||
| 2263 | } else { | ||
| 2264 | for (int c = 0, nc = normOffset; c < numComponents; | ||
| 2265 | c++, nc++) { | ||
| 2266 | fpixel[c] = normComponents[nc]; | ||
| 2267 | } | ||
| 2268 | } | ||
| 2269 | return fpixel; | ||
| 2270 | case DataBuffer.TYPE_DOUBLE: | ||
| 2271 | double[] dpixel; | ||
| 2272 | if (obj == null) { | ||
| 2273 | dpixel = new double[numComponents]; | ||
| 2274 | } else { | ||
| 2275 | dpixel = (double[]) obj; | ||
| 2276 | } | ||
| 2277 | if (needAlpha) { | ||
| 2278 | double alpha = | ||
| 2279 | (double) (normComponents[numColorComponents + normOffset]); | ||
| 2280 | for (int c = 0, nc = normOffset; c < numColorComponents; | ||
| 2281 | c++, nc++) { | ||
| 2282 | dpixel[c] = normComponents[nc] * alpha; | ||
| 2283 | } | ||
| 2284 | dpixel[numColorComponents] = alpha; | ||
| 2285 | } else { | ||
| 2286 | for (int c = 0, nc = normOffset; c < numComponents; | ||
| 2287 | c++, nc++) { | ||
| 2288 | dpixel[c] = (double) normComponents[nc]; | ||
| 2289 | } | ||
| 2290 | } | ||
| 2291 | return dpixel; | ||
| 2292 | default: | ||
| 2293 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 2294 | "implemented for transferType " + | ||
| 2295 | transferType); | ||
| 2296 | } | ||
| 2297 | } | ||
| 2298 | |||
| 2299 | /** | ||
| 2300 | * Returns an array of all of the color/alpha components in normalized | ||
| 2301 | * form, given a pixel in this <code>ColorModel</code>. The pixel | ||
| 2302 | * value is specified by an array of data elements of type transferType | ||
| 2303 | * passed in as an object reference. If pixel is not a primitive array | ||
| 2304 | * of type transferType, a <code>ClassCastException</code> is thrown. | ||
| 2305 | * An <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 2306 | * <code>pixel</code> is not large enough to hold a pixel value for this | ||
| 2307 | * <code>ColorModel</code>. | ||
| 2308 | * Normalized components are float values between a per component minimum | ||
| 2309 | * and maximum specified by the <code>ColorSpace</code> object for this | ||
| 2310 | * <code>ColorModel</code>. If the | ||
| 2311 | * <code>normComponents</code> array is <code>null</code>, a new array | ||
| 2312 | * will be allocated. The <code>normComponents</code> array | ||
| 2313 | * will be returned. Color/alpha components are stored in the | ||
| 2314 | * <code>normComponents</code> array starting at | ||
| 2315 | * <code>normOffset</code> (even if the array is allocated by this | ||
| 2316 | * method). An <code>ArrayIndexOutOfBoundsException</code> is thrown | ||
| 2317 | * if the <code>normComponents</code> array is not <code>null</code> | ||
| 2318 | * and is not large enough to hold all the color and alpha components | ||
| 2319 | * (starting at <code>normOffset</code>). | ||
| 2320 | * <p> | ||
| 2321 | * This method must be overrridden by a subclass if that subclass | ||
| 2322 | * is designed to translate pixel sample values to color component values | ||
| 2323 | * in a non-default way. The default translations implemented by this | ||
| 2324 | * class is described in the class comments. Any subclass implementing | ||
| 2325 | * a non-default translation must follow the constraints on allowable | ||
| 2326 | * translations defined there. | ||
| 2327 | * @param pixel the specified pixel | ||
| 2328 | * @param normComponents an array to receive the normalized components | ||
| 2329 | * @param normOffset the offset into the <code>normComponents</code> | ||
| 2330 | * array at which to start storing normalized components | ||
| 2331 | * @return an array containing normalized color and alpha | ||
| 2332 | * components. | ||
| 2333 | * @throws ClassCastException if <code>pixel</code> is not a primitive | ||
| 2334 | * array of type transferType | ||
| 2335 | * @throws ArrayIndexOutOfBoundsException if | ||
| 2336 | * <code>normComponents</code> is not large enough to hold all | ||
| 2337 | * color and alpha components starting at <code>normOffset</code> | ||
| 2338 | * @throws ArrayIndexOutOfBoundsException if | ||
| 2339 | * <code>pixel</code> is not large enough to hold a pixel | ||
| 2340 | * value for this <code>ColorModel</code>. | ||
| 2341 | * @since 1.4 | ||
| 2342 | */ | ||
| 2343 | public float[] getNormalizedComponents(Object pixel, | ||
| 2344 | float[] normComponents, | ||
| 2345 | int normOffset) { | ||
| 2346 | if (normComponents == null) { | ||
| 2347 | normComponents = new float[numComponents+normOffset]; | ||
| 2348 | } | ||
| 2349 | switch (transferType) { | ||
| 2350 | case DataBuffer.TYPE_BYTE: | ||
| 2351 | byte[] bpixel = (byte[]) pixel; | ||
| 2352 | for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { | ||
| 2353 | normComponents[nc] = ((float) (bpixel[c] & 0xff)) / | ||
| 2354 | ((float) ((1 << nBits[c]) - 1)); | ||
| 2355 | } | ||
| 2356 | break; | ||
| 2357 | case DataBuffer.TYPE_USHORT: | ||
| 2358 | short[] uspixel = (short[]) pixel; | ||
| 2359 | for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { | ||
| 2360 | normComponents[nc] = ((float) (uspixel[c] & 0xffff)) / | ||
| 2361 | ((float) ((1 << nBits[c]) - 1)); | ||
| 2362 | } | ||
| 2363 | break; | ||
| 2364 | case DataBuffer.TYPE_INT: | ||
| 2365 | int[] ipixel = (int[]) pixel; | ||
| 2366 | for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { | ||
| 2367 | normComponents[nc] = ((float) ipixel[c]) / | ||
| 2368 | ((float) ((1 << nBits[c]) - 1)); | ||
| 2369 | } | ||
| 2370 | break; | ||
| 2371 | case DataBuffer.TYPE_SHORT: | ||
| 2372 | short[] spixel = (short[]) pixel; | ||
| 2373 | for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { | ||
| 2374 | normComponents[nc] = ((float) spixel[c]) / 32767.0f; | ||
| 2375 | } | ||
| 2376 | break; | ||
| 2377 | case DataBuffer.TYPE_FLOAT: | ||
| 2378 | float[] fpixel = (float[]) pixel; | ||
| 2379 | for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { | ||
| 2380 | normComponents[nc] = fpixel[c]; | ||
| 2381 | } | ||
| 2382 | break; | ||
| 2383 | case DataBuffer.TYPE_DOUBLE: | ||
| 2384 | double[] dpixel = (double[]) pixel; | ||
| 2385 | for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { | ||
| 2386 | normComponents[nc] = (float) dpixel[c]; | ||
| 2387 | } | ||
| 2388 | break; | ||
| 2389 | default: | ||
| 2390 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 2391 | "implemented for transferType " + | ||
| 2392 | transferType); | ||
| 2393 | } | ||
| 2394 | |||
| 2395 | if (supportsAlpha && isAlphaPremultiplied) { | ||
| 2396 | float alpha = normComponents[numColorComponents + normOffset]; | ||
| 2397 | if (alpha != 0.0f) { | ||
| 2398 | float invAlpha = 1.0f / alpha; | ||
| 2399 | for (int c = normOffset; c < numColorComponents + normOffset; | ||
| 2400 | c++) { | ||
| 2401 | normComponents[c] *= invAlpha; | ||
| 2402 | } | ||
| 2403 | } | ||
| 2404 | } | ||
| 2405 | if (min != null) { | ||
| 2406 | // Normally (i.e. when this class is not subclassed to override | ||
| 2407 | // this method), the test (min != null) will be equivalent to | ||
| 2408 | // the test (nonStdScale). However, there is an unlikely, but | ||
| 2409 | // possible case, in which this method is overridden, nonStdScale | ||
| 2410 | // is set true by initScale(), the subclass method for some | ||
| 2411 | // reason calls this superclass method, but the min and | ||
| 2412 | // diffMinMax arrays were never initialized by setupLUTs(). In | ||
| 2413 | // that case, the right thing to do is follow the intended | ||
| 2414 | // semantics of this method, and rescale the color components | ||
| 2415 | // only if the ColorSpace min/max were detected to be other | ||
| 2416 | // than 0.0/1.0 by setupLUTs(). Note that this implies the | ||
| 2417 | // transferType is byte, ushort, int, or short - i.e. components | ||
| 2418 | // derived from float and double pixel data are never rescaled. | ||
| 2419 | for (int c = 0; c < numColorComponents; c++) { | ||
| 2420 | normComponents[c + normOffset] = min[c] + | ||
| 2421 | diffMinMax[c] * normComponents[c + normOffset]; | ||
| 2422 | } | ||
| 2423 | } | ||
| 2424 | return normComponents; | ||
| 2425 | } | ||
| 2426 | |||
| 2427 | /** | ||
| 2428 | * Forces the raster data to match the state specified in the | ||
| 2429 | * <CODE>isAlphaPremultiplied</CODE> variable, assuming the data | ||
| 2430 | * is currently correctly described by this <CODE>ColorModel</CODE>. | ||
| 2431 | * It may multiply or divide the color raster data by alpha, or | ||
| 2432 | * do nothing if the data is in the correct state. If the data needs | ||
| 2433 | * to be coerced, this method also returns an instance of | ||
| 2434 | * this <CODE>ColorModel</CODE> with | ||
| 2435 | * the <CODE>isAlphaPremultiplied</CODE> flag set appropriately. | ||
| 2436 | * Since <code>ColorModel</code> can be subclassed, subclasses inherit | ||
| 2437 | * the implementation of this method and if they don't override it | ||
| 2438 | * then they throw an exception if they use an unsupported | ||
| 2439 | * <code>transferType</code>. | ||
| 2440 | * | ||
| 2441 | * @throws NullPointerException if <code>raster</code> is | ||
| 2442 | * <code>null</code> and data coercion is required. | ||
| 2443 | * @throws UnsupportedOperationException if the transfer type of | ||
| 2444 | * this <CODE>ComponentColorModel</CODE> | ||
| 2445 | * is not one of the supported transfer types: | ||
| 2446 | * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>, | ||
| 2447 | * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>, | ||
| 2448 | * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>. | ||
| 2449 | */ | ||
| 2450 | public ColorModel coerceData (WritableRaster raster, | ||
| 2451 | boolean isAlphaPremultiplied) { | ||
| 2452 | if ((supportsAlpha == false) || | ||
| 2453 | (this.isAlphaPremultiplied == isAlphaPremultiplied)) | ||
| 2454 | { | ||
| 2455 | // Nothing to do | ||
| 2456 | return this; | ||
| 2457 | } | ||
| 2458 | |||
| 2459 | int w = raster.getWidth(); | ||
| 2460 | int h = raster.getHeight(); | ||
| 2461 | int aIdx = raster.getNumBands() - 1; | ||
| 2462 | float normAlpha; | ||
| 2463 | int rminX = raster.getMinX(); | ||
| 2464 | int rY = raster.getMinY(); | ||
| 2465 | int rX; | ||
| 2466 | if (isAlphaPremultiplied) { | ||
| 2467 | switch (transferType) { | ||
| 2468 | case DataBuffer.TYPE_BYTE: { | ||
| 2469 | byte pixel[] = null; | ||
| 2470 | byte zpixel[] = null; | ||
| 2471 | float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); | ||
| 2472 | for (int y = 0; y < h; y++, rY++) { | ||
| 2473 | rX = rminX; | ||
| 2474 | for (int x = 0; x < w; x++, rX++) { | ||
| 2475 | pixel = (byte[])raster.getDataElements(rX, rY, | ||
| 2476 | pixel); | ||
| 2477 | normAlpha = (pixel[aIdx] & 0xff) * alphaScale; | ||
| 2478 | if (normAlpha != 0.0f) { | ||
| 2479 | for (int c=0; c < aIdx; c++) { | ||
| 2480 | pixel[c] = (byte)((pixel[c] & 0xff) * | ||
| 2481 | normAlpha + 0.5f); | ||
| 2482 | } | ||
| 2483 | raster.setDataElements(rX, rY, pixel); | ||
| 2484 | } else { | ||
| 2485 | if (zpixel == null) { | ||
| 2486 | zpixel = new byte[numComponents]; | ||
| 2487 | java.util.Arrays.fill(zpixel, (byte) 0); | ||
| 2488 | } | ||
| 2489 | raster.setDataElements(rX, rY, zpixel); | ||
| 2490 | } | ||
| 2491 | } | ||
| 2492 | } | ||
| 2493 | } | ||
| 2494 | break; | ||
| 2495 | case DataBuffer.TYPE_USHORT: { | ||
| 2496 | short pixel[] = null; | ||
| 2497 | short zpixel[] = null; | ||
| 2498 | float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); | ||
| 2499 | for (int y = 0; y < h; y++, rY++) { | ||
| 2500 | rX = rminX; | ||
| 2501 | for (int x = 0; x < w; x++, rX++) { | ||
| 2502 | pixel = (short[])raster.getDataElements(rX, rY, | ||
| 2503 | pixel); | ||
| 2504 | normAlpha = (pixel[aIdx] & 0xffff) * alphaScale; | ||
| 2505 | if (normAlpha != 0.0f) { | ||
| 2506 | for (int c=0; c < aIdx; c++) { | ||
| 2507 | pixel[c] = (short) | ||
| 2508 | ((pixel[c] & 0xffff) * normAlpha + | ||
| 2509 | 0.5f); | ||
| 2510 | } | ||
| 2511 | raster.setDataElements(rX, rY, pixel); | ||
| 2512 | } else { | ||
| 2513 | if (zpixel == null) { | ||
| 2514 | zpixel = new short[numComponents]; | ||
| 2515 | java.util.Arrays.fill(zpixel, (short) 0); | ||
| 2516 | } | ||
| 2517 | raster.setDataElements(rX, rY, zpixel); | ||
| 2518 | } | ||
| 2519 | } | ||
| 2520 | } | ||
| 2521 | } | ||
| 2522 | break; | ||
| 2523 | case DataBuffer.TYPE_INT: { | ||
| 2524 | int pixel[] = null; | ||
| 2525 | int zpixel[] = null; | ||
| 2526 | float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); | ||
| 2527 | for (int y = 0; y < h; y++, rY++) { | ||
| 2528 | rX = rminX; | ||
| 2529 | for (int x = 0; x < w; x++, rX++) { | ||
| 2530 | pixel = (int[])raster.getDataElements(rX, rY, | ||
| 2531 | pixel); | ||
| 2532 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 2533 | if (normAlpha != 0.0f) { | ||
| 2534 | for (int c=0; c < aIdx; c++) { | ||
| 2535 | pixel[c] = (int) (pixel[c] * normAlpha + | ||
| 2536 | 0.5f); | ||
| 2537 | } | ||
| 2538 | raster.setDataElements(rX, rY, pixel); | ||
| 2539 | } else { | ||
| 2540 | if (zpixel == null) { | ||
| 2541 | zpixel = new int[numComponents]; | ||
| 2542 | java.util.Arrays.fill(zpixel, 0); | ||
| 2543 | } | ||
| 2544 | raster.setDataElements(rX, rY, zpixel); | ||
| 2545 | } | ||
| 2546 | } | ||
| 2547 | } | ||
| 2548 | } | ||
| 2549 | break; | ||
| 2550 | case DataBuffer.TYPE_SHORT: { | ||
| 2551 | short pixel[] = null; | ||
| 2552 | short zpixel[] = null; | ||
| 2553 | float alphaScale = 1.0f / 32767.0f; | ||
| 2554 | for (int y = 0; y < h; y++, rY++) { | ||
| 2555 | rX = rminX; | ||
| 2556 | for (int x = 0; x < w; x++, rX++) { | ||
| 2557 | pixel = (short[]) raster.getDataElements(rX, rY, | ||
| 2558 | pixel); | ||
| 2559 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 2560 | if (normAlpha != 0.0f) { | ||
| 2561 | for (int c=0; c < aIdx; c++) { | ||
| 2562 | pixel[c] = (short) (pixel[c] * normAlpha + | ||
| 2563 | 0.5f); | ||
| 2564 | } | ||
| 2565 | raster.setDataElements(rX, rY, pixel); | ||
| 2566 | } else { | ||
| 2567 | if (zpixel == null) { | ||
| 2568 | zpixel = new short[numComponents]; | ||
| 2569 | java.util.Arrays.fill(zpixel, (short) 0); | ||
| 2570 | } | ||
| 2571 | raster.setDataElements(rX, rY, zpixel); | ||
| 2572 | } | ||
| 2573 | } | ||
| 2574 | } | ||
| 2575 | } | ||
| 2576 | break; | ||
| 2577 | case DataBuffer.TYPE_FLOAT: { | ||
| 2578 | float pixel[] = null; | ||
| 2579 | float zpixel[] = null; | ||
| 2580 | for (int y = 0; y < h; y++, rY++) { | ||
| 2581 | rX = rminX; | ||
| 2582 | for (int x = 0; x < w; x++, rX++) { | ||
| 2583 | pixel = (float[]) raster.getDataElements(rX, rY, | ||
| 2584 | pixel); | ||
| 2585 | normAlpha = pixel[aIdx]; | ||
| 2586 | if (normAlpha != 0.0f) { | ||
| 2587 | for (int c=0; c < aIdx; c++) { | ||
| 2588 | pixel[c] *= normAlpha; | ||
| 2589 | } | ||
| 2590 | raster.setDataElements(rX, rY, pixel); | ||
| 2591 | } else { | ||
| 2592 | if (zpixel == null) { | ||
| 2593 | zpixel = new float[numComponents]; | ||
| 2594 | java.util.Arrays.fill(zpixel, 0.0f); | ||
| 2595 | } | ||
| 2596 | raster.setDataElements(rX, rY, zpixel); | ||
| 2597 | } | ||
| 2598 | } | ||
| 2599 | } | ||
| 2600 | } | ||
| 2601 | break; | ||
| 2602 | case DataBuffer.TYPE_DOUBLE: { | ||
| 2603 | double pixel[] = null; | ||
| 2604 | double zpixel[] = null; | ||
| 2605 | for (int y = 0; y < h; y++, rY++) { | ||
| 2606 | rX = rminX; | ||
| 2607 | for (int x = 0; x < w; x++, rX++) { | ||
| 2608 | pixel = (double[]) raster.getDataElements(rX, rY, | ||
| 2609 | pixel); | ||
| 2610 | double dnormAlpha = pixel[aIdx]; | ||
| 2611 | if (dnormAlpha != 0.0) { | ||
| 2612 | for (int c=0; c < aIdx; c++) { | ||
| 2613 | pixel[c] *= dnormAlpha; | ||
| 2614 | } | ||
| 2615 | raster.setDataElements(rX, rY, pixel); | ||
| 2616 | } else { | ||
| 2617 | if (zpixel == null) { | ||
| 2618 | zpixel = new double[numComponents]; | ||
| 2619 | java.util.Arrays.fill(zpixel, 0.0); | ||
| 2620 | } | ||
| 2621 | raster.setDataElements(rX, rY, zpixel); | ||
| 2622 | } | ||
| 2623 | } | ||
| 2624 | } | ||
| 2625 | } | ||
| 2626 | break; | ||
| 2627 | default: | ||
| 2628 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 2629 | "implemented for transferType " + transferType); | ||
| 2630 | } | ||
| 2631 | } | ||
| 2632 | else { | ||
| 2633 | // We are premultiplied and want to divide it out | ||
| 2634 | switch (transferType) { | ||
| 2635 | case DataBuffer.TYPE_BYTE: { | ||
| 2636 | byte pixel[] = null; | ||
| 2637 | float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); | ||
| 2638 | for (int y = 0; y < h; y++, rY++) { | ||
| 2639 | rX = rminX; | ||
| 2640 | for (int x = 0; x < w; x++, rX++) { | ||
| 2641 | pixel = (byte[])raster.getDataElements(rX, rY, | ||
| 2642 | pixel); | ||
| 2643 | normAlpha = (pixel[aIdx] & 0xff) * alphaScale; | ||
| 2644 | if (normAlpha != 0.0f) { | ||
| 2645 | float invAlpha = 1.0f / normAlpha; | ||
| 2646 | for (int c=0; c < aIdx; c++) { | ||
| 2647 | pixel[c] = (byte) | ||
| 2648 | ((pixel[c] & 0xff) * invAlpha + 0.5f); | ||
| 2649 | } | ||
| 2650 | raster.setDataElements(rX, rY, pixel); | ||
| 2651 | } | ||
| 2652 | } | ||
| 2653 | } | ||
| 2654 | } | ||
| 2655 | break; | ||
| 2656 | case DataBuffer.TYPE_USHORT: { | ||
| 2657 | short pixel[] = null; | ||
| 2658 | float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); | ||
| 2659 | for (int y = 0; y < h; y++, rY++) { | ||
| 2660 | rX = rminX; | ||
| 2661 | for (int x = 0; x < w; x++, rX++) { | ||
| 2662 | pixel = (short[])raster.getDataElements(rX, rY, | ||
| 2663 | pixel); | ||
| 2664 | normAlpha = (pixel[aIdx] & 0xffff) * alphaScale; | ||
| 2665 | if (normAlpha != 0.0f) { | ||
| 2666 | float invAlpha = 1.0f / normAlpha; | ||
| 2667 | for (int c=0; c < aIdx; c++) { | ||
| 2668 | pixel[c] = (short) | ||
| 2669 | ((pixel[c] & 0xffff) * invAlpha + 0.5f); | ||
| 2670 | } | ||
| 2671 | raster.setDataElements(rX, rY, pixel); | ||
| 2672 | } | ||
| 2673 | } | ||
| 2674 | } | ||
| 2675 | } | ||
| 2676 | break; | ||
| 2677 | case DataBuffer.TYPE_INT: { | ||
| 2678 | int pixel[] = null; | ||
| 2679 | float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); | ||
| 2680 | for (int y = 0; y < h; y++, rY++) { | ||
| 2681 | rX = rminX; | ||
| 2682 | for (int x = 0; x < w; x++, rX++) { | ||
| 2683 | pixel = (int[])raster.getDataElements(rX, rY, | ||
| 2684 | pixel); | ||
| 2685 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 2686 | if (normAlpha != 0.0f) { | ||
| 2687 | float invAlpha = 1.0f / normAlpha; | ||
| 2688 | for (int c=0; c < aIdx; c++) { | ||
| 2689 | pixel[c] = (int) | ||
| 2690 | (pixel[c] * invAlpha + 0.5f); | ||
| 2691 | } | ||
| 2692 | raster.setDataElements(rX, rY, pixel); | ||
| 2693 | } | ||
| 2694 | } | ||
| 2695 | } | ||
| 2696 | } | ||
| 2697 | break; | ||
| 2698 | case DataBuffer.TYPE_SHORT: { | ||
| 2699 | short pixel[] = null; | ||
| 2700 | float alphaScale = 1.0f / 32767.0f; | ||
| 2701 | for (int y = 0; y < h; y++, rY++) { | ||
| 2702 | rX = rminX; | ||
| 2703 | for (int x = 0; x < w; x++, rX++) { | ||
| 2704 | pixel = (short[])raster.getDataElements(rX, rY, | ||
| 2705 | pixel); | ||
| 2706 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 2707 | if (normAlpha != 0.0f) { | ||
| 2708 | float invAlpha = 1.0f / normAlpha; | ||
| 2709 | for (int c=0; c < aIdx; c++) { | ||
| 2710 | pixel[c] = (short) | ||
| 2711 | (pixel[c] * invAlpha + 0.5f); | ||
| 2712 | } | ||
| 2713 | raster.setDataElements(rX, rY, pixel); | ||
| 2714 | } | ||
| 2715 | } | ||
| 2716 | } | ||
| 2717 | } | ||
| 2718 | break; | ||
| 2719 | case DataBuffer.TYPE_FLOAT: { | ||
| 2720 | float pixel[] = null; | ||
| 2721 | for (int y = 0; y < h; y++, rY++) { | ||
| 2722 | rX = rminX; | ||
| 2723 | for (int x = 0; x < w; x++, rX++) { | ||
| 2724 | pixel = (float[])raster.getDataElements(rX, rY, | ||
| 2725 | pixel); | ||
| 2726 | normAlpha = pixel[aIdx]; | ||
| 2727 | if (normAlpha != 0.0f) { | ||
| 2728 | float invAlpha = 1.0f / normAlpha; | ||
| 2729 | for (int c=0; c < aIdx; c++) { | ||
| 2730 | pixel[c] *= invAlpha; | ||
| 2731 | } | ||
| 2732 | raster.setDataElements(rX, rY, pixel); | ||
| 2733 | } | ||
| 2734 | } | ||
| 2735 | } | ||
| 2736 | } | ||
| 2737 | break; | ||
| 2738 | case DataBuffer.TYPE_DOUBLE: { | ||
| 2739 | double pixel[] = null; | ||
| 2740 | for (int y = 0; y < h; y++, rY++) { | ||
| 2741 | rX = rminX; | ||
| 2742 | for (int x = 0; x < w; x++, rX++) { | ||
| 2743 | pixel = (double[])raster.getDataElements(rX, rY, | ||
| 2744 | pixel); | ||
| 2745 | double dnormAlpha = pixel[aIdx]; | ||
| 2746 | if (dnormAlpha != 0.0) { | ||
| 2747 | double invAlpha = 1.0 / dnormAlpha; | ||
| 2748 | for (int c=0; c < aIdx; c++) { | ||
| 2749 | pixel[c] *= invAlpha; | ||
| 2750 | } | ||
| 2751 | raster.setDataElements(rX, rY, pixel); | ||
| 2752 | } | ||
| 2753 | } | ||
| 2754 | } | ||
| 2755 | } | ||
| 2756 | break; | ||
| 2757 | default: | ||
| 2758 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 2759 | "implemented for transferType " + transferType); | ||
| 2760 | } | ||
| 2761 | } | ||
| 2762 | |||
| 2763 | // Return a new color model | ||
| 2764 | if (!signed) { | ||
| 2765 | return new ComponentColorModel(colorSpace, nBits, supportsAlpha, | ||
| 2766 | isAlphaPremultiplied, transparency, | ||
| 2767 | transferType); | ||
| 2768 | } else { | ||
| 2769 | return new ComponentColorModel(colorSpace, supportsAlpha, | ||
| 2770 | isAlphaPremultiplied, transparency, | ||
| 2771 | transferType); | ||
| 2772 | } | ||
| 2773 | |||
| 2774 | } | ||
| 2775 | |||
| 2776 | /** | ||
| 2777 | * Returns true if <CODE>raster</CODE> is compatible with this | ||
| 2778 | * <CODE>ColorModel</CODE>; false if it is not. | ||
| 2779 | * | ||
| 2780 | * @param raster The <CODE>Raster</CODE> object to test for compatibility. | ||
| 2781 | * | ||
| 2782 | * @return <CODE>true</CODE> if <CODE>raster</CODE> is compatible with this | ||
| 2783 | * <CODE>ColorModel</CODE>, <CODE>false</CODE> if it is not. | ||
| 2784 | */ | ||
| 2785 | public boolean isCompatibleRaster(Raster raster) { | ||
| 2786 | |||
| 2787 | SampleModel sm = raster.getSampleModel(); | ||
| 2788 | |||
| 2789 | if (sm instanceof ComponentSampleModel) { | ||
| 2790 | if (sm.getNumBands() != getNumComponents()) { | ||
| 2791 | return false; | ||
| 2792 | } | ||
| 2793 | for (int i=0; i<nBits.length; i++) { | ||
| 2794 | if (sm.getSampleSize(i) < nBits[i]) { | ||
| 2795 | return false; | ||
| 2796 | } | ||
| 2797 | } | ||
| 2798 | return (raster.getTransferType() == transferType); | ||
| 2799 | } | ||
| 2800 | else { | ||
| 2801 | return false; | ||
| 2802 | } | ||
| 2803 | } | ||
| 2804 | |||
| 2805 | /** | ||
| 2806 | * Creates a <CODE>WritableRaster</CODE> with the specified width and height, | ||
| 2807 | * that has a data layout (<CODE>SampleModel</CODE>) compatible with | ||
| 2808 | * this <CODE>ColorModel</CODE>. | ||
| 2809 | * | ||
| 2810 | * @param w The width of the <CODE>WritableRaster</CODE> you want to create. | ||
| 2811 | * @param h The height of the <CODE>WritableRaster</CODE> you want to create. | ||
| 2812 | * | ||
| 2813 | * @return A <CODE>WritableRaster</CODE> that is compatible with | ||
| 2814 | * this <CODE>ColorModel</CODE>. | ||
| 2815 | * @see WritableRaster | ||
| 2816 | * @see SampleModel | ||
| 2817 | */ | ||
| 2818 | public WritableRaster createCompatibleWritableRaster (int w, int h) { | ||
| 2819 | int dataSize = w*h*numComponents; | ||
| 2820 | WritableRaster raster = null; | ||
| 2821 | |||
| 2822 | switch (transferType) { | ||
| 2823 | case DataBuffer.TYPE_BYTE: | ||
| 2824 | case DataBuffer.TYPE_USHORT: | ||
| 2825 | raster = Raster.createInterleavedRaster(transferType, | ||
| 2826 | w, h, | ||
| 2827 | numComponents, null); | ||
| 2828 | break; | ||
| 2829 | default: | ||
| 2830 | SampleModel sm = createCompatibleSampleModel(w, h); | ||
| 2831 | DataBuffer db = sm.createDataBuffer(); | ||
| 2832 | raster = Raster.createWritableRaster(sm, db, null); | ||
| 2833 | } | ||
| 2834 | |||
| 2835 | return raster; | ||
| 2836 | } | ||
| 2837 | |||
| 2838 | /** | ||
| 2839 | * Creates a <CODE>SampleModel</CODE> with the specified width and height, | ||
| 2840 | * that has a data layout compatible with this <CODE>ColorModel</CODE>. | ||
| 2841 | * | ||
| 2842 | * @param w The width of the <CODE>SampleModel</CODE> you want to create. | ||
| 2843 | * @param h The height of the <CODE>SampleModel</CODE> you want to create. | ||
| 2844 | * | ||
| 2845 | * @return A <CODE>SampleModel</CODE> that is compatible with this | ||
| 2846 | * <CODE>ColorModel</CODE>. | ||
| 2847 | * | ||
| 2848 | * @see SampleModel | ||
| 2849 | */ | ||
| 2850 | public SampleModel createCompatibleSampleModel(int w, int h) { | ||
| 2851 | int[] bandOffsets = new int[numComponents]; | ||
| 2852 | for (int i=0; i < numComponents; i++) { | ||
| 2853 | bandOffsets[i] = i; | ||
| 2854 | } | ||
| 2855 | switch (transferType) { | ||
| 2856 | case DataBuffer.TYPE_BYTE: | ||
| 2857 | case DataBuffer.TYPE_USHORT: | ||
| 2858 | return new PixelInterleavedSampleModel(transferType, w, h, | ||
| 2859 | numComponents, | ||
| 2860 | w*numComponents, | ||
| 2861 | bandOffsets); | ||
| 2862 | default: | ||
| 2863 | return new ComponentSampleModel(transferType, w, h, | ||
| 2864 | numComponents, | ||
| 2865 | w*numComponents, | ||
| 2866 | bandOffsets); | ||
| 2867 | } | ||
| 2868 | } | ||
| 2869 | |||
| 2870 | /** | ||
| 2871 | * Checks whether or not the specified <CODE>SampleModel</CODE> | ||
| 2872 | * is compatible with this <CODE>ColorModel</CODE>. | ||
| 2873 | * | ||
| 2874 | * @param sm The <CODE>SampleModel</CODE> to test for compatibility. | ||
| 2875 | * | ||
| 2876 | * @return <CODE>true</CODE> if the <CODE>SampleModel</CODE> is | ||
| 2877 | * compatible with this <CODE>ColorModel</CODE>, <CODE>false</CODE> | ||
| 2878 | * if it is not. | ||
| 2879 | * | ||
| 2880 | * @see SampleModel | ||
| 2881 | */ | ||
| 2882 | public boolean isCompatibleSampleModel(SampleModel sm) { | ||
| 2883 | if (!(sm instanceof ComponentSampleModel)) { | ||
| 2884 | return false; | ||
| 2885 | } | ||
| 2886 | |||
| 2887 | // Must have the same number of components | ||
| 2888 | if (numComponents != sm.getNumBands()) { | ||
| 2889 | return false; | ||
| 2890 | } | ||
| 2891 | |||
| 2892 | if (sm.getTransferType() != transferType) { | ||
| 2893 | return false; | ||
| 2894 | } | ||
| 2895 | |||
| 2896 | return true; | ||
| 2897 | } | ||
| 2898 | |||
| 2899 | /** | ||
| 2900 | * Returns a <CODE>Raster</CODE> representing the alpha channel of an image, | ||
| 2901 | * extracted from the input <CODE>Raster</CODE>. | ||
| 2902 | * This method assumes that <CODE>Raster</CODE> objects associated with | ||
| 2903 | * this <CODE>ColorModel</CODE> store the alpha band, if present, as | ||
| 2904 | * the last band of image data. Returns null if there is no separate spatial | ||
| 2905 | * alpha channel associated with this <CODE>ColorModel</CODE>. | ||
| 2906 | * This method creates a new <CODE>Raster</CODE>, but will share the data | ||
| 2907 | * array. | ||
| 2908 | * | ||
| 2909 | * @param raster The <CODE>WritableRaster</CODE> from which to extract the | ||
| 2910 | * alpha channel. | ||
| 2911 | * | ||
| 2912 | * @return A <CODE>WritableRaster</CODE> containing the image's alpha channel. | ||
| 2913 | * | ||
| 2914 | */ | ||
| 2915 | public WritableRaster getAlphaRaster(WritableRaster raster) { | ||
| 2916 | if (hasAlpha() == false) { | ||
| 2917 | return null; | ||
| 2918 | } | ||
| 2919 | |||
| 2920 | int x = raster.getMinX(); | ||
| 2921 | int y = raster.getMinY(); | ||
| 2922 | int[] band = new int[1]; | ||
| 2923 | band[0] = raster.getNumBands() - 1; | ||
| 2924 | return raster.createWritableChild(x, y, raster.getWidth(), | ||
| 2925 | raster.getHeight(), x, y, | ||
| 2926 | band); | ||
| 2927 | } | ||
| 2928 | |||
| 2929 | /** | ||
| 2930 | * Compares this color model with another for equality. | ||
| 2931 | * | ||
| 2932 | * @param obj The object to compare with this color model. | ||
| 2933 | * @return <CODE>true</CODE> if the color model objects are equal, | ||
| 2934 | * <CODE>false</CODE> if they are not. | ||
| 2935 | */ | ||
| 2936 | public boolean equals(Object obj) { | ||
| 2937 | if (!super.equals(obj)) { | ||
| 2938 | return false; | ||
| 2939 | } | ||
| 2940 | |||
| 2941 | if (obj.getClass() != getClass()) { | ||
| 2942 | return false; | ||
| 2943 | } | ||
| 2944 | |||
| 2945 | return true; | ||
| 2946 | } | ||
| 2947 | |||
| 2948 | } | ||
Binary file not shown.
| @@ -0,0 +1,1212 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 | /* **************************************************************** | ||
| 27 | ****************************************************************** | ||
| 28 | ****************************************************************** | ||
| 29 | *** COPYRIGHT (c) Eastman Kodak Company, 1997 | ||
| 30 | *** As an unpublished work pursuant to Title 17 of the United | ||
| 31 | *** States Code. All rights reserved. | ||
| 32 | ****************************************************************** | ||
| 33 | ****************************************************************** | ||
| 34 | ******************************************************************/ | ||
| 35 | |||
| 36 | package java.awt.image; | ||
| 37 | |||
| 38 | import java.util.Arrays; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * This class represents image data which is stored such that each sample | ||
| 42 | * of a pixel occupies one data element of the DataBuffer. It stores the | ||
| 43 | * N samples which make up a pixel in N separate data array elements. | ||
| 44 | * Different bands may be in different banks of the DataBuffer. | ||
| 45 | * Accessor methods are provided so that image data can be manipulated | ||
| 46 | * directly. This class can support different kinds of interleaving, e.g. | ||
| 47 | * band interleaving, scanline interleaving, and pixel interleaving. | ||
| 48 | * Pixel stride is the number of data array elements between two samples | ||
| 49 | * for the same band on the same scanline. Scanline stride is the number | ||
| 50 | * of data array elements between a given sample and the corresponding sample | ||
| 51 | * in the same column of the next scanline. Band offsets denote the number | ||
| 52 | * of data array elements from the first data array element of the bank | ||
| 53 | * of the DataBuffer holding each band to the first sample of the band. | ||
| 54 | * The bands are numbered from 0 to N-1. This class can represent image | ||
| 55 | * data for which each sample is an unsigned integral number which can be | ||
| 56 | * stored in 8, 16, or 32 bits (using <code>DataBuffer.TYPE_BYTE</code>, | ||
| 57 | * <code>DataBuffer.TYPE_USHORT</code>, or <code>DataBuffer.TYPE_INT</code>, | ||
| 58 | * respectively), data for which each sample is a signed integral number | ||
| 59 | * which can be stored in 16 bits (using <code>DataBuffer.TYPE_SHORT</code>), | ||
| 60 | * or data for which each sample is a signed float or double quantity | ||
| 61 | * (using <code>DataBuffer.TYPE_FLOAT</code> or | ||
| 62 | * <code>DataBuffer.TYPE_DOUBLE</code>, respectively). | ||
| 63 | * All samples of a given ComponentSampleModel | ||
| 64 | * are stored with the same precision. All strides and offsets must be | ||
| 65 | * non-negative. This class supports | ||
| 66 | * {@link DataBuffer#TYPE_BYTE TYPE_BYTE}, | ||
| 67 | * {@link DataBuffer#TYPE_USHORT TYPE_USHORT}, | ||
| 68 | * {@link DataBuffer#TYPE_SHORT TYPE_SHORT}, | ||
| 69 | * {@link DataBuffer#TYPE_INT TYPE_INT}, | ||
| 70 | * {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT}, | ||
| 71 | * {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE}, | ||
| 72 | * @see java.awt.image.PixelInterleavedSampleModel | ||
| 73 | * @see java.awt.image.BandedSampleModel | ||
| 74 | */ | ||
| 75 | |||
| 76 | public class ComponentSampleModel extends SampleModel | ||
| 77 | { | ||
| 78 | /** Offsets for all bands in data array elements. */ | ||
| 79 | protected int bandOffsets[]; | ||
| 80 | |||
| 81 | /** Index for each bank storing a band of image data. */ | ||
| 82 | protected int[] bankIndices; | ||
| 83 | |||
| 84 | /** | ||
| 85 | * The number of bands in this | ||
| 86 | * <code>ComponentSampleModel</code>. | ||
| 87 | */ | ||
| 88 | protected int numBands = 1; | ||
| 89 | |||
| 90 | /** | ||
| 91 | * The number of banks in this | ||
| 92 | * <code>ComponentSampleModel</code>. | ||
| 93 | */ | ||
| 94 | protected int numBanks = 1; | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Line stride (in data array elements) of the region of image | ||
| 98 | * data described by this ComponentSampleModel. | ||
| 99 | */ | ||
| 100 | protected int scanlineStride; | ||
| 101 | |||
| 102 | /** Pixel stride (in data array elements) of the region of image | ||
| 103 | * data described by this ComponentSampleModel. | ||
| 104 | */ | ||
| 105 | protected int pixelStride; | ||
| 106 | |||
| 107 | static private native void initIDs(); | ||
| 108 | static { | ||
| 109 | ColorModel.loadLibraries(); | ||
| 110 | initIDs(); | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Constructs a ComponentSampleModel with the specified parameters. | ||
| 115 | * The number of bands will be given by the length of the bandOffsets array. | ||
| 116 | * All bands will be stored in the first bank of the DataBuffer. | ||
| 117 | * @param dataType the data type for storing samples | ||
| 118 | * @param w the width (in pixels) of the region of | ||
| 119 | * image data described | ||
| 120 | * @param h the height (in pixels) of the region of | ||
| 121 | * image data described | ||
| 122 | * @param pixelStride the pixel stride of the region of image | ||
| 123 | * data described | ||
| 124 | * @param scanlineStride the line stride of the region of image | ||
| 125 | * data described | ||
| 126 | * @param bandOffsets the offsets of all bands | ||
| 127 | * @throws IllegalArgumentException if <code>w</code> or | ||
| 128 | * <code>h</code> is not greater than 0 | ||
| 129 | * @throws IllegalArgumentException if <code>pixelStride</code> | ||
| 130 | * is less than 0 | ||
| 131 | * @throws IllegalArgumentException if <code>scanlineStride</code> | ||
| 132 | * is less than 0 | ||
| 133 | * @throws IllegalArgumentException if <code>numBands</code> | ||
| 134 | * is less than 1 | ||
| 135 | * @throws IllegalArgumentException if the product of <code>w</code> | ||
| 136 | * and <code>h</code> is greater than | ||
| 137 | * <code>Integer.MAX_VALUE</code> | ||
| 138 | * @throws IllegalArgumentException if <code>dataType</code> is not | ||
| 139 | * one of the supported data types | ||
| 140 | */ | ||
| 141 | public ComponentSampleModel(int dataType, | ||
| 142 | int w, int h, | ||
| 143 | int pixelStride, | ||
| 144 | int scanlineStride, | ||
| 145 | int bandOffsets[]) { | ||
| 146 | super(dataType, w, h, bandOffsets.length); | ||
| 147 | this.dataType = dataType; | ||
| 148 | this.pixelStride = pixelStride; | ||
| 149 | this.scanlineStride = scanlineStride; | ||
| 150 | this.bandOffsets = (int[])bandOffsets.clone(); | ||
| 151 | numBands = bandOffsets.length; | ||
| 152 | if (pixelStride < 0) { | ||
| 153 | throw new IllegalArgumentException("Pixel stride must be >= 0"); | ||
| 154 | } | ||
| 155 | // TODO - bug 4296691 - remove this check | ||
| 156 | if (scanlineStride < 0) { | ||
| 157 | throw new IllegalArgumentException("Scanline stride must be >= 0"); | ||
| 158 | } | ||
| 159 | if (numBands < 1) { | ||
| 160 | throw new IllegalArgumentException("Must have at least one band."); | ||
| 161 | } | ||
| 162 | if ((dataType < DataBuffer.TYPE_BYTE) || | ||
| 163 | (dataType > DataBuffer.TYPE_DOUBLE)) { | ||
| 164 | throw new IllegalArgumentException("Unsupported dataType."); | ||
| 165 | } | ||
| 166 | bankIndices = new int[numBands]; | ||
| 167 | for (int i=0; i<numBands; i++) { | ||
| 168 | bankIndices[i] = 0; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | |||
| 173 | /** | ||
| 174 | * Constructs a ComponentSampleModel with the specified parameters. | ||
| 175 | * The number of bands will be given by the length of the bandOffsets array. | ||
| 176 | * Different bands may be stored in different banks of the DataBuffer. | ||
| 177 | * | ||
| 178 | * @param dataType the data type for storing samples | ||
| 179 | * @param w the width (in pixels) of the region of | ||
| 180 | * image data described | ||
| 181 | * @param h the height (in pixels) of the region of | ||
| 182 | * image data described | ||
| 183 | * @param pixelStride the pixel stride of the region of image | ||
| 184 | * data described | ||
| 185 | * @param scanlineStride The line stride of the region of image | ||
| 186 | * data described | ||
| 187 | * @param bankIndices the bank indices of all bands | ||
| 188 | * @param bandOffsets the band offsets of all bands | ||
| 189 | * @throws IllegalArgumentException if <code>w</code> or | ||
| 190 | * <code>h</code> is not greater than 0 | ||
| 191 | * @throws IllegalArgumentException if <code>pixelStride</code> | ||
| 192 | * is less than 0 | ||
| 193 | * @throws IllegalArgumentException if <code>scanlineStride</code> | ||
| 194 | * is less than 0 | ||
| 195 | * @throws IllegalArgumentException if the length of | ||
| 196 | * <code>bankIndices</code> does not equal the length of | ||
| 197 | * <code>bankOffsets</code> | ||
| 198 | * @throws IllegalArgumentException if any of the bank indices | ||
| 199 | * of <code>bandIndices</code> is less than 0 | ||
| 200 | * @throws IllegalArgumentException if <code>dataType</code> is not | ||
| 201 | * one of the supported data types | ||
| 202 | */ | ||
| 203 | public ComponentSampleModel(int dataType, | ||
| 204 | int w, int h, | ||
| 205 | int pixelStride, | ||
| 206 | int scanlineStride, | ||
| 207 | int bankIndices[], | ||
| 208 | int bandOffsets[]) { | ||
| 209 | super(dataType, w, h, bandOffsets.length); | ||
| 210 | this.dataType = dataType; | ||
| 211 | this.pixelStride = pixelStride; | ||
| 212 | this.scanlineStride = scanlineStride; | ||
| 213 | this.bandOffsets = (int[])bandOffsets.clone(); | ||
| 214 | this.bankIndices = (int[]) bankIndices.clone(); | ||
| 215 | if (pixelStride < 0) { | ||
| 216 | throw new IllegalArgumentException("Pixel stride must be >= 0"); | ||
| 217 | } | ||
| 218 | // TODO - bug 4296691 - remove this check | ||
| 219 | if (scanlineStride < 0) { | ||
| 220 | throw new IllegalArgumentException("Scanline stride must be >= 0"); | ||
| 221 | } | ||
| 222 | if ((dataType < DataBuffer.TYPE_BYTE) || | ||
| 223 | (dataType > DataBuffer.TYPE_DOUBLE)) { | ||
| 224 | throw new IllegalArgumentException("Unsupported dataType."); | ||
| 225 | } | ||
| 226 | int maxBank = bankIndices[0]; | ||
| 227 | if (maxBank < 0) { | ||
| 228 | throw new IllegalArgumentException("Index of bank 0 is less than "+ | ||
| 229 | "0 ("+maxBank+")"); | ||
| 230 | } | ||
| 231 | for (int i=1; i < bankIndices.length; i++) { | ||
| 232 | if (bankIndices[i] > maxBank) { | ||
| 233 | maxBank = bankIndices[i]; | ||
| 234 | } | ||
| 235 | else if (bankIndices[i] < 0) { | ||
| 236 | throw new IllegalArgumentException("Index of bank "+i+ | ||
| 237 | " is less than 0 ("+ | ||
| 238 | maxBank+")"); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | numBanks = maxBank+1; | ||
| 242 | numBands = bandOffsets.length; | ||
| 243 | if (bandOffsets.length != bankIndices.length) { | ||
| 244 | throw new IllegalArgumentException("Length of bandOffsets must "+ | ||
| 245 | "equal length of bankIndices."); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | /** | ||
| 250 | * Returns the size of the data buffer (in data elements) needed | ||
| 251 | * for a data buffer that matches this ComponentSampleModel. | ||
| 252 | */ | ||
| 253 | private long getBufferSize() { | ||
| 254 | int maxBandOff=bandOffsets[0]; | ||
| 255 | for (int i=1; i<bandOffsets.length; i++) | ||
| 256 | maxBandOff = Math.max(maxBandOff,bandOffsets[i]); | ||
| 257 | |||
| 258 | long size = 0; | ||
| 259 | if (maxBandOff >= 0) | ||
| 260 | size += maxBandOff+1; | ||
| 261 | if (pixelStride > 0) | ||
| 262 | size += pixelStride * (width-1); | ||
| 263 | if (scanlineStride > 0) | ||
| 264 | size += scanlineStride*(height-1); | ||
| 265 | return size; | ||
| 266 | } | ||
| 267 | |||
| 268 | /** | ||
| 269 | * Preserves band ordering with new step factor... | ||
| 270 | */ | ||
| 271 | int []orderBands(int orig[], int step) { | ||
| 272 | int map[] = new int[orig.length]; | ||
| 273 | int ret[] = new int[orig.length]; | ||
| 274 | |||
| 275 | for (int i=0; i<map.length; i++) map[i] = i; | ||
| 276 | |||
| 277 | for (int i = 0; i < ret.length; i++) { | ||
| 278 | int index = i; | ||
| 279 | for (int j = i+1; j < ret.length; j++) { | ||
| 280 | if (orig[map[index]] > orig[map[j]]) { | ||
| 281 | index = j; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | ret[map[index]] = i*step; | ||
| 285 | map[index] = map[i]; | ||
| 286 | } | ||
| 287 | return ret; | ||
| 288 | } | ||
| 289 | |||
| 290 | /** | ||
| 291 | * Creates a new <code>ComponentSampleModel</code> with the specified | ||
| 292 | * width and height. The new <code>SampleModel</code> will have the same | ||
| 293 | * number of bands, storage data type, interleaving scheme, and | ||
| 294 | * pixel stride as this <code>SampleModel</code>. | ||
| 295 | * @param w the width of the resulting <code>SampleModel</code> | ||
| 296 | * @param h the height of the resulting <code>SampleModel</code> | ||
| 297 | * @return a new <code>ComponentSampleModel</code> with the specified size | ||
| 298 | * @throws IllegalArgumentException if <code>w</code> or | ||
| 299 | * <code>h</code> is not greater than 0 | ||
| 300 | */ | ||
| 301 | public SampleModel createCompatibleSampleModel(int w, int h) { | ||
| 302 | SampleModel ret=null; | ||
| 303 | long size; | ||
| 304 | int minBandOff=bandOffsets[0]; | ||
| 305 | int maxBandOff=bandOffsets[0]; | ||
| 306 | for (int i=1; i<bandOffsets.length; i++) { | ||
| 307 | minBandOff = Math.min(minBandOff,bandOffsets[i]); | ||
| 308 | maxBandOff = Math.max(maxBandOff,bandOffsets[i]); | ||
| 309 | } | ||
| 310 | maxBandOff -= minBandOff; | ||
| 311 | |||
| 312 | int bands = bandOffsets.length; | ||
| 313 | int bandOff[]; | ||
| 314 | int pStride = Math.abs(pixelStride); | ||
| 315 | int lStride = Math.abs(scanlineStride); | ||
| 316 | int bStride = Math.abs(maxBandOff); | ||
| 317 | |||
| 318 | if (pStride > lStride) { | ||
| 319 | if (pStride > bStride) { | ||
| 320 | if (lStride > bStride) { // pix > line > band | ||
| 321 | bandOff = new int[bandOffsets.length]; | ||
| 322 | for (int i=0; i<bands; i++) | ||
| 323 | bandOff[i] = bandOffsets[i]-minBandOff; | ||
| 324 | lStride = bStride+1; | ||
| 325 | pStride = lStride*h; | ||
| 326 | } else { // pix > band > line | ||
| 327 | bandOff = orderBands(bandOffsets,lStride*h); | ||
| 328 | pStride = bands*lStride*h; | ||
| 329 | } | ||
| 330 | } else { // band > pix > line | ||
| 331 | pStride = lStride*h; | ||
| 332 | bandOff = orderBands(bandOffsets,pStride*w); | ||
| 333 | } | ||
| 334 | } else { | ||
| 335 | if (pStride > bStride) { // line > pix > band | ||
| 336 | bandOff = new int[bandOffsets.length]; | ||
| 337 | for (int i=0; i<bands; i++) | ||
| 338 | bandOff[i] = bandOffsets[i]-minBandOff; | ||
| 339 | pStride = bStride+1; | ||
| 340 | lStride = pStride*w; | ||
| 341 | } else { | ||
| 342 | if (lStride > bStride) { // line > band > pix | ||
| 343 | bandOff = orderBands(bandOffsets,pStride*w); | ||
| 344 | lStride = bands*pStride*w; | ||
| 345 | } else { // band > line > pix | ||
| 346 | lStride = pStride*w; | ||
| 347 | bandOff = orderBands(bandOffsets,lStride*h); | ||
| 348 | } | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | // make sure we make room for negative offsets... | ||
| 353 | int base = 0; | ||
| 354 | if (scanlineStride < 0) { | ||
| 355 | base += lStride*h; | ||
| 356 | lStride *= -1; | ||
| 357 | } | ||
| 358 | if (pixelStride < 0) { | ||
| 359 | base += pStride*w; | ||
| 360 | pStride *= -1; | ||
| 361 | } | ||
| 362 | |||
| 363 | for (int i=0; i<bands; i++) | ||
| 364 | bandOff[i] += base; | ||
| 365 | return new ComponentSampleModel(dataType, w, h, pStride, | ||
| 366 | lStride, bankIndices, bandOff); | ||
| 367 | } | ||
| 368 | |||
| 369 | /** | ||
| 370 | * Creates a new ComponentSampleModel with a subset of the bands | ||
| 371 | * of this ComponentSampleModel. The new ComponentSampleModel can be | ||
| 372 | * used with any DataBuffer that the existing ComponentSampleModel | ||
| 373 | * can be used with. The new ComponentSampleModel/DataBuffer | ||
| 374 | * combination will represent an image with a subset of the bands | ||
| 375 | * of the original ComponentSampleModel/DataBuffer combination. | ||
| 376 | * @param bands a subset of bands from this | ||
| 377 | * <code>ComponentSampleModel</code> | ||
| 378 | * @return a <code>ComponentSampleModel</code> created with a subset | ||
| 379 | * of bands from this <code>ComponentSampleModel</code>. | ||
| 380 | */ | ||
| 381 | public SampleModel createSubsetSampleModel(int bands[]) { | ||
| 382 | if (bands.length > bankIndices.length) | ||
| 383 | throw new RasterFormatException("There are only " + | ||
| 384 | bankIndices.length + | ||
| 385 | " bands"); | ||
| 386 | int newBankIndices[] = new int[bands.length]; | ||
| 387 | int newBandOffsets[] = new int[bands.length]; | ||
| 388 | |||
| 389 | for (int i=0; i<bands.length; i++) { | ||
| 390 | newBankIndices[i] = bankIndices[bands[i]]; | ||
| 391 | newBandOffsets[i] = bandOffsets[bands[i]]; | ||
| 392 | } | ||
| 393 | |||
| 394 | return new ComponentSampleModel(this.dataType, width, height, | ||
| 395 | this.pixelStride, | ||
| 396 | this.scanlineStride, | ||
| 397 | newBankIndices, newBandOffsets); | ||
| 398 | } | ||
| 399 | |||
| 400 | /** | ||
| 401 | * Creates a <code>DataBuffer</code> that corresponds to this | ||
| 402 | * <code>ComponentSampleModel</code>. | ||
| 403 | * The <code>DataBuffer</code> object's data type, number of banks, | ||
| 404 | * and size are be consistent with this <code>ComponentSampleModel</code>. | ||
| 405 | * @return a <code>DataBuffer</code> whose data type, number of banks | ||
| 406 | * and size are consistent with this | ||
| 407 | * <code>ComponentSampleModel</code>. | ||
| 408 | */ | ||
| 409 | public DataBuffer createDataBuffer() { | ||
| 410 | DataBuffer dataBuffer = null; | ||
| 411 | |||
| 412 | int size = (int)getBufferSize(); | ||
| 413 | switch (dataType) { | ||
| 414 | case DataBuffer.TYPE_BYTE: | ||
| 415 | dataBuffer = new DataBufferByte(size, numBanks); | ||
| 416 | break; | ||
| 417 | case DataBuffer.TYPE_USHORT: | ||
| 418 | dataBuffer = new DataBufferUShort(size, numBanks); | ||
| 419 | break; | ||
| 420 | case DataBuffer.TYPE_SHORT: | ||
| 421 | dataBuffer = new DataBufferShort(size, numBanks); | ||
| 422 | break; | ||
| 423 | case DataBuffer.TYPE_INT: | ||
| 424 | dataBuffer = new DataBufferInt(size, numBanks); | ||
| 425 | break; | ||
| 426 | case DataBuffer.TYPE_FLOAT: | ||
| 427 | dataBuffer = new DataBufferFloat(size, numBanks); | ||
| 428 | break; | ||
| 429 | case DataBuffer.TYPE_DOUBLE: | ||
| 430 | dataBuffer = new DataBufferDouble(size, numBanks); | ||
| 431 | break; | ||
| 432 | } | ||
| 433 | |||
| 434 | return dataBuffer; | ||
| 435 | } | ||
| 436 | |||
| 437 | |||
| 438 | /** Gets the offset for the first band of pixel (x,y). | ||
| 439 | * A sample of the first band can be retrieved from a | ||
| 440 | * <code>DataBuffer</code> | ||
| 441 | * <code>data</code> with a <code>ComponentSampleModel</code> | ||
| 442 | * <code>csm</code> as | ||
| 443 | * <pre> | ||
| 444 | * data.getElem(csm.getOffset(x, y)); | ||
| 445 | * </pre> | ||
| 446 | * @param x the X location of the pixel | ||
| 447 | * @param y the Y location of the pixel | ||
| 448 | * @return the offset for the first band of the specified pixel. | ||
| 449 | */ | ||
| 450 | public int getOffset(int x, int y) { | ||
| 451 | int offset = y*scanlineStride + x*pixelStride + bandOffsets[0]; | ||
| 452 | return offset; | ||
| 453 | } | ||
| 454 | |||
| 455 | /** Gets the offset for band b of pixel (x,y). | ||
| 456 | * A sample of band <code>b</code> can be retrieved from a | ||
| 457 | * <code>DataBuffer</code> <code>data</code> | ||
| 458 | * with a <code>ComponentSampleModel</code> <code>csm</code> as | ||
| 459 | * <pre> | ||
| 460 | * data.getElem(csm.getOffset(x, y, b)); | ||
| 461 | * </pre> | ||
| 462 | * @param x the X location of the specified pixel | ||
| 463 | * @param y the Y location of the specified pixel | ||
| 464 | * @param b the specified band | ||
| 465 | * @return the offset for the specified band of the specified pixel. | ||
| 466 | */ | ||
| 467 | public int getOffset(int x, int y, int b) { | ||
| 468 | int offset = y*scanlineStride + x*pixelStride + bandOffsets[b]; | ||
| 469 | return offset; | ||
| 470 | } | ||
| 471 | |||
| 472 | /** Returns the number of bits per sample for all bands. | ||
| 473 | * @return an array containing the number of bits per sample | ||
| 474 | * for all bands, where each element in the array | ||
| 475 | * represents a band. | ||
| 476 | */ | ||
| 477 | public final int[] getSampleSize() { | ||
| 478 | int sampleSize[] = new int [numBands]; | ||
| 479 | int sizeInBits = getSampleSize(0); | ||
| 480 | |||
| 481 | for (int i=0; i<numBands; i++) | ||
| 482 | sampleSize[i] = sizeInBits; | ||
| 483 | |||
| 484 | return sampleSize; | ||
| 485 | } | ||
| 486 | |||
| 487 | /** Returns the number of bits per sample for the specified band. | ||
| 488 | * @param band the specified band | ||
| 489 | * @return the number of bits per sample for the specified band. | ||
| 490 | */ | ||
| 491 | public final int getSampleSize(int band) { | ||
| 492 | return DataBuffer.getDataTypeSize(dataType); | ||
| 493 | } | ||
| 494 | |||
| 495 | /** Returns the bank indices for all bands. | ||
| 496 | * @return the bank indices for all bands. | ||
| 497 | */ | ||
| 498 | public final int [] getBankIndices() { | ||
| 499 | return (int[]) bankIndices.clone(); | ||
| 500 | } | ||
| 501 | |||
| 502 | /** Returns the band offset for all bands. | ||
| 503 | * @return the band offsets for all bands. | ||
| 504 | */ | ||
| 505 | public final int [] getBandOffsets() { | ||
| 506 | return (int[])bandOffsets.clone(); | ||
| 507 | } | ||
| 508 | |||
| 509 | /** Returns the scanline stride of this ComponentSampleModel. | ||
| 510 | * @return the scanline stride of this <code>ComponentSampleModel</code>. | ||
| 511 | */ | ||
| 512 | public final int getScanlineStride() { | ||
| 513 | return scanlineStride; | ||
| 514 | } | ||
| 515 | |||
| 516 | /** Returns the pixel stride of this ComponentSampleModel. | ||
| 517 | * @return the pixel stride of this <code>ComponentSampleModel</code>. | ||
| 518 | */ | ||
| 519 | public final int getPixelStride() { | ||
| 520 | return pixelStride; | ||
| 521 | } | ||
| 522 | |||
| 523 | /** | ||
| 524 | * Returns the number of data elements needed to transfer a pixel | ||
| 525 | * with the | ||
| 526 | * {@link #getDataElements(int, int, Object, DataBuffer) } and | ||
| 527 | * {@link #setDataElements(int, int, Object, DataBuffer) } | ||
| 528 | * methods. | ||
| 529 | * For a <code>ComponentSampleModel</code>, this is identical to the | ||
| 530 | * number of bands. | ||
| 531 | * @return the number of data elements needed to transfer a pixel with | ||
| 532 | * the <code>getDataElements</code> and | ||
| 533 | * <code>setDataElements</code> methods. | ||
| 534 | * @see java.awt.image.SampleModel#getNumDataElements | ||
| 535 | * @see #getNumBands | ||
| 536 | */ | ||
| 537 | public final int getNumDataElements() { | ||
| 538 | return getNumBands(); | ||
| 539 | } | ||
| 540 | |||
| 541 | /** | ||
| 542 | * Returns data for a single pixel in a primitive array of type | ||
| 543 | * <code>TransferType</code>. For a <code>ComponentSampleModel</code>, | ||
| 544 | * this is the same as the data type, and samples are returned | ||
| 545 | * one per array element. Generally, <code>obj</code> should | ||
| 546 | * be passed in as <code>null</code>, so that the <code>Object</code> | ||
| 547 | * is created automatically and is the right primitive data type. | ||
| 548 | * <p> | ||
| 549 | * The following code illustrates transferring data for one pixel from | ||
| 550 | * <code>DataBuffer</code> <code>db1</code>, whose storage layout is | ||
| 551 | * described by <code>ComponentSampleModel</code> <code>csm1</code>, | ||
| 552 | * to <code>DataBuffer</code> <code>db2</code>, whose storage layout | ||
| 553 | * is described by <code>ComponentSampleModel</code> <code>csm2</code>. | ||
| 554 | * The transfer is usually more efficient than using | ||
| 555 | * <code>getPixel</code> and <code>setPixel</code>. | ||
| 556 | * <pre> | ||
| 557 | * ComponentSampleModel csm1, csm2; | ||
| 558 | * DataBufferInt db1, db2; | ||
| 559 | * csm2.setDataElements(x, y, | ||
| 560 | * csm1.getDataElements(x, y, null, db1), db2); | ||
| 561 | * </pre> | ||
| 562 | * | ||
| 563 | * Using <code>getDataElements</code> and <code>setDataElements</code> | ||
| 564 | * to transfer between two <code>DataBuffer/SampleModel</code> | ||
| 565 | * pairs is legitimate if the <code>SampleModel</code> objects have | ||
| 566 | * the same number of bands, corresponding bands have the same number of | ||
| 567 | * bits per sample, and the <code>TransferType</code>s are the same. | ||
| 568 | * <p> | ||
| 569 | * If <code>obj</code> is not <code>null</code>, it should be a | ||
| 570 | * primitive array of type <code>TransferType</code>. | ||
| 571 | * Otherwise, a <code>ClassCastException</code> is thrown. An | ||
| 572 | * <code>ArrayIndexOutOfBoundsException</code> might be thrown if the | ||
| 573 | * coordinates are not in bounds, or if <code>obj</code> is not | ||
| 574 | * <code>null</code> and is not large enough to hold | ||
| 575 | * the pixel data. | ||
| 576 | * | ||
| 577 | * @param x the X coordinate of the pixel location | ||
| 578 | * @param y the Y coordinate of the pixel location | ||
| 579 | * @param obj if non-<code>null</code>, a primitive array | ||
| 580 | * in which to return the pixel data | ||
| 581 | * @param data the <code>DataBuffer</code> containing the image data | ||
| 582 | * @return the data of the specified pixel | ||
| 583 | * @see #setDataElements(int, int, Object, DataBuffer) | ||
| 584 | * | ||
| 585 | * @throws NullPointerException if data is null. | ||
| 586 | * @throws ArrayIndexOutOfBoundsException if the coordinates are | ||
| 587 | * not in bounds, or if obj is too small to hold the ouput. | ||
| 588 | */ | ||
| 589 | public Object getDataElements(int x, int y, Object obj, DataBuffer data) { | ||
| 590 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 591 | throw new ArrayIndexOutOfBoundsException | ||
| 592 | ("Coordinate out of bounds!"); | ||
| 593 | } | ||
| 594 | |||
| 595 | int type = getTransferType(); | ||
| 596 | int numDataElems = getNumDataElements(); | ||
| 597 | int pixelOffset = y*scanlineStride + x*pixelStride; | ||
| 598 | |||
| 599 | switch(type) { | ||
| 600 | |||
| 601 | case DataBuffer.TYPE_BYTE: | ||
| 602 | |||
| 603 | byte[] bdata; | ||
| 604 | |||
| 605 | if (obj == null) | ||
| 606 | bdata = new byte[numDataElems]; | ||
| 607 | else | ||
| 608 | bdata = (byte[])obj; | ||
| 609 | |||
| 610 | for (int i=0; i<numDataElems; i++) { | ||
| 611 | bdata[i] = (byte)data.getElem(bankIndices[i], | ||
| 612 | pixelOffset + bandOffsets[i]); | ||
| 613 | } | ||
| 614 | |||
| 615 | obj = (Object)bdata; | ||
| 616 | break; | ||
| 617 | |||
| 618 | case DataBuffer.TYPE_USHORT: | ||
| 619 | case DataBuffer.TYPE_SHORT: | ||
| 620 | |||
| 621 | short[] sdata; | ||
| 622 | |||
| 623 | if (obj == null) | ||
| 624 | sdata = new short[numDataElems]; | ||
| 625 | else | ||
| 626 | sdata = (short[])obj; | ||
| 627 | |||
| 628 | for (int i=0; i<numDataElems; i++) { | ||
| 629 | sdata[i] = (short)data.getElem(bankIndices[i], | ||
| 630 | pixelOffset + bandOffsets[i]); | ||
| 631 | } | ||
| 632 | |||
| 633 | obj = (Object)sdata; | ||
| 634 | break; | ||
| 635 | |||
| 636 | case DataBuffer.TYPE_INT: | ||
| 637 | |||
| 638 | int[] idata; | ||
| 639 | |||
| 640 | if (obj == null) | ||
| 641 | idata = new int[numDataElems]; | ||
| 642 | else | ||
| 643 | idata = (int[])obj; | ||
| 644 | |||
| 645 | for (int i=0; i<numDataElems; i++) { | ||
| 646 | idata[i] = data.getElem(bankIndices[i], | ||
| 647 | pixelOffset + bandOffsets[i]); | ||
| 648 | } | ||
| 649 | |||
| 650 | obj = (Object)idata; | ||
| 651 | break; | ||
| 652 | |||
| 653 | case DataBuffer.TYPE_FLOAT: | ||
| 654 | |||
| 655 | float[] fdata; | ||
| 656 | |||
| 657 | if (obj == null) | ||
| 658 | fdata = new float[numDataElems]; | ||
| 659 | else | ||
| 660 | fdata = (float[])obj; | ||
| 661 | |||
| 662 | for (int i=0; i<numDataElems; i++) { | ||
| 663 | fdata[i] = data.getElemFloat(bankIndices[i], | ||
| 664 | pixelOffset + bandOffsets[i]); | ||
| 665 | } | ||
| 666 | |||
| 667 | obj = (Object)fdata; | ||
| 668 | break; | ||
| 669 | |||
| 670 | case DataBuffer.TYPE_DOUBLE: | ||
| 671 | |||
| 672 | double[] ddata; | ||
| 673 | |||
| 674 | if (obj == null) | ||
| 675 | ddata = new double[numDataElems]; | ||
| 676 | else | ||
| 677 | ddata = (double[])obj; | ||
| 678 | |||
| 679 | for (int i=0; i<numDataElems; i++) { | ||
| 680 | ddata[i] = data.getElemDouble(bankIndices[i], | ||
| 681 | pixelOffset + bandOffsets[i]); | ||
| 682 | } | ||
| 683 | |||
| 684 | obj = (Object)ddata; | ||
| 685 | break; | ||
| 686 | } | ||
| 687 | |||
| 688 | return obj; | ||
| 689 | } | ||
| 690 | |||
| 691 | /** | ||
| 692 | * Returns all samples for the specified pixel in an int array, | ||
| 693 | * one sample per array element. | ||
| 694 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if | ||
| 695 | * the coordinates are not in bounds. | ||
| 696 | * @param x the X coordinate of the pixel location | ||
| 697 | * @param y the Y coordinate of the pixel location | ||
| 698 | * @param iArray If non-null, returns the samples in this array | ||
| 699 | * @param data The DataBuffer containing the image data | ||
| 700 | * @return the samples of the specified pixel. | ||
| 701 | * @see #setPixel(int, int, int[], DataBuffer) | ||
| 702 | * | ||
| 703 | * @throws NullPointerException if data is null. | ||
| 704 | * @throws ArrayIndexOutOfBoundsException if the coordinates are | ||
| 705 | * not in bounds, or if iArray is too small to hold the output. | ||
| 706 | */ | ||
| 707 | public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { | ||
| 708 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 709 | throw new ArrayIndexOutOfBoundsException | ||
| 710 | ("Coordinate out of bounds!"); | ||
| 711 | } | ||
| 712 | int pixels[]; | ||
| 713 | if (iArray != null) { | ||
| 714 | pixels = iArray; | ||
| 715 | } else { | ||
| 716 | pixels = new int [numBands]; | ||
| 717 | } | ||
| 718 | int pixelOffset = y*scanlineStride + x*pixelStride; | ||
| 719 | for (int i=0; i<numBands; i++) { | ||
| 720 | pixels[i] = data.getElem(bankIndices[i], | ||
| 721 | pixelOffset + bandOffsets[i]); | ||
| 722 | } | ||
| 723 | return pixels; | ||
| 724 | } | ||
| 725 | |||
| 726 | /** | ||
| 727 | * Returns all samples for the specified rectangle of pixels in | ||
| 728 | * an int array, one sample per array element. | ||
| 729 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if | ||
| 730 | * the coordinates are not in bounds. | ||
| 731 | * @param x The X coordinate of the upper left pixel location | ||
| 732 | * @param y The Y coordinate of the upper left pixel location | ||
| 733 | * @param w The width of the pixel rectangle | ||
| 734 | * @param h The height of the pixel rectangle | ||
| 735 | * @param iArray If non-null, returns the samples in this array | ||
| 736 | * @param data The DataBuffer containing the image data | ||
| 737 | * @return the samples of the pixels within the specified region. | ||
| 738 | * @see #setPixels(int, int, int, int, int[], DataBuffer) | ||
| 739 | */ | ||
| 740 | public int[] getPixels(int x, int y, int w, int h, | ||
| 741 | int iArray[], DataBuffer data) { | ||
| 742 | int x1 = x + w; | ||
| 743 | int y1 = y + h; | ||
| 744 | |||
| 745 | if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || | ||
| 746 | y < 0 || y >= height || y > height || y1 < 0 || y1 > height) | ||
| 747 | { | ||
| 748 | throw new ArrayIndexOutOfBoundsException | ||
| 749 | ("Coordinate out of bounds!"); | ||
| 750 | } | ||
| 751 | int pixels[]; | ||
| 752 | if (iArray != null) { | ||
| 753 | pixels = iArray; | ||
| 754 | } else { | ||
| 755 | pixels = new int [w*h*numBands]; | ||
| 756 | } | ||
| 757 | int lineOffset = y*scanlineStride + x*pixelStride; | ||
| 758 | int srcOffset = 0; | ||
| 759 | |||
| 760 | for (int i = 0; i < h; i++) { | ||
| 761 | int pixelOffset = lineOffset; | ||
| 762 | for (int j = 0; j < w; j++) { | ||
| 763 | for (int k=0; k < numBands; k++) { | ||
| 764 | pixels[srcOffset++] = | ||
| 765 | data.getElem(bankIndices[k], pixelOffset + bandOffsets[k]); | ||
| 766 | } | ||
| 767 | pixelOffset += pixelStride; | ||
| 768 | } | ||
| 769 | lineOffset += scanlineStride; | ||
| 770 | } | ||
| 771 | return pixels; | ||
| 772 | } | ||
| 773 | |||
| 774 | /** | ||
| 775 | * Returns as int the sample in a specified band for the pixel | ||
| 776 | * located at (x,y). | ||
| 777 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if | ||
| 778 | * the coordinates are not in bounds. | ||
| 779 | * @param x the X coordinate of the pixel location | ||
| 780 | * @param y the Y coordinate of the pixel location | ||
| 781 | * @param b the band to return | ||
| 782 | * @param data the <code>DataBuffer</code> containing the image data | ||
| 783 | * @return the sample in a specified band for the specified pixel | ||
| 784 | * @see #setSample(int, int, int, int, DataBuffer) | ||
| 785 | */ | ||
| 786 | public int getSample(int x, int y, int b, DataBuffer data) { | ||
| 787 | // Bounds check for 'b' will be performed automatically | ||
| 788 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 789 | throw new ArrayIndexOutOfBoundsException | ||
| 790 | ("Coordinate out of bounds!"); | ||
| 791 | } | ||
| 792 | int sample = data.getElem(bankIndices[b], | ||
| 793 | y*scanlineStride + x*pixelStride + | ||
| 794 | bandOffsets[b]); | ||
| 795 | return sample; | ||
| 796 | } | ||
| 797 | |||
| 798 | /** | ||
| 799 | * Returns the sample in a specified band | ||
| 800 | * for the pixel located at (x,y) as a float. | ||
| 801 | * An <code>ArrayIndexOutOfBoundsException</code> might be | ||
| 802 | * thrown if the coordinates are not in bounds. | ||
| 803 | * @param x The X coordinate of the pixel location | ||
| 804 | * @param y The Y coordinate of the pixel location | ||
| 805 | * @param b The band to return | ||
| 806 | * @param data The DataBuffer containing the image data | ||
| 807 | * @return a float value representing the sample in the specified | ||
| 808 | * band for the specified pixel. | ||
| 809 | */ | ||
| 810 | public float getSampleFloat(int x, int y, int b, DataBuffer data) { | ||
| 811 | // Bounds check for 'b' will be performed automatically | ||
| 812 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 813 | throw new ArrayIndexOutOfBoundsException | ||
| 814 | ("Coordinate out of bounds!"); | ||
| 815 | } | ||
| 816 | |||
| 817 | float sample = data.getElemFloat(bankIndices[b], | ||
| 818 | y*scanlineStride + x*pixelStride + | ||
| 819 | bandOffsets[b]); | ||
| 820 | return sample; | ||
| 821 | } | ||
| 822 | |||
| 823 | /** | ||
| 824 | * Returns the sample in a specified band | ||
| 825 | * for a pixel located at (x,y) as a double. | ||
| 826 | * An <code>ArrayIndexOutOfBoundsException</code> might be | ||
| 827 | * thrown if the coordinates are not in bounds. | ||
| 828 | * @param x The X coordinate of the pixel location | ||
| 829 | * @param y The Y coordinate of the pixel location | ||
| 830 | * @param b The band to return | ||
| 831 | * @param data The DataBuffer containing the image data | ||
| 832 | * @return a double value representing the sample in the specified | ||
| 833 | * band for the specified pixel. | ||
| 834 | */ | ||
| 835 | public double getSampleDouble(int x, int y, int b, DataBuffer data) { | ||
| 836 | // Bounds check for 'b' will be performed automatically | ||
| 837 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 838 | throw new ArrayIndexOutOfBoundsException | ||
| 839 | ("Coordinate out of bounds!"); | ||
| 840 | } | ||
| 841 | |||
| 842 | double sample = data.getElemDouble(bankIndices[b], | ||
| 843 | y*scanlineStride + x*pixelStride + | ||
| 844 | bandOffsets[b]); | ||
| 845 | return sample; | ||
| 846 | } | ||
| 847 | |||
| 848 | /** | ||
| 849 | * Returns the samples in a specified band for the specified rectangle | ||
| 850 | * of pixels in an int array, one sample per data array element. | ||
| 851 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if | ||
| 852 | * the coordinates are not in bounds. | ||
| 853 | * @param x The X coordinate of the upper left pixel location | ||
| 854 | * @param y The Y coordinate of the upper left pixel location | ||
| 855 | * @param w the width of the pixel rectangle | ||
| 856 | * @param h the height of the pixel rectangle | ||
| 857 | * @param b the band to return | ||
| 858 | * @param iArray if non-<code>null</code>, returns the samples | ||
| 859 | * in this array | ||
| 860 | * @param data the <code>DataBuffer</code> containing the image data | ||
| 861 | * @return the samples in the specified band of the specified pixel | ||
| 862 | * @see #setSamples(int, int, int, int, int, int[], DataBuffer) | ||
| 863 | */ | ||
| 864 | public int[] getSamples(int x, int y, int w, int h, int b, | ||
| 865 | int iArray[], DataBuffer data) { | ||
| 866 | // Bounds check for 'b' will be performed automatically | ||
| 867 | if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { | ||
| 868 | throw new ArrayIndexOutOfBoundsException | ||
| 869 | ("Coordinate out of bounds!"); | ||
| 870 | } | ||
| 871 | int samples[]; | ||
| 872 | if (iArray != null) { | ||
| 873 | samples = iArray; | ||
| 874 | } else { | ||
| 875 | samples = new int [w*h]; | ||
| 876 | } | ||
| 877 | int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b]; | ||
| 878 | int srcOffset = 0; | ||
| 879 | |||
| 880 | for (int i = 0; i < h; i++) { | ||
| 881 | int sampleOffset = lineOffset; | ||
| 882 | for (int j = 0; j < w; j++) { | ||
| 883 | samples[srcOffset++] = data.getElem(bankIndices[b], | ||
| 884 | sampleOffset); | ||
| 885 | sampleOffset += pixelStride; | ||
| 886 | } | ||
| 887 | lineOffset += scanlineStride; | ||
| 888 | } | ||
| 889 | return samples; | ||
| 890 | } | ||
| 891 | |||
| 892 | /** | ||
| 893 | * Sets the data for a single pixel in the specified | ||
| 894 | * <code>DataBuffer</code> from a primitive array of type | ||
| 895 | * <code>TransferType</code>. For a <code>ComponentSampleModel</code>, | ||
| 896 | * this is the same as the data type, and samples are transferred | ||
| 897 | * one per array element. | ||
| 898 | * <p> | ||
| 899 | * The following code illustrates transferring data for one pixel from | ||
| 900 | * <code>DataBuffer</code> <code>db1</code>, whose storage layout is | ||
| 901 | * described by <code>ComponentSampleModel</code> <code>csm1</code>, | ||
| 902 | * to <code>DataBuffer</code> <code>db2</code>, whose storage layout | ||
| 903 | * is described by <code>ComponentSampleModel</code> <code>csm2</code>. | ||
| 904 | * The transfer is usually more efficient than using | ||
| 905 | * <code>getPixel</code> and <code>setPixel</code>. | ||
| 906 | * <pre> | ||
| 907 | * ComponentSampleModel csm1, csm2; | ||
| 908 | * DataBufferInt db1, db2; | ||
| 909 | * csm2.setDataElements(x, y, csm1.getDataElements(x, y, null, db1), | ||
| 910 | * db2); | ||
| 911 | * </pre> | ||
| 912 | * Using <code>getDataElements</code> and <code>setDataElements</code> | ||
| 913 | * to transfer between two <code>DataBuffer/SampleModel</code> pairs | ||
| 914 | * is legitimate if the <code>SampleModel</code> objects have | ||
| 915 | * the same number of bands, corresponding bands have the same number of | ||
| 916 | * bits per sample, and the <code>TransferType</code>s are the same. | ||
| 917 | * <p> | ||
| 918 | * A <code>ClassCastException</code> is thrown if <code>obj</code> is not | ||
| 919 | * a primitive array of type <code>TransferType</code>. | ||
| 920 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if | ||
| 921 | * the coordinates are not in bounds, or if <code>obj</code> is not large | ||
| 922 | * enough to hold the pixel data. | ||
| 923 | * @param x the X coordinate of the pixel location | ||
| 924 | * @param y the Y coordinate of the pixel location | ||
| 925 | * @param obj a primitive array containing pixel data | ||
| 926 | * @param data the DataBuffer containing the image data | ||
| 927 | * @see #getDataElements(int, int, Object, DataBuffer) | ||
| 928 | */ | ||
| 929 | public void setDataElements(int x, int y, Object obj, DataBuffer data) { | ||
| 930 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 931 | throw new ArrayIndexOutOfBoundsException | ||
| 932 | ("Coordinate out of bounds!"); | ||
| 933 | } | ||
| 934 | |||
| 935 | int type = getTransferType(); | ||
| 936 | int numDataElems = getNumDataElements(); | ||
| 937 | int pixelOffset = y*scanlineStride + x*pixelStride; | ||
| 938 | |||
| 939 | switch(type) { | ||
| 940 | |||
| 941 | case DataBuffer.TYPE_BYTE: | ||
| 942 | |||
| 943 | byte[] barray = (byte[])obj; | ||
| 944 | |||
| 945 | for (int i=0; i<numDataElems; i++) { | ||
| 946 | data.setElem(bankIndices[i], pixelOffset + bandOffsets[i], | ||
| 947 | ((int)barray[i])&0xff); | ||
| 948 | } | ||
| 949 | break; | ||
| 950 | |||
| 951 | case DataBuffer.TYPE_USHORT: | ||
| 952 | case DataBuffer.TYPE_SHORT: | ||
| 953 | |||
| 954 | short[] sarray = (short[])obj; | ||
| 955 | |||
| 956 | for (int i=0; i<numDataElems; i++) { | ||
| 957 | data.setElem(bankIndices[i], pixelOffset + bandOffsets[i], | ||
| 958 | ((int)sarray[i])&0xffff); | ||
| 959 | } | ||
| 960 | break; | ||
| 961 | |||
| 962 | case DataBuffer.TYPE_INT: | ||
| 963 | |||
| 964 | int[] iarray = (int[])obj; | ||
| 965 | |||
| 966 | for (int i=0; i<numDataElems; i++) { | ||
| 967 | data.setElem(bankIndices[i], | ||
| 968 | pixelOffset + bandOffsets[i], iarray[i]); | ||
| 969 | } | ||
| 970 | break; | ||
| 971 | |||
| 972 | case DataBuffer.TYPE_FLOAT: | ||
| 973 | |||
| 974 | float[] farray = (float[])obj; | ||
| 975 | |||
| 976 | for (int i=0; i<numDataElems; i++) { | ||
| 977 | data.setElemFloat(bankIndices[i], | ||
| 978 | pixelOffset + bandOffsets[i], farray[i]); | ||
| 979 | } | ||
| 980 | break; | ||
| 981 | |||
| 982 | case DataBuffer.TYPE_DOUBLE: | ||
| 983 | |||
| 984 | double[] darray = (double[])obj; | ||
| 985 | |||
| 986 | for (int i=0; i<numDataElems; i++) { | ||
| 987 | data.setElemDouble(bankIndices[i], | ||
| 988 | pixelOffset + bandOffsets[i], darray[i]); | ||
| 989 | } | ||
| 990 | break; | ||
| 991 | |||
| 992 | } | ||
| 993 | } | ||
| 994 | |||
| 995 | /** | ||
| 996 | * Sets a pixel in the <code>DataBuffer</code> using an int array of | ||
| 997 | * samples for input. An <code>ArrayIndexOutOfBoundsException</code> | ||
| 998 | * might be thrown if the coordinates are | ||
| 999 | * not in bounds. | ||
| 1000 | * @param x The X coordinate of the pixel location | ||
| 1001 | * @param y The Y coordinate of the pixel location | ||
| 1002 | * @param iArray The input samples in an int array | ||
| 1003 | * @param data The DataBuffer containing the image data | ||
| 1004 | * @see #getPixel(int, int, int[], DataBuffer) | ||
| 1005 | */ | ||
| 1006 | public void setPixel(int x, int y, int iArray[], DataBuffer data) { | ||
| 1007 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 1008 | throw new ArrayIndexOutOfBoundsException | ||
| 1009 | ("Coordinate out of bounds!"); | ||
| 1010 | } | ||
| 1011 | int pixelOffset = y*scanlineStride + x*pixelStride; | ||
| 1012 | for (int i=0; i<numBands; i++) { | ||
| 1013 | data.setElem(bankIndices[i], | ||
| 1014 | pixelOffset + bandOffsets[i],iArray[i]); | ||
| 1015 | } | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | /** | ||
| 1019 | * Sets all samples for a rectangle of pixels from an int array containing | ||
| 1020 | * one sample per array element. | ||
| 1021 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the | ||
| 1022 | * coordinates are not in bounds. | ||
| 1023 | * @param x The X coordinate of the upper left pixel location | ||
| 1024 | * @param y The Y coordinate of the upper left pixel location | ||
| 1025 | * @param w The width of the pixel rectangle | ||
| 1026 | * @param h The height of the pixel rectangle | ||
| 1027 | * @param iArray The input samples in an int array | ||
| 1028 | * @param data The DataBuffer containing the image data | ||
| 1029 | * @see #getPixels(int, int, int, int, int[], DataBuffer) | ||
| 1030 | */ | ||
| 1031 | public void setPixels(int x, int y, int w, int h, | ||
| 1032 | int iArray[], DataBuffer data) { | ||
| 1033 | int x1 = x + w; | ||
| 1034 | int y1 = y + h; | ||
| 1035 | |||
| 1036 | if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || | ||
| 1037 | y < 0 || y >= height || h > height || y1 < 0 || y1 > height) | ||
| 1038 | { | ||
| 1039 | throw new ArrayIndexOutOfBoundsException | ||
| 1040 | ("Coordinate out of bounds!"); | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | int lineOffset = y*scanlineStride + x*pixelStride; | ||
| 1044 | int srcOffset = 0; | ||
| 1045 | |||
| 1046 | for (int i = 0; i < h; i++) { | ||
| 1047 | int pixelOffset = lineOffset; | ||
| 1048 | for (int j = 0; j < w; j++) { | ||
| 1049 | for (int k=0; k < numBands; k++) { | ||
| 1050 | data.setElem(bankIndices[k], pixelOffset + bandOffsets[k], | ||
| 1051 | iArray[srcOffset++]); | ||
| 1052 | } | ||
| 1053 | pixelOffset += pixelStride; | ||
| 1054 | } | ||
| 1055 | lineOffset += scanlineStride; | ||
| 1056 | } | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | /** | ||
| 1060 | * Sets a sample in the specified band for the pixel located at (x,y) | ||
| 1061 | * in the <code>DataBuffer</code> using an int for input. | ||
| 1062 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the | ||
| 1063 | * coordinates are not in bounds. | ||
| 1064 | * @param x The X coordinate of the pixel location | ||
| 1065 | * @param y The Y coordinate of the pixel location | ||
| 1066 | * @param b the band to set | ||
| 1067 | * @param s the input sample as an int | ||
| 1068 | * @param data the DataBuffer containing the image data | ||
| 1069 | * @see #getSample(int, int, int, DataBuffer) | ||
| 1070 | */ | ||
| 1071 | public void setSample(int x, int y, int b, int s, | ||
| 1072 | DataBuffer data) { | ||
| 1073 | // Bounds check for 'b' will be performed automatically | ||
| 1074 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 1075 | throw new ArrayIndexOutOfBoundsException | ||
| 1076 | ("Coordinate out of bounds!"); | ||
| 1077 | } | ||
| 1078 | data.setElem(bankIndices[b], | ||
| 1079 | y*scanlineStride + x*pixelStride + bandOffsets[b], s); | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | /** | ||
| 1083 | * Sets a sample in the specified band for the pixel located at (x,y) | ||
| 1084 | * in the <code>DataBuffer</code> using a float for input. | ||
| 1085 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if | ||
| 1086 | * the coordinates are not in bounds. | ||
| 1087 | * @param x The X coordinate of the pixel location | ||
| 1088 | * @param y The Y coordinate of the pixel location | ||
| 1089 | * @param b The band to set | ||
| 1090 | * @param s The input sample as a float | ||
| 1091 | * @param data The DataBuffer containing the image data | ||
| 1092 | * @see #getSample(int, int, int, DataBuffer) | ||
| 1093 | */ | ||
| 1094 | public void setSample(int x, int y, int b, | ||
| 1095 | float s , | ||
| 1096 | DataBuffer data) { | ||
| 1097 | // Bounds check for 'b' will be performed automatically | ||
| 1098 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 1099 | throw new ArrayIndexOutOfBoundsException | ||
| 1100 | ("Coordinate out of bounds!"); | ||
| 1101 | } | ||
| 1102 | data.setElemFloat(bankIndices[b], | ||
| 1103 | y*scanlineStride + x*pixelStride + bandOffsets[b], | ||
| 1104 | s); | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | /** | ||
| 1108 | * Sets a sample in the specified band for the pixel located at (x,y) | ||
| 1109 | * in the <code>DataBuffer</code> using a double for input. | ||
| 1110 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if | ||
| 1111 | * the coordinates are not in bounds. | ||
| 1112 | * @param x The X coordinate of the pixel location | ||
| 1113 | * @param y The Y coordinate of the pixel location | ||
| 1114 | * @param b The band to set | ||
| 1115 | * @param s The input sample as a double | ||
| 1116 | * @param data The DataBuffer containing the image data | ||
| 1117 | * @see #getSample(int, int, int, DataBuffer) | ||
| 1118 | */ | ||
| 1119 | public void setSample(int x, int y, int b, | ||
| 1120 | double s, | ||
| 1121 | DataBuffer data) { | ||
| 1122 | // Bounds check for 'b' will be performed automatically | ||
| 1123 | if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { | ||
| 1124 | throw new ArrayIndexOutOfBoundsException | ||
| 1125 | ("Coordinate out of bounds!"); | ||
| 1126 | } | ||
| 1127 | data.setElemDouble(bankIndices[b], | ||
| 1128 | y*scanlineStride + x*pixelStride + bandOffsets[b], | ||
| 1129 | s); | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | /** | ||
| 1133 | * Sets the samples in the specified band for the specified rectangle | ||
| 1134 | * of pixels from an int array containing one sample per data array element. | ||
| 1135 | * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the | ||
| 1136 | * coordinates are not in bounds. | ||
| 1137 | * @param x The X coordinate of the upper left pixel location | ||
| 1138 | * @param y The Y coordinate of the upper left pixel location | ||
| 1139 | * @param w The width of the pixel rectangle | ||
| 1140 | * @param h The height of the pixel rectangle | ||
| 1141 | * @param b The band to set | ||
| 1142 | * @param iArray The input samples in an int array | ||
| 1143 | * @param data The DataBuffer containing the image data | ||
| 1144 | * @see #getSamples(int, int, int, int, int, int[], DataBuffer) | ||
| 1145 | */ | ||
| 1146 | public void setSamples(int x, int y, int w, int h, int b, | ||
| 1147 | int iArray[], DataBuffer data) { | ||
| 1148 | // Bounds check for 'b' will be performed automatically | ||
| 1149 | if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { | ||
| 1150 | throw new ArrayIndexOutOfBoundsException | ||
| 1151 | ("Coordinate out of bounds!"); | ||
| 1152 | } | ||
| 1153 | int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b]; | ||
| 1154 | int srcOffset = 0; | ||
| 1155 | |||
| 1156 | for (int i = 0; i < h; i++) { | ||
| 1157 | int sampleOffset = lineOffset; | ||
| 1158 | for (int j = 0; j < w; j++) { | ||
| 1159 | data.setElem(bankIndices[b], sampleOffset, iArray[srcOffset++]); | ||
| 1160 | sampleOffset += pixelStride; | ||
| 1161 | } | ||
| 1162 | lineOffset += scanlineStride; | ||
| 1163 | } | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | public boolean equals(Object o) { | ||
| 1167 | if ((o == null) || !(o instanceof ComponentSampleModel)) { | ||
| 1168 | return false; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | ComponentSampleModel that = (ComponentSampleModel)o; | ||
| 1172 | return this.width == that.width && | ||
| 1173 | this.height == that.height && | ||
| 1174 | this.numBands == that.numBands && | ||
| 1175 | this.dataType == that.dataType && | ||
| 1176 | Arrays.equals(this.bandOffsets, that.bandOffsets) && | ||
| 1177 | Arrays.equals(this.bankIndices, that.bankIndices) && | ||
| 1178 | this.numBands == that.numBands && | ||
| 1179 | this.numBanks == that.numBanks && | ||
| 1180 | this.scanlineStride == that.scanlineStride && | ||
| 1181 | this.pixelStride == that.pixelStride; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | // If we implement equals() we must also implement hashCode | ||
| 1185 | public int hashCode() { | ||
| 1186 | int hash = 0; | ||
| 1187 | hash = width; | ||
| 1188 | hash <<= 8; | ||
| 1189 | hash ^= height; | ||
| 1190 | hash <<= 8; | ||
| 1191 | hash ^= numBands; | ||
| 1192 | hash <<= 8; | ||
| 1193 | hash ^= dataType; | ||
| 1194 | hash <<= 8; | ||
| 1195 | for (int i = 0; i < bandOffsets.length; i++) { | ||
| 1196 | hash ^= bandOffsets[i]; | ||
| 1197 | hash <<= 8; | ||
| 1198 | } | ||
| 1199 | for (int i = 0; i < bankIndices.length; i++) { | ||
| 1200 | hash ^= bankIndices[i]; | ||
| 1201 | hash <<= 8; | ||
| 1202 | } | ||
| 1203 | hash ^= numBands; | ||
| 1204 | hash <<= 8; | ||
| 1205 | hash ^= numBanks; | ||
| 1206 | hash <<= 8; | ||
| 1207 | hash ^= scanlineStride; | ||
| 1208 | hash <<= 8; | ||
| 1209 | hash ^= pixelStride; | ||
| 1210 | return hash; | ||
| 1211 | } | ||
| 1212 | } | ||
Binary file not shown.
| @@ -0,0 +1,347 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.color.ICC_Profile; | ||
| 29 | import java.awt.geom.Rectangle2D; | ||
| 30 | import java.awt.Rectangle; | ||
| 31 | import java.awt.RenderingHints; | ||
| 32 | import java.awt.geom.Point2D; | ||
| 33 | import sun.awt.image.ImagingLib; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * This class implements a convolution from the source | ||
| 37 | * to the destination. | ||
| 38 | * Convolution using a convolution kernel is a spatial operation that | ||
| 39 | * computes the output pixel from an input pixel by multiplying the kernel | ||
| 40 | * with the surround of the input pixel. | ||
| 41 | * This allows the output pixel to be affected by the immediate neighborhood | ||
| 42 | * in a way that can be mathematically specified with a kernel. | ||
| 43 | *<p> | ||
| 44 | * This class operates with BufferedImage data in which color components are | ||
| 45 | * premultiplied with the alpha component. If the Source BufferedImage has | ||
| 46 | * an alpha component, and the color components are not premultiplied with | ||
| 47 | * the alpha component, then the data are premultiplied before being | ||
| 48 | * convolved. If the Destination has color components which are not | ||
| 49 | * premultiplied, then alpha is divided out before storing into the | ||
| 50 | * Destination (if alpha is 0, the color components are set to 0). If the | ||
| 51 | * Destination has no alpha component, then the resulting alpha is discarded | ||
| 52 | * after first dividing it out of the color components. | ||
| 53 | * <p> | ||
| 54 | * Rasters are treated as having no alpha channel. If the above treatment | ||
| 55 | * of the alpha channel in BufferedImages is not desired, it may be avoided | ||
| 56 | * by getting the Raster of a source BufferedImage and using the filter method | ||
| 57 | * of this class which works with Rasters. | ||
| 58 | * <p> | ||
| 59 | * If a RenderingHints object is specified in the constructor, the | ||
| 60 | * color rendering hint and the dithering hint may be used when color | ||
| 61 | * conversion is required. | ||
| 62 | *<p> | ||
| 63 | * Note that the Source and the Destination may not be the same object. | ||
| 64 | * @see Kernel | ||
| 65 | * @see java.awt.RenderingHints#KEY_COLOR_RENDERING | ||
| 66 | * @see java.awt.RenderingHints#KEY_DITHERING | ||
| 67 | */ | ||
| 68 | public class ConvolveOp implements BufferedImageOp, RasterOp { | ||
| 69 | Kernel kernel; | ||
| 70 | int edgeHint; | ||
| 71 | RenderingHints hints; | ||
| 72 | /** | ||
| 73 | * Edge condition constants. | ||
| 74 | */ | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Pixels at the edge of the destination image are set to zero. This | ||
| 78 | * is the default. | ||
| 79 | */ | ||
| 80 | |||
| 81 | public static final int EDGE_ZERO_FILL = 0; | ||
| 82 | |||
| 83 | /** | ||
| 84 | * Pixels at the edge of the source image are copied to | ||
| 85 | * the corresponding pixels in the destination without modification. | ||
| 86 | */ | ||
| 87 | public static final int EDGE_NO_OP = 1; | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Constructs a ConvolveOp given a Kernel, an edge condition, and a | ||
| 91 | * RenderingHints object (which may be null). | ||
| 92 | * @param kernel the specified <code>Kernel</code> | ||
| 93 | * @param edgeCondition the specified edge condition | ||
| 94 | * @param hints the specified <code>RenderingHints</code> object | ||
| 95 | * @see Kernel | ||
| 96 | * @see #EDGE_NO_OP | ||
| 97 | * @see #EDGE_ZERO_FILL | ||
| 98 | * @see java.awt.RenderingHints | ||
| 99 | */ | ||
| 100 | public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) { | ||
| 101 | this.kernel = kernel; | ||
| 102 | this.edgeHint = edgeCondition; | ||
| 103 | this.hints = hints; | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Constructs a ConvolveOp given a Kernel. The edge condition | ||
| 108 | * will be EDGE_ZERO_FILL. | ||
| 109 | * @param kernel the specified <code>Kernel</code> | ||
| 110 | * @see Kernel | ||
| 111 | * @see #EDGE_ZERO_FILL | ||
| 112 | */ | ||
| 113 | public ConvolveOp(Kernel kernel) { | ||
| 114 | this.kernel = kernel; | ||
| 115 | this.edgeHint = EDGE_ZERO_FILL; | ||
| 116 | } | ||
| 117 | |||
| 118 | /** | ||
| 119 | * Returns the edge condition. | ||
| 120 | * @return the edge condition of this <code>ConvolveOp</code>. | ||
| 121 | * @see #EDGE_NO_OP | ||
| 122 | * @see #EDGE_ZERO_FILL | ||
| 123 | */ | ||
| 124 | public int getEdgeCondition() { | ||
| 125 | return edgeHint; | ||
| 126 | } | ||
| 127 | |||
| 128 | /** | ||
| 129 | * Returns the Kernel. | ||
| 130 | * @return the <code>Kernel</code> of this <code>ConvolveOp</code>. | ||
| 131 | */ | ||
| 132 | public final Kernel getKernel() { | ||
| 133 | return (Kernel) kernel.clone(); | ||
| 134 | } | ||
| 135 | |||
| 136 | /** | ||
| 137 | * Performs a convolution on BufferedImages. Each component of the | ||
| 138 | * source image will be convolved (including the alpha component, if | ||
| 139 | * present). | ||
| 140 | * If the color model in the source image is not the same as that | ||
| 141 | * in the destination image, the pixels will be converted | ||
| 142 | * in the destination. If the destination image is null, | ||
| 143 | * a BufferedImage will be created with the source ColorModel. | ||
| 144 | * The IllegalArgumentException may be thrown if the source is the | ||
| 145 | * same as the destination. | ||
| 146 | * @param src the source <code>BufferedImage</code> to filter | ||
| 147 | * @param dst the destination <code>BufferedImage</code> for the | ||
| 148 | * filtered <code>src</code> | ||
| 149 | * @return the filtered <code>BufferedImage</code> | ||
| 150 | * @throws NullPointerException if <code>src</code> is <code>null</code> | ||
| 151 | * @throws IllegalArgumentException if <code>src</code> equals | ||
| 152 | * <code>dst</code> | ||
| 153 | * @throws ImagingOpException if <code>src</code> cannot be filtered | ||
| 154 | */ | ||
| 155 | public final BufferedImage filter (BufferedImage src, BufferedImage dst) { | ||
| 156 | if (src == null) { | ||
| 157 | throw new NullPointerException("src image is null"); | ||
| 158 | } | ||
| 159 | if (src == dst) { | ||
| 160 | throw new IllegalArgumentException("src image cannot be the "+ | ||
| 161 | "same as the dst image"); | ||
| 162 | } | ||
| 163 | |||
| 164 | boolean needToConvert = false; | ||
| 165 | ColorModel srcCM = src.getColorModel(); | ||
| 166 | ColorModel dstCM; | ||
| 167 | BufferedImage origDst = dst; | ||
| 168 | |||
| 169 | // Can't convolve an IndexColorModel. Need to expand it | ||
| 170 | if (srcCM instanceof IndexColorModel) { | ||
| 171 | IndexColorModel icm = (IndexColorModel) srcCM; | ||
| 172 | src = icm.convertToIntDiscrete(src.getRaster(), false); | ||
| 173 | srcCM = src.getColorModel(); | ||
| 174 | } | ||
| 175 | |||
| 176 | if (dst == null) { | ||
| 177 | dst = createCompatibleDestImage(src, null); | ||
| 178 | dstCM = srcCM; | ||
| 179 | origDst = dst; | ||
| 180 | } | ||
| 181 | else { | ||
| 182 | dstCM = dst.getColorModel(); | ||
| 183 | if (srcCM.getColorSpace().getType() != | ||
| 184 | dstCM.getColorSpace().getType()) | ||
| 185 | { | ||
| 186 | needToConvert = true; | ||
| 187 | dst = createCompatibleDestImage(src, null); | ||
| 188 | dstCM = dst.getColorModel(); | ||
| 189 | } | ||
| 190 | else if (dstCM instanceof IndexColorModel) { | ||
| 191 | dst = createCompatibleDestImage(src, null); | ||
| 192 | dstCM = dst.getColorModel(); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | if (ImagingLib.filter(this, src, dst) == null) { | ||
| 197 | throw new ImagingOpException ("Unable to convolve src image"); | ||
| 198 | } | ||
| 199 | |||
| 200 | if (needToConvert) { | ||
| 201 | ColorConvertOp ccop = new ColorConvertOp(hints); | ||
| 202 | ccop.filter(dst, origDst); | ||
| 203 | } | ||
| 204 | else if (origDst != dst) { | ||
| 205 | java.awt.Graphics2D g = origDst.createGraphics(); | ||
| 206 | try { | ||
| 207 | g.drawImage(dst, 0, 0, null); | ||
| 208 | } finally { | ||
| 209 | g.dispose(); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | return origDst; | ||
| 214 | } | ||
| 215 | |||
| 216 | /** | ||
| 217 | * Performs a convolution on Rasters. Each band of the source Raster | ||
| 218 | * will be convolved. | ||
| 219 | * The source and destination must have the same number of bands. | ||
| 220 | * If the destination Raster is null, a new Raster will be created. | ||
| 221 | * The IllegalArgumentException may be thrown if the source is | ||
| 222 | * the same as the destination. | ||
| 223 | * @param src the source <code>Raster</code> to filter | ||
| 224 | * @param dst the destination <code>WritableRaster</code> for the | ||
| 225 | * filtered <code>src</code> | ||
| 226 | * @return the filtered <code>WritableRaster</code> | ||
| 227 | * @throws NullPointerException if <code>src</code> is <code>null</code> | ||
| 228 | * @throws ImagingOpException if <code>src</code> and <code>dst</code> | ||
| 229 | * do not have the same number of bands | ||
| 230 | * @throws ImagingOpException if <code>src</code> cannot be filtered | ||
| 231 | * @throws IllegalArgumentException if <code>src</code> equals | ||
| 232 | * <code>dst</code> | ||
| 233 | */ | ||
| 234 | public final WritableRaster filter (Raster src, WritableRaster dst) { | ||
| 235 | if (dst == null) { | ||
| 236 | dst = createCompatibleDestRaster(src); | ||
| 237 | } | ||
| 238 | else if (src == dst) { | ||
| 239 | throw new IllegalArgumentException("src image cannot be the "+ | ||
| 240 | "same as the dst image"); | ||
| 241 | } | ||
| 242 | else if (src.getNumBands() != dst.getNumBands()) { | ||
| 243 | throw new ImagingOpException("Different number of bands in src "+ | ||
| 244 | " and dst Rasters"); | ||
| 245 | } | ||
| 246 | |||
| 247 | if (ImagingLib.filter(this, src, dst) == null) { | ||
| 248 | throw new ImagingOpException ("Unable to convolve src image"); | ||
| 249 | } | ||
| 250 | |||
| 251 | return dst; | ||
| 252 | } | ||
| 253 | |||
| 254 | /** | ||
| 255 | * Creates a zeroed destination image with the correct size and number | ||
| 256 | * of bands. If destCM is null, an appropriate ColorModel will be used. | ||
| 257 | * @param src Source image for the filter operation. | ||
| 258 | * @param destCM ColorModel of the destination. Can be null. | ||
| 259 | * @return a destination <code>BufferedImage</code> with the correct | ||
| 260 | * size and number of bands. | ||
| 261 | */ | ||
| 262 | public BufferedImage createCompatibleDestImage(BufferedImage src, | ||
| 263 | ColorModel destCM) { | ||
| 264 | BufferedImage image; | ||
| 265 | |||
| 266 | int w = src.getWidth(); | ||
| 267 | int h = src.getHeight(); | ||
| 268 | |||
| 269 | WritableRaster wr = null; | ||
| 270 | |||
| 271 | if (destCM == null) { | ||
| 272 | destCM = src.getColorModel(); | ||
| 273 | // Not much support for ICM | ||
| 274 | if (destCM instanceof IndexColorModel) { | ||
| 275 | destCM = ColorModel.getRGBdefault(); | ||
| 276 | } else { | ||
| 277 | /* Create destination image as similar to the source | ||
| 278 | * as it possible... | ||
| 279 | */ | ||
| 280 | wr = src.getData().createCompatibleWritableRaster(w, h); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | if (wr == null) { | ||
| 285 | /* This is the case when destination color model | ||
| 286 | * was explicitly specified (and it may be not compatible | ||
| 287 | * with source raster structure) or source is indexed image. | ||
| 288 | * We should use destination color model to create compatible | ||
| 289 | * destination raster here. | ||
| 290 | */ | ||
| 291 | wr = destCM.createCompatibleWritableRaster(w, h); | ||
| 292 | } | ||
| 293 | |||
| 294 | image = new BufferedImage (destCM, wr, | ||
| 295 | destCM.isAlphaPremultiplied(), null); | ||
| 296 | |||
| 297 | return image; | ||
| 298 | } | ||
| 299 | |||
| 300 | /** | ||
| 301 | * Creates a zeroed destination Raster with the correct size and number | ||
| 302 | * of bands, given this source. | ||
| 303 | */ | ||
| 304 | public WritableRaster createCompatibleDestRaster(Raster src) { | ||
| 305 | return src.createCompatibleWritableRaster(); | ||
| 306 | } | ||
| 307 | |||
| 308 | /** | ||
| 309 | * Returns the bounding box of the filtered destination image. Since | ||
| 310 | * this is not a geometric operation, the bounding box does not | ||
| 311 | * change. | ||
| 312 | */ | ||
| 313 | public final Rectangle2D getBounds2D(BufferedImage src) { | ||
| 314 | return getBounds2D(src.getRaster()); | ||
| 315 | } | ||
| 316 | |||
| 317 | /** | ||
| 318 | * Returns the bounding box of the filtered destination Raster. Since | ||
| 319 | * this is not a geometric operation, the bounding box does not | ||
| 320 | * change. | ||
| 321 | */ | ||
| 322 | public final Rectangle2D getBounds2D(Raster src) { | ||
| 323 | return src.getBounds(); | ||
| 324 | } | ||
| 325 | |||
| 326 | /** | ||
| 327 | * Returns the location of the destination point given a | ||
| 328 | * point in the source. If dstPt is non-null, it will | ||
| 329 | * be used to hold the return value. Since this is not a geometric | ||
| 330 | * operation, the srcPt will equal the dstPt. | ||
| 331 | */ | ||
| 332 | public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { | ||
| 333 | if (dstPt == null) { | ||
| 334 | dstPt = new Point2D.Float(); | ||
| 335 | } | ||
| 336 | dstPt.setLocation(srcPt.getX(), srcPt.getY()); | ||
| 337 | |||
| 338 | return dstPt; | ||
| 339 | } | ||
| 340 | |||
| 341 | /** | ||
| 342 | * Returns the rendering hints for this op. | ||
| 343 | */ | ||
| 344 | public final RenderingHints getRenderingHints() { | ||
| 345 | return hints; | ||
| 346 | } | ||
| 347 | } | ||
Binary file not shown.
| @@ -0,0 +1,193 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.image.ImageConsumer; | ||
| 29 | import java.awt.image.ColorModel; | ||
| 30 | import java.util.Hashtable; | ||
| 31 | import java.awt.Rectangle; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * An ImageFilter class for cropping images. | ||
| 35 | * This class extends the basic ImageFilter Class to extract a given | ||
| 36 | * rectangular region of an existing Image and provide a source for a | ||
| 37 | * new image containing just the extracted region. It is meant to | ||
| 38 | * be used in conjunction with a FilteredImageSource object to produce | ||
| 39 | * cropped versions of existing images. | ||
| 40 | * | ||
| 41 | * @see FilteredImageSource | ||
| 42 | * @see ImageFilter | ||
| 43 | * | ||
| 44 | * @author Jim Graham | ||
| 45 | */ | ||
| 46 | public class CropImageFilter extends ImageFilter { | ||
| 47 | int cropX; | ||
| 48 | int cropY; | ||
| 49 | int cropW; | ||
| 50 | int cropH; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Constructs a CropImageFilter that extracts the absolute rectangular | ||
| 54 | * region of pixels from its source Image as specified by the x, y, | ||
| 55 | * w, and h parameters. | ||
| 56 | * @param x the x location of the top of the rectangle to be extracted | ||
| 57 | * @param y the y location of the top of the rectangle to be extracted | ||
| 58 | * @param w the width of the rectangle to be extracted | ||
| 59 | * @param h the height of the rectangle to be extracted | ||
| 60 | */ | ||
| 61 | public CropImageFilter(int x, int y, int w, int h) { | ||
| 62 | cropX = x; | ||
| 63 | cropY = y; | ||
| 64 | cropW = w; | ||
| 65 | cropH = h; | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Passes along the properties from the source object after adding a | ||
| 70 | * property indicating the cropped region. | ||
| 71 | * This method invokes <code>super.setProperties</code>, | ||
| 72 | * which might result in additional properties being added. | ||
| 73 | * <p> | ||
| 74 | * Note: This method is intended to be called by the | ||
| 75 | * <code>ImageProducer</code> of the <code>Image</code> whose pixels | ||
| 76 | * are being filtered. Developers using | ||
| 77 | * this class to filter pixels from an image should avoid calling | ||
| 78 | * this method directly since that operation could interfere | ||
| 79 | * with the filtering operation. | ||
| 80 | */ | ||
| 81 | public void setProperties(Hashtable<?,?> props) { | ||
| 82 | Hashtable<Object,Object> p = (Hashtable<Object,Object>)props.clone(); | ||
| 83 | p.put("croprect", new Rectangle(cropX, cropY, cropW, cropH)); | ||
| 84 | super.setProperties(p); | ||
| 85 | } | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Override the source image's dimensions and pass the dimensions | ||
| 89 | * of the rectangular cropped region to the ImageConsumer. | ||
| 90 | * <p> | ||
| 91 | * Note: This method is intended to be called by the | ||
| 92 | * <code>ImageProducer</code> of the <code>Image</code> whose | ||
| 93 | * pixels are being filtered. Developers using | ||
| 94 | * this class to filter pixels from an image should avoid calling | ||
| 95 | * this method directly since that operation could interfere | ||
| 96 | * with the filtering operation. | ||
| 97 | * @see ImageConsumer | ||
| 98 | */ | ||
| 99 | public void setDimensions(int w, int h) { | ||
| 100 | consumer.setDimensions(cropW, cropH); | ||
| 101 | } | ||
| 102 | |||
| 103 | /** | ||
| 104 | * Determine whether the delivered byte pixels intersect the region to | ||
| 105 | * be extracted and passes through only that subset of pixels that | ||
| 106 | * appear in the output region. | ||
| 107 | * <p> | ||
| 108 | * Note: This method is intended to be called by the | ||
| 109 | * <code>ImageProducer</code> of the <code>Image</code> whose | ||
| 110 | * pixels are being filtered. Developers using | ||
| 111 | * this class to filter pixels from an image should avoid calling | ||
| 112 | * this method directly since that operation could interfere | ||
| 113 | * with the filtering operation. | ||
| 114 | */ | ||
| 115 | public void setPixels(int x, int y, int w, int h, | ||
| 116 | ColorModel model, byte pixels[], int off, | ||
| 117 | int scansize) { | ||
| 118 | int x1 = x; | ||
| 119 | if (x1 < cropX) { | ||
| 120 | x1 = cropX; | ||
| 121 | } | ||
| 122 | int x2 = addWithoutOverflow(x, w); | ||
| 123 | if (x2 > cropX + cropW) { | ||
| 124 | x2 = cropX + cropW; | ||
| 125 | } | ||
| 126 | int y1 = y; | ||
| 127 | if (y1 < cropY) { | ||
| 128 | y1 = cropY; | ||
| 129 | } | ||
| 130 | |||
| 131 | int y2 = addWithoutOverflow(y, h); | ||
| 132 | if (y2 > cropY + cropH) { | ||
| 133 | y2 = cropY + cropH; | ||
| 134 | } | ||
| 135 | if (x1 >= x2 || y1 >= y2) { | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | consumer.setPixels(x1 - cropX, y1 - cropY, (x2 - x1), (y2 - y1), | ||
| 139 | model, pixels, | ||
| 140 | off + (y1 - y) * scansize + (x1 - x), scansize); | ||
| 141 | } | ||
| 142 | |||
| 143 | /** | ||
| 144 | * Determine if the delivered int pixels intersect the region to | ||
| 145 | * be extracted and pass through only that subset of pixels that | ||
| 146 | * appear in the output region. | ||
| 147 | * <p> | ||
| 148 | * Note: This method is intended to be called by the | ||
| 149 | * <code>ImageProducer</code> of the <code>Image</code> whose | ||
| 150 | * pixels are being filtered. Developers using | ||
| 151 | * this class to filter pixels from an image should avoid calling | ||
| 152 | * this method directly since that operation could interfere | ||
| 153 | * with the filtering operation. | ||
| 154 | */ | ||
| 155 | public void setPixels(int x, int y, int w, int h, | ||
| 156 | ColorModel model, int pixels[], int off, | ||
| 157 | int scansize) { | ||
| 158 | int x1 = x; | ||
| 159 | if (x1 < cropX) { | ||
| 160 | x1 = cropX; | ||
| 161 | } | ||
| 162 | int x2 = addWithoutOverflow(x, w); | ||
| 163 | if (x2 > cropX + cropW) { | ||
| 164 | x2 = cropX + cropW; | ||
| 165 | } | ||
| 166 | int y1 = y; | ||
| 167 | if (y1 < cropY) { | ||
| 168 | y1 = cropY; | ||
| 169 | } | ||
| 170 | |||
| 171 | int y2 = addWithoutOverflow(y, h); | ||
| 172 | if (y2 > cropY + cropH) { | ||
| 173 | y2 = cropY + cropH; | ||
| 174 | } | ||
| 175 | if (x1 >= x2 || y1 >= y2) { | ||
| 176 | return; | ||
| 177 | } | ||
| 178 | consumer.setPixels(x1 - cropX, y1 - cropY, (x2 - x1), (y2 - y1), | ||
| 179 | model, pixels, | ||
| 180 | off + (y1 - y) * scansize + (x1 - x), scansize); | ||
| 181 | } | ||
| 182 | |||
| 183 | //check for potential overflow (see bug 4801285) | ||
| 184 | private int addWithoutOverflow(int x, int w) { | ||
| 185 | int x2 = x + w; | ||
| 186 | if ( x > 0 && w > 0 && x2 < 0 ) { | ||
| 187 | x2 = Integer.MAX_VALUE; | ||
| 188 | } else if( x < 0 && w < 0 && x2 > 0 ) { | ||
| 189 | x2 = Integer.MIN_VALUE; | ||
| 190 | } | ||
| 191 | return x2; | ||
| 192 | } | ||
| 193 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,541 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 | /* **************************************************************** | ||
| 27 | ****************************************************************** | ||
| 28 | ****************************************************************** | ||
| 29 | *** COPYRIGHT (c) Eastman Kodak Company, 1997 | ||
| 30 | *** As an unpublished work pursuant to Title 17 of the United | ||
| 31 | *** States Code. All rights reserved. | ||
| 32 | ****************************************************************** | ||
| 33 | ****************************************************************** | ||
| 34 | ******************************************************************/ | ||
| 35 | |||
| 36 | package java.awt.image; | ||
| 37 | |||
| 38 | import sun.java2d.StateTrackable.State; | ||
| 39 | import static sun.java2d.StateTrackable.State.*; | ||
| 40 | import sun.java2d.StateTrackableDelegate; | ||
| 41 | |||
| 42 | import sun.awt.image.SunWritableRaster; | ||
| 43 | |||
| 44 | /** | ||
| 45 | * This class exists to wrap one or more data arrays. Each data array in | ||
| 46 | * the DataBuffer is referred to as a bank. Accessor methods for getting | ||
| 47 | * and setting elements of the DataBuffer's banks exist with and without | ||
| 48 | * a bank specifier. The methods without a bank specifier use the default 0th | ||
| 49 | * bank. The DataBuffer can optionally take an offset per bank, so that | ||
| 50 | * data in an existing array can be used even if the interesting data | ||
| 51 | * doesn't start at array location zero. Getting or setting the 0th | ||
| 52 | * element of a bank, uses the (0+offset)th element of the array. The | ||
| 53 | * size field specifies how much of the data array is available for | ||
| 54 | * use. Size + offset for a given bank should never be greater | ||
| 55 | * than the length of the associated data array. The data type of | ||
| 56 | * a data buffer indicates the type of the data array(s) and may also | ||
| 57 | * indicate additional semantics, e.g. storing unsigned 8-bit data | ||
| 58 | * in elements of a byte array. The data type may be TYPE_UNDEFINED | ||
| 59 | * or one of the types defined below. Other types may be added in | ||
| 60 | * the future. Generally, an object of class DataBuffer will be cast down | ||
| 61 | * to one of its data type specific subclasses to access data type specific | ||
| 62 | * methods for improved performance. Currently, the Java 2D(tm) API | ||
| 63 | * image classes use TYPE_BYTE, TYPE_USHORT, TYPE_INT, TYPE_SHORT, | ||
| 64 | * TYPE_FLOAT, and TYPE_DOUBLE DataBuffers to store image data. | ||
| 65 | * @see java.awt.image.Raster | ||
| 66 | * @see java.awt.image.SampleModel | ||
| 67 | */ | ||
| 68 | public abstract class DataBuffer { | ||
| 69 | |||
| 70 | /** Tag for unsigned byte data. */ | ||
| 71 | public static final int TYPE_BYTE = 0; | ||
| 72 | |||
| 73 | /** Tag for unsigned short data. */ | ||
| 74 | public static final int TYPE_USHORT = 1; | ||
| 75 | |||
| 76 | /** Tag for signed short data. Placeholder for future use. */ | ||
| 77 | public static final int TYPE_SHORT = 2; | ||
| 78 | |||
| 79 | /** Tag for int data. */ | ||
| 80 | public static final int TYPE_INT = 3; | ||
| 81 | |||
| 82 | /** Tag for float data. Placeholder for future use. */ | ||
| 83 | public static final int TYPE_FLOAT = 4; | ||
| 84 | |||
| 85 | /** Tag for double data. Placeholder for future use. */ | ||
| 86 | public static final int TYPE_DOUBLE = 5; | ||
| 87 | |||
| 88 | /** Tag for undefined data. */ | ||
| 89 | public static final int TYPE_UNDEFINED = 32; | ||
| 90 | |||
| 91 | /** The data type of this DataBuffer. */ | ||
| 92 | protected int dataType; | ||
| 93 | |||
| 94 | /** The number of banks in this DataBuffer. */ | ||
| 95 | protected int banks; | ||
| 96 | |||
| 97 | /** Offset into default (first) bank from which to get the first element. */ | ||
| 98 | protected int offset; | ||
| 99 | |||
| 100 | /** Usable size of all banks. */ | ||
| 101 | protected int size; | ||
| 102 | |||
| 103 | /** Offsets into all banks. */ | ||
| 104 | protected int offsets[]; | ||
| 105 | |||
| 106 | /* The current StateTrackable state. */ | ||
| 107 | StateTrackableDelegate theTrackable; | ||
| 108 | |||
| 109 | /** Size of the data types indexed by DataType tags defined above. */ | ||
| 110 | private static final int dataTypeSize[] = {8,16,16,32,32,64}; | ||
| 111 | |||
| 112 | /** Returns the size (in bits) of the data type, given a datatype tag. | ||
| 113 | * @param type the value of one of the defined datatype tags | ||
| 114 | * @return the size of the data type | ||
| 115 | * @throws IllegalArgumentException if <code>type</code> is less than | ||
| 116 | * zero or greater than {@link #TYPE_DOUBLE} | ||
| 117 | */ | ||
| 118 | public static int getDataTypeSize(int type) { | ||
| 119 | if (type < TYPE_BYTE || type > TYPE_DOUBLE) { | ||
| 120 | throw new IllegalArgumentException("Unknown data type "+type); | ||
| 121 | } | ||
| 122 | return dataTypeSize[type]; | ||
| 123 | } | ||
| 124 | |||
| 125 | /** | ||
| 126 | * Constructs a DataBuffer containing one bank of the specified | ||
| 127 | * data type and size. | ||
| 128 | * | ||
| 129 | * @param dataType the data type of this <code>DataBuffer</code> | ||
| 130 | * @param size the size of the banks | ||
| 131 | */ | ||
| 132 | protected DataBuffer(int dataType, int size) { | ||
| 133 | this(UNTRACKABLE, dataType, size); | ||
| 134 | } | ||
| 135 | |||
| 136 | /** | ||
| 137 | * Constructs a DataBuffer containing one bank of the specified | ||
| 138 | * data type and size with the indicated initial {@link State State}. | ||
| 139 | * | ||
| 140 | * @param initialState the initial {@link State State} state of the data | ||
| 141 | * @param dataType the data type of this <code>DataBuffer</code> | ||
| 142 | * @param size the size of the banks | ||
| 143 | * @since 1.7 | ||
| 144 | */ | ||
| 145 | DataBuffer(State initialState, | ||
| 146 | int dataType, int size) | ||
| 147 | { | ||
| 148 | this.theTrackable = StateTrackableDelegate.createInstance(initialState); | ||
| 149 | this.dataType = dataType; | ||
| 150 | this.banks = 1; | ||
| 151 | this.size = size; | ||
| 152 | this.offset = 0; | ||
| 153 | this.offsets = new int[1]; // init to 0 by new | ||
| 154 | } | ||
| 155 | |||
| 156 | /** | ||
| 157 | * Constructs a DataBuffer containing the specified number of | ||
| 158 | * banks. Each bank has the specified size and an offset of 0. | ||
| 159 | * | ||
| 160 | * @param dataType the data type of this <code>DataBuffer</code> | ||
| 161 | * @param size the size of the banks | ||
| 162 | * @param numBanks the number of banks in this | ||
| 163 | * <code>DataBuffer</code> | ||
| 164 | */ | ||
| 165 | protected DataBuffer(int dataType, int size, int numBanks) { | ||
| 166 | this(UNTRACKABLE, dataType, size, numBanks); | ||
| 167 | } | ||
| 168 | |||
| 169 | /** | ||
| 170 | * Constructs a DataBuffer containing the specified number of | ||
| 171 | * banks with the indicated initial {@link State State}. | ||
| 172 | * Each bank has the specified size and an offset of 0. | ||
| 173 | * | ||
| 174 | * @param initialState the initial {@link State State} state of the data | ||
| 175 | * @param dataType the data type of this <code>DataBuffer</code> | ||
| 176 | * @param size the size of the banks | ||
| 177 | * @param numBanks the number of banks in this | ||
| 178 | * <code>DataBuffer</code> | ||
| 179 | * @since 1.7 | ||
| 180 | */ | ||
| 181 | DataBuffer(State initialState, | ||
| 182 | int dataType, int size, int numBanks) | ||
| 183 | { | ||
| 184 | this.theTrackable = StateTrackableDelegate.createInstance(initialState); | ||
| 185 | this.dataType = dataType; | ||
| 186 | this.banks = numBanks; | ||
| 187 | this.size = size; | ||
| 188 | this.offset = 0; | ||
| 189 | this.offsets = new int[banks]; // init to 0 by new | ||
| 190 | } | ||
| 191 | |||
| 192 | /** | ||
| 193 | * Constructs a DataBuffer that contains the specified number | ||
| 194 | * of banks. Each bank has the specified datatype, size and offset. | ||
| 195 | * | ||
| 196 | * @param dataType the data type of this <code>DataBuffer</code> | ||
| 197 | * @param size the size of the banks | ||
| 198 | * @param numBanks the number of banks in this | ||
| 199 | * <code>DataBuffer</code> | ||
| 200 | * @param offset the offset for each bank | ||
| 201 | */ | ||
| 202 | protected DataBuffer(int dataType, int size, int numBanks, int offset) { | ||
| 203 | this(UNTRACKABLE, dataType, size, numBanks, offset); | ||
| 204 | } | ||
| 205 | |||
| 206 | /** | ||
| 207 | * Constructs a DataBuffer that contains the specified number | ||
| 208 | * of banks with the indicated initial {@link State State}. | ||
| 209 | * Each bank has the specified datatype, size and offset. | ||
| 210 | * | ||
| 211 | * @param initialState the initial {@link State State} state of the data | ||
| 212 | * @param dataType the data type of this <code>DataBuffer</code> | ||
| 213 | * @param size the size of the banks | ||
| 214 | * @param numBanks the number of banks in this | ||
| 215 | * <code>DataBuffer</code> | ||
| 216 | * @param offset the offset for each bank | ||
| 217 | * @since 1.7 | ||
| 218 | */ | ||
| 219 | DataBuffer(State initialState, | ||
| 220 | int dataType, int size, int numBanks, int offset) | ||
| 221 | { | ||
| 222 | this.theTrackable = StateTrackableDelegate.createInstance(initialState); | ||
| 223 | this.dataType = dataType; | ||
| 224 | this.banks = numBanks; | ||
| 225 | this.size = size; | ||
| 226 | this.offset = offset; | ||
| 227 | this.offsets = new int[numBanks]; | ||
| 228 | for (int i = 0; i < numBanks; i++) { | ||
| 229 | this.offsets[i] = offset; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * Constructs a DataBuffer which contains the specified number | ||
| 235 | * of banks. Each bank has the specified datatype and size. The | ||
| 236 | * offset for each bank is specified by its respective entry in | ||
| 237 | * the offsets array. | ||
| 238 | * | ||
| 239 | * @param dataType the data type of this <code>DataBuffer</code> | ||
| 240 | * @param size the size of the banks | ||
| 241 | * @param numBanks the number of banks in this | ||
| 242 | * <code>DataBuffer</code> | ||
| 243 | * @param offsets an array containing an offset for each bank. | ||
| 244 | * @throws ArrayIndexOutOfBoundsException if <code>numBanks</code> | ||
| 245 | * does not equal the length of <code>offsets</code> | ||
| 246 | */ | ||
| 247 | protected DataBuffer(int dataType, int size, int numBanks, int offsets[]) { | ||
| 248 | this(UNTRACKABLE, dataType, size, numBanks, offsets); | ||
| 249 | } | ||
| 250 | |||
| 251 | /** | ||
| 252 | * Constructs a DataBuffer which contains the specified number | ||
| 253 | * of banks with the indicated initial {@link State State}. | ||
| 254 | * Each bank has the specified datatype and size. The | ||
| 255 | * offset for each bank is specified by its respective entry in | ||
| 256 | * the offsets array. | ||
| 257 | * | ||
| 258 | * @param initialState the initial {@link State State} state of the data | ||
| 259 | * @param dataType the data type of this <code>DataBuffer</code> | ||
| 260 | * @param size the size of the banks | ||
| 261 | * @param numBanks the number of banks in this | ||
| 262 | * <code>DataBuffer</code> | ||
| 263 | * @param offsets an array containing an offset for each bank. | ||
| 264 | * @throws ArrayIndexOutOfBoundsException if <code>numBanks</code> | ||
| 265 | * does not equal the length of <code>offsets</code> | ||
| 266 | * @since 1.7 | ||
| 267 | */ | ||
| 268 | DataBuffer(State initialState, | ||
| 269 | int dataType, int size, int numBanks, int offsets[]) | ||
| 270 | { | ||
| 271 | if (numBanks != offsets.length) { | ||
| 272 | throw new ArrayIndexOutOfBoundsException("Number of banks" + | ||
| 273 | " does not match number of bank offsets"); | ||
| 274 | } | ||
| 275 | this.theTrackable = StateTrackableDelegate.createInstance(initialState); | ||
| 276 | this.dataType = dataType; | ||
| 277 | this.banks = numBanks; | ||
| 278 | this.size = size; | ||
| 279 | this.offset = offsets[0]; | ||
| 280 | this.offsets = (int[])offsets.clone(); | ||
| 281 | } | ||
| 282 | |||
| 283 | /** Returns the data type of this DataBuffer. | ||
| 284 | * @return the data type of this <code>DataBuffer</code>. | ||
| 285 | */ | ||
| 286 | public int getDataType() { | ||
| 287 | return dataType; | ||
| 288 | } | ||
| 289 | |||
| 290 | /** Returns the size (in array elements) of all banks. | ||
| 291 | * @return the size of all banks. | ||
| 292 | */ | ||
| 293 | public int getSize() { | ||
| 294 | return size; | ||
| 295 | } | ||
| 296 | |||
| 297 | /** Returns the offset of the default bank in array elements. | ||
| 298 | * @return the offset of the default bank. | ||
| 299 | */ | ||
| 300 | public int getOffset() { | ||
| 301 | return offset; | ||
| 302 | } | ||
| 303 | |||
| 304 | /** Returns the offsets (in array elements) of all the banks. | ||
| 305 | * @return the offsets of all banks. | ||
| 306 | */ | ||
| 307 | public int[] getOffsets() { | ||
| 308 | return (int[])offsets.clone(); | ||
| 309 | } | ||
| 310 | |||
| 311 | /** Returns the number of banks in this DataBuffer. | ||
| 312 | * @return the number of banks. | ||
| 313 | */ | ||
| 314 | public int getNumBanks() { | ||
| 315 | return banks; | ||
| 316 | } | ||
| 317 | |||
| 318 | /** | ||
| 319 | * Returns the requested data array element from the first (default) bank | ||
| 320 | * as an integer. | ||
| 321 | * @param i the index of the requested data array element | ||
| 322 | * @return the data array element at the specified index. | ||
| 323 | * @see #setElem(int, int) | ||
| 324 | * @see #setElem(int, int, int) | ||
| 325 | */ | ||
| 326 | public int getElem(int i) { | ||
| 327 | return getElem(0,i); | ||
| 328 | } | ||
| 329 | |||
| 330 | /** | ||
| 331 | * Returns the requested data array element from the specified bank | ||
| 332 | * as an integer. | ||
| 333 | * @param bank the specified bank | ||
| 334 | * @param i the index of the requested data array element | ||
| 335 | * @return the data array element at the specified index from the | ||
| 336 | * specified bank at the specified index. | ||
| 337 | * @see #setElem(int, int) | ||
| 338 | * @see #setElem(int, int, int) | ||
| 339 | */ | ||
| 340 | public abstract int getElem(int bank, int i); | ||
| 341 | |||
| 342 | /** | ||
| 343 | * Sets the requested data array element in the first (default) bank | ||
| 344 | * from the given integer. | ||
| 345 | * @param i the specified index into the data array | ||
| 346 | * @param val the data to set the element at the specified index in | ||
| 347 | * the data array | ||
| 348 | * @see #getElem(int) | ||
| 349 | * @see #getElem(int, int) | ||
| 350 | */ | ||
| 351 | public void setElem(int i, int val) { | ||
| 352 | setElem(0,i,val); | ||
| 353 | } | ||
| 354 | |||
| 355 | /** | ||
| 356 | * Sets the requested data array element in the specified bank | ||
| 357 | * from the given integer. | ||
| 358 | * @param bank the specified bank | ||
| 359 | * @param i the specified index into the data array | ||
| 360 | * @param val the data to set the element in the specified bank | ||
| 361 | * at the specified index in the data array | ||
| 362 | * @see #getElem(int) | ||
| 363 | * @see #getElem(int, int) | ||
| 364 | */ | ||
| 365 | public abstract void setElem(int bank, int i, int val); | ||
| 366 | |||
| 367 | /** | ||
| 368 | * Returns the requested data array element from the first (default) bank | ||
| 369 | * as a float. The implementation in this class is to cast getElem(i) | ||
| 370 | * to a float. Subclasses may override this method if another | ||
| 371 | * implementation is needed. | ||
| 372 | * @param i the index of the requested data array element | ||
| 373 | * @return a float value representing the data array element at the | ||
| 374 | * specified index. | ||
| 375 | * @see #setElemFloat(int, float) | ||
| 376 | * @see #setElemFloat(int, int, float) | ||
| 377 | */ | ||
| 378 | public float getElemFloat(int i) { | ||
| 379 | return (float)getElem(i); | ||
| 380 | } | ||
| 381 | |||
| 382 | /** | ||
| 383 | * Returns the requested data array element from the specified bank | ||
| 384 | * as a float. The implementation in this class is to cast | ||
| 385 | * {@link #getElem(int, int)} | ||
| 386 | * to a float. Subclasses can override this method if another | ||
| 387 | * implementation is needed. | ||
| 388 | * @param bank the specified bank | ||
| 389 | * @param i the index of the requested data array element | ||
| 390 | * @return a float value representing the data array element from the | ||
| 391 | * specified bank at the specified index. | ||
| 392 | * @see #setElemFloat(int, float) | ||
| 393 | * @see #setElemFloat(int, int, float) | ||
| 394 | */ | ||
| 395 | public float getElemFloat(int bank, int i) { | ||
| 396 | return (float)getElem(bank,i); | ||
| 397 | } | ||
| 398 | |||
| 399 | /** | ||
| 400 | * Sets the requested data array element in the first (default) bank | ||
| 401 | * from the given float. The implementation in this class is to cast | ||
| 402 | * val to an int and call {@link #setElem(int, int)}. Subclasses | ||
| 403 | * can override this method if another implementation is needed. | ||
| 404 | * @param i the specified index | ||
| 405 | * @param val the value to set the element at the specified index in | ||
| 406 | * the data array | ||
| 407 | * @see #getElemFloat(int) | ||
| 408 | * @see #getElemFloat(int, int) | ||
| 409 | */ | ||
| 410 | public void setElemFloat(int i, float val) { | ||
| 411 | setElem(i,(int)val); | ||
| 412 | } | ||
| 413 | |||
| 414 | /** | ||
| 415 | * Sets the requested data array element in the specified bank | ||
| 416 | * from the given float. The implementation in this class is to cast | ||
| 417 | * val to an int and call {@link #setElem(int, int)}. Subclasses can | ||
| 418 | * override this method if another implementation is needed. | ||
| 419 | * @param bank the specified bank | ||
| 420 | * @param i the specified index | ||
| 421 | * @param val the value to set the element in the specified bank at | ||
| 422 | * the specified index in the data array | ||
| 423 | * @see #getElemFloat(int) | ||
| 424 | * @see #getElemFloat(int, int) | ||
| 425 | */ | ||
| 426 | public void setElemFloat(int bank, int i, float val) { | ||
| 427 | setElem(bank,i,(int)val); | ||
| 428 | } | ||
| 429 | |||
| 430 | /** | ||
| 431 | * Returns the requested data array element from the first (default) bank | ||
| 432 | * as a double. The implementation in this class is to cast | ||
| 433 | * {@link #getElem(int)} | ||
| 434 | * to a double. Subclasses can override this method if another | ||
| 435 | * implementation is needed. | ||
| 436 | * @param i the specified index | ||
| 437 | * @return a double value representing the element at the specified | ||
| 438 | * index in the data array. | ||
| 439 | * @see #setElemDouble(int, double) | ||
| 440 | * @see #setElemDouble(int, int, double) | ||
| 441 | */ | ||
| 442 | public double getElemDouble(int i) { | ||
| 443 | return (double)getElem(i); | ||
| 444 | } | ||
| 445 | |||
| 446 | /** | ||
| 447 | * Returns the requested data array element from the specified bank as | ||
| 448 | * a double. The implementation in this class is to cast getElem(bank, i) | ||
| 449 | * to a double. Subclasses may override this method if another | ||
| 450 | * implementation is needed. | ||
| 451 | * @param bank the specified bank | ||
| 452 | * @param i the specified index | ||
| 453 | * @return a double value representing the element from the specified | ||
| 454 | * bank at the specified index in the data array. | ||
| 455 | * @see #setElemDouble(int, double) | ||
| 456 | * @see #setElemDouble(int, int, double) | ||
| 457 | */ | ||
| 458 | public double getElemDouble(int bank, int i) { | ||
| 459 | return (double)getElem(bank,i); | ||
| 460 | } | ||
| 461 | |||
| 462 | /** | ||
| 463 | * Sets the requested data array element in the first (default) bank | ||
| 464 | * from the given double. The implementation in this class is to cast | ||
| 465 | * val to an int and call {@link #setElem(int, int)}. Subclasses can | ||
| 466 | * override this method if another implementation is needed. | ||
| 467 | * @param i the specified index | ||
| 468 | * @param val the value to set the element at the specified index | ||
| 469 | * in the data array | ||
| 470 | * @see #getElemDouble(int) | ||
| 471 | * @see #getElemDouble(int, int) | ||
| 472 | */ | ||
| 473 | public void setElemDouble(int i, double val) { | ||
| 474 | setElem(i,(int)val); | ||
| 475 | } | ||
| 476 | |||
| 477 | /** | ||
| 478 | * Sets the requested data array element in the specified bank | ||
| 479 | * from the given double. The implementation in this class is to cast | ||
| 480 | * val to an int and call {@link #setElem(int, int)}. Subclasses can | ||
| 481 | * override this method if another implementation is needed. | ||
| 482 | * @param bank the specified bank | ||
| 483 | * @param i the specified index | ||
| 484 | * @param val the value to set the element in the specified bank | ||
| 485 | * at the specified index of the data array | ||
| 486 | * @see #getElemDouble(int) | ||
| 487 | * @see #getElemDouble(int, int) | ||
| 488 | */ | ||
| 489 | public void setElemDouble(int bank, int i, double val) { | ||
| 490 | setElem(bank,i,(int)val); | ||
| 491 | } | ||
| 492 | |||
| 493 | static int[] toIntArray(Object obj) { | ||
| 494 | if (obj instanceof int[]) { | ||
| 495 | return (int[])obj; | ||
| 496 | } else if (obj == null) { | ||
| 497 | return null; | ||
| 498 | } else if (obj instanceof short[]) { | ||
| 499 | short sdata[] = (short[])obj; | ||
| 500 | int idata[] = new int[sdata.length]; | ||
| 501 | for (int i = 0; i < sdata.length; i++) { | ||
| 502 | idata[i] = (int)sdata[i] & 0xffff; | ||
| 503 | } | ||
| 504 | return idata; | ||
| 505 | } else if (obj instanceof byte[]) { | ||
| 506 | byte bdata[] = (byte[])obj; | ||
| 507 | int idata[] = new int[bdata.length]; | ||
| 508 | for (int i = 0; i < bdata.length; i++) { | ||
| 509 | idata[i] = 0xff & (int)bdata[i]; | ||
| 510 | } | ||
| 511 | return idata; | ||
| 512 | } | ||
| 513 | return null; | ||
| 514 | } | ||
| 515 | |||
| 516 | static { | ||
| 517 | SunWritableRaster.setDataStealer(new SunWritableRaster.DataStealer() { | ||
| 518 | public byte[] getData(DataBufferByte dbb, int bank) { | ||
| 519 | return dbb.bankdata[bank]; | ||
| 520 | } | ||
| 521 | |||
| 522 | public short[] getData(DataBufferUShort dbus, int bank) { | ||
| 523 | return dbus.bankdata[bank]; | ||
| 524 | } | ||
| 525 | |||
| 526 | public int[] getData(DataBufferInt dbi, int bank) { | ||
| 527 | return dbi.bankdata[bank]; | ||
| 528 | } | ||
| 529 | |||
| 530 | public StateTrackableDelegate getTrackable(DataBuffer db) { | ||
| 531 | return db.theTrackable; | ||
| 532 | } | ||
| 533 | |||
| 534 | public void setTrackable(DataBuffer db, | ||
| 535 | StateTrackableDelegate trackable) | ||
| 536 | { | ||
| 537 | db.theTrackable = trackable; | ||
| 538 | } | ||
| 539 | }); | ||
| 540 | } | ||
| 541 | } | ||
Binary file not shown.
| @@ -0,0 +1,286 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 | /* **************************************************************** | ||
| 27 | ****************************************************************** | ||
| 28 | ****************************************************************** | ||
| 29 | *** COPYRIGHT (c) Eastman Kodak Company, 1997 | ||
| 30 | *** As an unpublished work pursuant to Title 17 of the United | ||
| 31 | *** States Code. All rights reserved. | ||
| 32 | ****************************************************************** | ||
| 33 | ****************************************************************** | ||
| 34 | ******************************************************************/ | ||
| 35 | |||
| 36 | package java.awt.image; | ||
| 37 | |||
| 38 | import static sun.java2d.StateTrackable.State.*; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * This class extends <CODE>DataBuffer</CODE> and stores data internally as bytes. | ||
| 42 | * Values stored in the byte array(s) of this <CODE>DataBuffer</CODE> are treated as | ||
| 43 | * unsigned values. | ||
| 44 | * <p> | ||
| 45 | * <a name="optimizations"> | ||
| 46 | * Note that some implementations may function more efficiently | ||
| 47 | * if they can maintain control over how the data for an image is | ||
| 48 | * stored. | ||
| 49 | * For example, optimizations such as caching an image in video | ||
| 50 | * memory require that the implementation track all modifications | ||
| 51 | * to that data. | ||
| 52 | * Other implementations may operate better if they can store the | ||
| 53 | * data in locations other than a Java array. | ||
| 54 | * To maintain optimum compatibility with various optimizations | ||
| 55 | * it is best to avoid constructors and methods which expose the | ||
| 56 | * underlying storage as a Java array, as noted below in the | ||
| 57 | * documentation for those methods. | ||
| 58 | * </a> | ||
| 59 | */ | ||
| 60 | public final class DataBufferByte extends DataBuffer | ||
| 61 | { | ||
| 62 | /** The default data bank. */ | ||
| 63 | byte data[]; | ||
| 64 | |||
| 65 | /** All data banks */ | ||
| 66 | byte bankdata[][]; | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Constructs a byte-based <CODE>DataBuffer</CODE> with a single bank and the | ||
| 70 | * specified size. | ||
| 71 | * | ||
| 72 | * @param size The size of the <CODE>DataBuffer</CODE>. | ||
| 73 | */ | ||
| 74 | public DataBufferByte(int size) { | ||
| 75 | super(STABLE, TYPE_BYTE, size); | ||
| 76 | data = new byte[size]; | ||
| 77 | bankdata = new byte[1][]; | ||
| 78 | bankdata[0] = data; | ||
| 79 | } | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Constructs a byte based <CODE>DataBuffer</CODE> with the specified number of | ||
| 83 | * banks all of which are the specified size. | ||
| 84 | * | ||
| 85 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 86 | * @param numBanks The number of banks in the a<CODE>DataBuffer</CODE>. | ||
| 87 | */ | ||
| 88 | public DataBufferByte(int size, int numBanks) { | ||
| 89 | super(STABLE, TYPE_BYTE, size, numBanks); | ||
| 90 | bankdata = new byte[numBanks][]; | ||
| 91 | for (int i= 0; i < numBanks; i++) { | ||
| 92 | bankdata[i] = new byte[size]; | ||
| 93 | } | ||
| 94 | data = bankdata[0]; | ||
| 95 | } | ||
| 96 | |||
| 97 | /** | ||
| 98 | * Constructs a byte-based <CODE>DataBuffer</CODE> with a single bank using the | ||
| 99 | * specified array. | ||
| 100 | * Only the first <CODE>size</CODE> elements should be used by accessors of | ||
| 101 | * this <CODE>DataBuffer</CODE>. <CODE>dataArray</CODE> must be large enough to | ||
| 102 | * hold <CODE>size</CODE> elements. | ||
| 103 | * <p> | ||
| 104 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 105 | * may be incompatible with <a href="#optimizations">performance | ||
| 106 | * optimizations</a> used by some implementations (such as caching | ||
| 107 | * an associated image in video memory). | ||
| 108 | * | ||
| 109 | * @param dataArray The byte array for the <CODE>DataBuffer</CODE>. | ||
| 110 | * @param size The size of the <CODE>DataBuffer</CODE> bank. | ||
| 111 | */ | ||
| 112 | public DataBufferByte(byte dataArray[], int size) { | ||
| 113 | super(UNTRACKABLE, TYPE_BYTE, size); | ||
| 114 | data = dataArray; | ||
| 115 | bankdata = new byte[1][]; | ||
| 116 | bankdata[0] = data; | ||
| 117 | } | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Constructs a byte-based <CODE>DataBuffer</CODE> with a single bank using the | ||
| 121 | * specified array, size, and offset. <CODE>dataArray</CODE> must have at least | ||
| 122 | * <CODE>offset</CODE> + <CODE>size</CODE> elements. Only elements <CODE>offset</CODE> | ||
| 123 | * through <CODE>offset</CODE> + <CODE>size</CODE> - 1 | ||
| 124 | * should be used by accessors of this <CODE>DataBuffer</CODE>. | ||
| 125 | * <p> | ||
| 126 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 127 | * may be incompatible with <a href="#optimizations">performance | ||
| 128 | * optimizations</a> used by some implementations (such as caching | ||
| 129 | * an associated image in video memory). | ||
| 130 | * | ||
| 131 | * @param dataArray The byte array for the <CODE>DataBuffer</CODE>. | ||
| 132 | * @param size The size of the <CODE>DataBuffer</CODE> bank. | ||
| 133 | * @param offset The offset into the <CODE>dataArray</CODE>. <CODE>dataArray</CODE> | ||
| 134 | * must have at least <CODE>offset</CODE> + <CODE>size</CODE> elements. | ||
| 135 | */ | ||
| 136 | public DataBufferByte(byte dataArray[], int size, int offset){ | ||
| 137 | super(UNTRACKABLE, TYPE_BYTE, size, 1, offset); | ||
| 138 | data = dataArray; | ||
| 139 | bankdata = new byte[1][]; | ||
| 140 | bankdata[0] = data; | ||
| 141 | } | ||
| 142 | |||
| 143 | /** | ||
| 144 | * Constructs a byte-based <CODE>DataBuffer</CODE> with the specified arrays. | ||
| 145 | * The number of banks is equal to <CODE>dataArray.length</CODE>. | ||
| 146 | * Only the first <CODE>size</CODE> elements of each array should be used by | ||
| 147 | * accessors of this <CODE>DataBuffer</CODE>. | ||
| 148 | * <p> | ||
| 149 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 150 | * may be incompatible with <a href="#optimizations">performance | ||
| 151 | * optimizations</a> used by some implementations (such as caching | ||
| 152 | * an associated image in video memory). | ||
| 153 | * | ||
| 154 | * @param dataArray The byte arrays for the <CODE>DataBuffer</CODE>. | ||
| 155 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 156 | */ | ||
| 157 | public DataBufferByte(byte dataArray[][], int size) { | ||
| 158 | super(UNTRACKABLE, TYPE_BYTE, size, dataArray.length); | ||
| 159 | bankdata = (byte[][]) dataArray.clone(); | ||
| 160 | data = bankdata[0]; | ||
| 161 | } | ||
| 162 | |||
| 163 | /** | ||
| 164 | * Constructs a byte-based <CODE>DataBuffer</CODE> with the specified arrays, size, | ||
| 165 | * and offsets. | ||
| 166 | * The number of banks is equal to <CODE>dataArray.length</CODE>. Each array must | ||
| 167 | * be at least as large as <CODE>size</CODE> + the corresponding <CODE>offset</CODE>. | ||
| 168 | * There must be an entry in the <CODE>offset</CODE> array for each <CODE>dataArray</CODE> | ||
| 169 | * entry. For each bank, only elements <CODE>offset</CODE> through | ||
| 170 | * <CODE>offset</CODE> + <CODE>size</CODE> - 1 should be used by accessors of this | ||
| 171 | * <CODE>DataBuffer</CODE>. | ||
| 172 | * <p> | ||
| 173 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 174 | * may be incompatible with <a href="#optimizations">performance | ||
| 175 | * optimizations</a> used by some implementations (such as caching | ||
| 176 | * an associated image in video memory). | ||
| 177 | * | ||
| 178 | * @param dataArray The byte arrays for the <CODE>DataBuffer</CODE>. | ||
| 179 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 180 | * @param offsets The offsets into each array. | ||
| 181 | */ | ||
| 182 | public DataBufferByte(byte dataArray[][], int size, int offsets[]) { | ||
| 183 | super(UNTRACKABLE, TYPE_BYTE, size, dataArray.length, offsets); | ||
| 184 | bankdata = (byte[][]) dataArray.clone(); | ||
| 185 | data = bankdata[0]; | ||
| 186 | } | ||
| 187 | |||
| 188 | /** | ||
| 189 | * Returns the default (first) byte data array. | ||
| 190 | * <p> | ||
| 191 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 192 | * object to be incompatible with <a href="#optimizations">performance | ||
| 193 | * optimizations</a> used by some implementations (such as caching | ||
| 194 | * an associated image in video memory). | ||
| 195 | * | ||
| 196 | * @return The first byte data array. | ||
| 197 | */ | ||
| 198 | public byte[] getData() { | ||
| 199 | theTrackable.setUntrackable(); | ||
| 200 | return data; | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * Returns the data array for the specified bank. | ||
| 205 | * <p> | ||
| 206 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 207 | * object to be incompatible with <a href="#optimizations">performance | ||
| 208 | * optimizations</a> used by some implementations (such as caching | ||
| 209 | * an associated image in video memory). | ||
| 210 | * | ||
| 211 | * @param bank The bank whose data array you want to get. | ||
| 212 | * @return The data array for the specified bank. | ||
| 213 | */ | ||
| 214 | public byte[] getData(int bank) { | ||
| 215 | theTrackable.setUntrackable(); | ||
| 216 | return bankdata[bank]; | ||
| 217 | } | ||
| 218 | |||
| 219 | /** | ||
| 220 | * Returns the data arrays for all banks. | ||
| 221 | * <p> | ||
| 222 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 223 | * object to be incompatible with <a href="#optimizations">performance | ||
| 224 | * optimizations</a> used by some implementations (such as caching | ||
| 225 | * an associated image in video memory). | ||
| 226 | * | ||
| 227 | * @return All of the data arrays. | ||
| 228 | */ | ||
| 229 | public byte[][] getBankData() { | ||
| 230 | theTrackable.setUntrackable(); | ||
| 231 | return (byte[][]) bankdata.clone(); | ||
| 232 | } | ||
| 233 | |||
| 234 | /** | ||
| 235 | * Returns the requested data array element from the first (default) bank. | ||
| 236 | * | ||
| 237 | * @param i The data array element you want to get. | ||
| 238 | * @return The requested data array element as an integer. | ||
| 239 | * @see #setElem(int, int) | ||
| 240 | * @see #setElem(int, int, int) | ||
| 241 | */ | ||
| 242 | public int getElem(int i) { | ||
| 243 | return (int)(data[i+offset]) & 0xff; | ||
| 244 | } | ||
| 245 | |||
| 246 | /** | ||
| 247 | * Returns the requested data array element from the specified bank. | ||
| 248 | * | ||
| 249 | * @param bank The bank from which you want to get a data array element. | ||
| 250 | * @param i The data array element you want to get. | ||
| 251 | * @return The requested data array element as an integer. | ||
| 252 | * @see #setElem(int, int) | ||
| 253 | * @see #setElem(int, int, int) | ||
| 254 | */ | ||
| 255 | public int getElem(int bank, int i) { | ||
| 256 | return (int)(bankdata[bank][i+offsets[bank]]) & 0xff; | ||
| 257 | } | ||
| 258 | |||
| 259 | /** | ||
| 260 | * Sets the requested data array element in the first (default) bank | ||
| 261 | * to the specified value. | ||
| 262 | * | ||
| 263 | * @param i The data array element you want to set. | ||
| 264 | * @param val The integer value to which you want to set the data array element. | ||
| 265 | * @see #getElem(int) | ||
| 266 | * @see #getElem(int, int) | ||
| 267 | */ | ||
| 268 | public void setElem(int i, int val) { | ||
| 269 | data[i+offset] = (byte)val; | ||
| 270 | theTrackable.markDirty(); | ||
| 271 | } | ||
| 272 | |||
| 273 | /** | ||
| 274 | * Sets the requested data array element in the specified bank | ||
| 275 | * from the given integer. | ||
| 276 | * @param bank The bank in which you want to set the data array element. | ||
| 277 | * @param i The data array element you want to set. | ||
| 278 | * @param val The integer value to which you want to set the specified data array element. | ||
| 279 | * @see #getElem(int) | ||
| 280 | * @see #getElem(int, int) | ||
| 281 | */ | ||
| 282 | public void setElem(int bank, int i, int val) { | ||
| 283 | bankdata[bank][i+offsets[bank]] = (byte)val; | ||
| 284 | theTrackable.markDirty(); | ||
| 285 | } | ||
| 286 | } | ||
Binary file not shown.
| @@ -0,0 +1,403 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import static sun.java2d.StateTrackable.State.*; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * This class extends <code>DataBuffer</code> and stores data internally | ||
| 32 | * in <code>double</code> form. | ||
| 33 | * <p> | ||
| 34 | * <a name="optimizations"> | ||
| 35 | * Note that some implementations may function more efficiently | ||
| 36 | * if they can maintain control over how the data for an image is | ||
| 37 | * stored. | ||
| 38 | * For example, optimizations such as caching an image in video | ||
| 39 | * memory require that the implementation track all modifications | ||
| 40 | * to that data. | ||
| 41 | * Other implementations may operate better if they can store the | ||
| 42 | * data in locations other than a Java array. | ||
| 43 | * To maintain optimum compatibility with various optimizations | ||
| 44 | * it is best to avoid constructors and methods which expose the | ||
| 45 | * underlying storage as a Java array as noted below in the | ||
| 46 | * documentation for those methods. | ||
| 47 | * </a> | ||
| 48 | * | ||
| 49 | * @since 1.4 | ||
| 50 | */ | ||
| 51 | |||
| 52 | public final class DataBufferDouble extends DataBuffer { | ||
| 53 | |||
| 54 | /** The array of data banks. */ | ||
| 55 | double bankdata[][]; | ||
| 56 | |||
| 57 | /** A reference to the default data bank. */ | ||
| 58 | double data[]; | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Constructs a <code>double</code>-based <code>DataBuffer</code> | ||
| 62 | * with a specified size. | ||
| 63 | * | ||
| 64 | * @param size The number of elements in the <code>DataBuffer</code>. | ||
| 65 | */ | ||
| 66 | public DataBufferDouble(int size) { | ||
| 67 | super(STABLE, TYPE_DOUBLE, size); | ||
| 68 | data = new double[size]; | ||
| 69 | bankdata = new double[1][]; | ||
| 70 | bankdata[0] = data; | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Constructs a <code>double</code>-based <code>DataBuffer</code> | ||
| 75 | * with a specified number of banks, all of which are of a | ||
| 76 | * specified size. | ||
| 77 | * | ||
| 78 | * @param size The number of elements in each bank of the | ||
| 79 | * <code>DataBuffer</code>. | ||
| 80 | * @param numBanks The number of banks in the <code>DataBuffer</code>. | ||
| 81 | */ | ||
| 82 | public DataBufferDouble(int size, int numBanks) { | ||
| 83 | super(STABLE, TYPE_DOUBLE, size, numBanks); | ||
| 84 | bankdata = new double[numBanks][]; | ||
| 85 | for (int i= 0; i < numBanks; i++) { | ||
| 86 | bankdata[i] = new double[size]; | ||
| 87 | } | ||
| 88 | data = bankdata[0]; | ||
| 89 | } | ||
| 90 | |||
| 91 | /** | ||
| 92 | * Constructs a <code>double</code>-based <code>DataBuffer</code> | ||
| 93 | * with the specified data array. Only the first | ||
| 94 | * <code>size</code> elements are available for use by this | ||
| 95 | * <code>DataBuffer</code>. The array must be large enough to | ||
| 96 | * hold <code>size</code> elements. | ||
| 97 | * <p> | ||
| 98 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 99 | * may be incompatible with <a href="#optimizations">performance | ||
| 100 | * optimizations</a> used by some implementations (such as caching | ||
| 101 | * an associated image in video memory). | ||
| 102 | * | ||
| 103 | * @param dataArray An array of <code>double</code>s to be used as the | ||
| 104 | * first and only bank of this <code>DataBuffer</code>. | ||
| 105 | * @param size The number of elements of the array to be used. | ||
| 106 | */ | ||
| 107 | public DataBufferDouble(double dataArray[], int size) { | ||
| 108 | super(UNTRACKABLE, TYPE_DOUBLE, size); | ||
| 109 | data = dataArray; | ||
| 110 | bankdata = new double[1][]; | ||
| 111 | bankdata[0] = data; | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * Constructs a <code>double</code>-based <code>DataBuffer</code> | ||
| 116 | * with the specified data array. Only the elements between | ||
| 117 | * <code>offset</code> and <code>offset + size - 1</code> are | ||
| 118 | * available for use by this <code>DataBuffer</code>. The array | ||
| 119 | * must be large enough to hold <code>offset + size</code> elements. | ||
| 120 | * <p> | ||
| 121 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 122 | * may be incompatible with <a href="#optimizations">performance | ||
| 123 | * optimizations</a> used by some implementations (such as caching | ||
| 124 | * an associated image in video memory). | ||
| 125 | * | ||
| 126 | * @param dataArray An array of <code>double</code>s to be used as the | ||
| 127 | * first and only bank of this <code>DataBuffer</code>. | ||
| 128 | * @param size The number of elements of the array to be used. | ||
| 129 | * @param offset The offset of the first element of the array | ||
| 130 | * that will be used. | ||
| 131 | */ | ||
| 132 | public DataBufferDouble(double dataArray[], int size, int offset) { | ||
| 133 | super(UNTRACKABLE, TYPE_DOUBLE, size, 1, offset); | ||
| 134 | data = dataArray; | ||
| 135 | bankdata = new double[1][]; | ||
| 136 | bankdata[0] = data; | ||
| 137 | } | ||
| 138 | |||
| 139 | /** | ||
| 140 | * Constructs a <code>double</code>-based <code>DataBuffer</code> | ||
| 141 | * with the specified data arrays. Only the first | ||
| 142 | * <code>size</code> elements of each array are available for use | ||
| 143 | * by this <code>DataBuffer</code>. The number of banks will be | ||
| 144 | * equal <code>to dataArray.length</code>. | ||
| 145 | * <p> | ||
| 146 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 147 | * may be incompatible with <a href="#optimizations">performance | ||
| 148 | * optimizations</a> used by some implementations (such as caching | ||
| 149 | * an associated image in video memory). | ||
| 150 | * | ||
| 151 | * @param dataArray An array of arrays of <code>double</code>s to be | ||
| 152 | * used as the banks of this <code>DataBuffer</code>. | ||
| 153 | * @param size The number of elements of each array to be used. | ||
| 154 | */ | ||
| 155 | public DataBufferDouble(double dataArray[][], int size) { | ||
| 156 | super(UNTRACKABLE, TYPE_DOUBLE, size, dataArray.length); | ||
| 157 | bankdata = (double[][]) dataArray.clone(); | ||
| 158 | data = bankdata[0]; | ||
| 159 | } | ||
| 160 | |||
| 161 | /** | ||
| 162 | * Constructs a <code>double</code>-based <code>DataBuffer</code> | ||
| 163 | * with the specified data arrays, size, and per-bank offsets. | ||
| 164 | * The number of banks is equal to dataArray.length. Each array | ||
| 165 | * must be at least as large as <code>size</code> plus the | ||
| 166 | * corresponding offset. There must be an entry in the | ||
| 167 | * <code>offsets</code> array for each data array. | ||
| 168 | * <p> | ||
| 169 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 170 | * may be incompatible with <a href="#optimizations">performance | ||
| 171 | * optimizations</a> used by some implementations (such as caching | ||
| 172 | * an associated image in video memory). | ||
| 173 | * | ||
| 174 | * @param dataArray An array of arrays of <code>double</code>s to be | ||
| 175 | * used as the banks of this <code>DataBuffer</code>. | ||
| 176 | * @param size The number of elements of each array to be used. | ||
| 177 | * @param offsets An array of integer offsets, one for each bank. | ||
| 178 | */ | ||
| 179 | public DataBufferDouble(double dataArray[][], int size, int offsets[]) { | ||
| 180 | super(UNTRACKABLE, TYPE_DOUBLE, size, dataArray.length, offsets); | ||
| 181 | bankdata = (double[][]) dataArray.clone(); | ||
| 182 | data = bankdata[0]; | ||
| 183 | } | ||
| 184 | |||
| 185 | /** | ||
| 186 | * Returns the default (first) <code>double</code> data array. | ||
| 187 | * <p> | ||
| 188 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 189 | * object to be incompatible with <a href="#optimizations">performance | ||
| 190 | * optimizations</a> used by some implementations (such as caching | ||
| 191 | * an associated image in video memory). | ||
| 192 | * | ||
| 193 | * @return the first double data array. | ||
| 194 | */ | ||
| 195 | public double[] getData() { | ||
| 196 | theTrackable.setUntrackable(); | ||
| 197 | return data; | ||
| 198 | } | ||
| 199 | |||
| 200 | /** | ||
| 201 | * Returns the data array for the specified bank. | ||
| 202 | * <p> | ||
| 203 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 204 | * object to be incompatible with <a href="#optimizations">performance | ||
| 205 | * optimizations</a> used by some implementations (such as caching | ||
| 206 | * an associated image in video memory). | ||
| 207 | * | ||
| 208 | * @param bank the data array | ||
| 209 | * @return the data array specified by <code>bank</code>. | ||
| 210 | */ | ||
| 211 | public double[] getData(int bank) { | ||
| 212 | theTrackable.setUntrackable(); | ||
| 213 | return bankdata[bank]; | ||
| 214 | } | ||
| 215 | |||
| 216 | /** | ||
| 217 | * Returns the data array for all banks. | ||
| 218 | * <p> | ||
| 219 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 220 | * object to be incompatible with <a href="#optimizations">performance | ||
| 221 | * optimizations</a> used by some implementations (such as caching | ||
| 222 | * an associated image in video memory). | ||
| 223 | * | ||
| 224 | * @return all data arrays from this data buffer. | ||
| 225 | */ | ||
| 226 | public double[][] getBankData() { | ||
| 227 | theTrackable.setUntrackable(); | ||
| 228 | return (double[][]) bankdata.clone(); | ||
| 229 | } | ||
| 230 | |||
| 231 | /** | ||
| 232 | * Returns the requested data array element from the first | ||
| 233 | * (default) bank as an <code>int</code>. | ||
| 234 | * | ||
| 235 | * @param i The desired data array element. | ||
| 236 | * @return The data entry as an <code>int</code>. | ||
| 237 | * @see #setElem(int, int) | ||
| 238 | * @see #setElem(int, int, int) | ||
| 239 | */ | ||
| 240 | public int getElem(int i) { | ||
| 241 | return (int)(data[i+offset]); | ||
| 242 | } | ||
| 243 | |||
| 244 | /** | ||
| 245 | * Returns the requested data array element from the specified | ||
| 246 | * bank as an <code>int</code>. | ||
| 247 | * | ||
| 248 | * @param bank The bank number. | ||
| 249 | * @param i The desired data array element. | ||
| 250 | * | ||
| 251 | * @return The data entry as an <code>int</code>. | ||
| 252 | * @see #setElem(int, int) | ||
| 253 | * @see #setElem(int, int, int) | ||
| 254 | */ | ||
| 255 | public int getElem(int bank, int i) { | ||
| 256 | return (int)(bankdata[bank][i+offsets[bank]]); | ||
| 257 | } | ||
| 258 | |||
| 259 | /** | ||
| 260 | * Sets the requested data array element in the first (default) | ||
| 261 | * bank to the given <code>int</code>. | ||
| 262 | * | ||
| 263 | * @param i The desired data array element. | ||
| 264 | * @param val The value to be set. | ||
| 265 | * @see #getElem(int) | ||
| 266 | * @see #getElem(int, int) | ||
| 267 | */ | ||
| 268 | public void setElem(int i, int val) { | ||
| 269 | data[i+offset] = (double)val; | ||
| 270 | theTrackable.markDirty(); | ||
| 271 | } | ||
| 272 | |||
| 273 | /** | ||
| 274 | * Sets the requested data array element in the specified bank | ||
| 275 | * to the given <code>int</code>. | ||
| 276 | * | ||
| 277 | * @param bank The bank number. | ||
| 278 | * @param i The desired data array element. | ||
| 279 | * @param val The value to be set. | ||
| 280 | * @see #getElem(int) | ||
| 281 | * @see #getElem(int, int) | ||
| 282 | */ | ||
| 283 | public void setElem(int bank, int i, int val) { | ||
| 284 | bankdata[bank][i+offsets[bank]] = (double)val; | ||
| 285 | theTrackable.markDirty(); | ||
| 286 | } | ||
| 287 | |||
| 288 | /** | ||
| 289 | * Returns the requested data array element from the first | ||
| 290 | * (default) bank as a <code>float</code>. | ||
| 291 | * | ||
| 292 | * @param i The desired data array element. | ||
| 293 | * | ||
| 294 | * @return The data entry as a <code>float</code>. | ||
| 295 | * @see #setElemFloat(int, float) | ||
| 296 | * @see #setElemFloat(int, int, float) | ||
| 297 | */ | ||
| 298 | public float getElemFloat(int i) { | ||
| 299 | return (float)data[i+offset]; | ||
| 300 | } | ||
| 301 | |||
| 302 | /** | ||
| 303 | * Returns the requested data array element from the specified | ||
| 304 | * bank as a <code>float</code>. | ||
| 305 | * | ||
| 306 | * @param bank The bank number. | ||
| 307 | * @param i The desired data array element. | ||
| 308 | * | ||
| 309 | * @return The data entry as a <code>float</code>. | ||
| 310 | * @see #setElemFloat(int, float) | ||
| 311 | * @see #setElemFloat(int, int, float) | ||
| 312 | */ | ||
| 313 | public float getElemFloat(int bank, int i) { | ||
| 314 | return (float)bankdata[bank][i+offsets[bank]]; | ||
| 315 | } | ||
| 316 | |||
| 317 | /** | ||
| 318 | * Sets the requested data array element in the first (default) | ||
| 319 | * bank to the given <code>float</code>. | ||
| 320 | * | ||
| 321 | * @param i The desired data array element. | ||
| 322 | * @param val The value to be set. | ||
| 323 | * @see #getElemFloat(int) | ||
| 324 | * @see #getElemFloat(int, int) | ||
| 325 | */ | ||
| 326 | public void setElemFloat(int i, float val) { | ||
| 327 | data[i+offset] = (double)val; | ||
| 328 | theTrackable.markDirty(); | ||
| 329 | } | ||
| 330 | |||
| 331 | /** | ||
| 332 | * Sets the requested data array element in the specified bank to | ||
| 333 | * the given <code>float</code>. | ||
| 334 | * | ||
| 335 | * @param bank The bank number. | ||
| 336 | * @param i The desired data array element. | ||
| 337 | * @param val The value to be set. | ||
| 338 | * @see #getElemFloat(int) | ||
| 339 | * @see #getElemFloat(int, int) | ||
| 340 | */ | ||
| 341 | public void setElemFloat(int bank, int i, float val) { | ||
| 342 | bankdata[bank][i+offsets[bank]] = (double)val; | ||
| 343 | theTrackable.markDirty(); | ||
| 344 | } | ||
| 345 | |||
| 346 | /** | ||
| 347 | * Returns the requested data array element from the first | ||
| 348 | * (default) bank as a <code>double</code>. | ||
| 349 | * | ||
| 350 | * @param i The desired data array element. | ||
| 351 | * | ||
| 352 | * @return The data entry as a <code>double</code>. | ||
| 353 | * @see #setElemDouble(int, double) | ||
| 354 | * @see #setElemDouble(int, int, double) | ||
| 355 | */ | ||
| 356 | public double getElemDouble(int i) { | ||
| 357 | return data[i+offset]; | ||
| 358 | } | ||
| 359 | |||
| 360 | /** | ||
| 361 | * Returns the requested data array element from the specified | ||
| 362 | * bank as a <code>double</code>. | ||
| 363 | * | ||
| 364 | * @param bank The bank number. | ||
| 365 | * @param i The desired data array element. | ||
| 366 | * | ||
| 367 | * @return The data entry as a <code>double</code>. | ||
| 368 | * @see #setElemDouble(int, double) | ||
| 369 | * @see #setElemDouble(int, int, double) | ||
| 370 | */ | ||
| 371 | public double getElemDouble(int bank, int i) { | ||
| 372 | return bankdata[bank][i+offsets[bank]]; | ||
| 373 | } | ||
| 374 | |||
| 375 | /** | ||
| 376 | * Sets the requested data array element in the first (default) | ||
| 377 | * bank to the given <code>double</code>. | ||
| 378 | * | ||
| 379 | * @param i The desired data array element. | ||
| 380 | * @param val The value to be set. | ||
| 381 | * @see #getElemDouble(int) | ||
| 382 | * @see #getElemDouble(int, int) | ||
| 383 | */ | ||
| 384 | public void setElemDouble(int i, double val) { | ||
| 385 | data[i+offset] = val; | ||
| 386 | theTrackable.markDirty(); | ||
| 387 | } | ||
| 388 | |||
| 389 | /** | ||
| 390 | * Sets the requested data array element in the specified bank to | ||
| 391 | * the given <code>double</code>. | ||
| 392 | * | ||
| 393 | * @param bank The bank number. | ||
| 394 | * @param i The desired data array element. | ||
| 395 | * @param val The value to be set. | ||
| 396 | * @see #getElemDouble(int) | ||
| 397 | * @see #getElemDouble(int, int) | ||
| 398 | */ | ||
| 399 | public void setElemDouble(int bank, int i, double val) { | ||
| 400 | bankdata[bank][i+offsets[bank]] = val; | ||
| 401 | theTrackable.markDirty(); | ||
| 402 | } | ||
| 403 | } | ||
Binary file not shown.
| @@ -0,0 +1,406 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import static sun.java2d.StateTrackable.State.*; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * This class extends <code>DataBuffer</code> and stores data internally | ||
| 32 | * in <code>float</code> form. | ||
| 33 | * <p> | ||
| 34 | * <a name="optimizations"> | ||
| 35 | * Note that some implementations may function more efficiently | ||
| 36 | * if they can maintain control over how the data for an image is | ||
| 37 | * stored. | ||
| 38 | * For example, optimizations such as caching an image in video | ||
| 39 | * memory require that the implementation track all modifications | ||
| 40 | * to that data. | ||
| 41 | * Other implementations may operate better if they can store the | ||
| 42 | * data in locations other than a Java array. | ||
| 43 | * To maintain optimum compatibility with various optimizations | ||
| 44 | * it is best to avoid constructors and methods which expose the | ||
| 45 | * underlying storage as a Java array as noted below in the | ||
| 46 | * documentation for those methods. | ||
| 47 | * </a> | ||
| 48 | * | ||
| 49 | * @since 1.4 | ||
| 50 | */ | ||
| 51 | |||
| 52 | public final class DataBufferFloat extends DataBuffer { | ||
| 53 | |||
| 54 | /** The array of data banks. */ | ||
| 55 | float bankdata[][]; | ||
| 56 | |||
| 57 | /** A reference to the default data bank. */ | ||
| 58 | float data[]; | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Constructs a <code>float</code>-based <code>DataBuffer</code> | ||
| 62 | * with a specified size. | ||
| 63 | * | ||
| 64 | * @param size The number of elements in the DataBuffer. | ||
| 65 | */ | ||
| 66 | public DataBufferFloat(int size) { | ||
| 67 | super(STABLE, TYPE_FLOAT, size); | ||
| 68 | data = new float[size]; | ||
| 69 | bankdata = new float[1][]; | ||
| 70 | bankdata[0] = data; | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Constructs a <code>float</code>-based <code>DataBuffer</code> | ||
| 75 | * with a specified number of banks, all of which are of a | ||
| 76 | * specified size. | ||
| 77 | * | ||
| 78 | * @param size The number of elements in each bank of the | ||
| 79 | * <code>DataBuffer</code>. | ||
| 80 | * @param numBanks The number of banks in the | ||
| 81 | * <code>DataBuffer</code>. | ||
| 82 | */ | ||
| 83 | public DataBufferFloat(int size, int numBanks) { | ||
| 84 | super(STABLE, TYPE_FLOAT, size, numBanks); | ||
| 85 | bankdata = new float[numBanks][]; | ||
| 86 | for (int i= 0; i < numBanks; i++) { | ||
| 87 | bankdata[i] = new float[size]; | ||
| 88 | } | ||
| 89 | data = bankdata[0]; | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * Constructs a <code>float</code>-based <code>DataBuffer</code> | ||
| 94 | * with the specified data array. Only the first | ||
| 95 | * <code>size</code> elements are available for use by this | ||
| 96 | * <code>DataBuffer</code>. The array must be large enough to | ||
| 97 | * hold <code>size</code> elements. | ||
| 98 | * <p> | ||
| 99 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 100 | * may be incompatible with <a href="#optimizations">performance | ||
| 101 | * optimizations</a> used by some implementations (such as caching | ||
| 102 | * an associated image in video memory). | ||
| 103 | * | ||
| 104 | * @param dataArray An array of <code>float</code>s to be used as the | ||
| 105 | * first and only bank of this <code>DataBuffer</code>. | ||
| 106 | * @param size The number of elements of the array to be used. | ||
| 107 | */ | ||
| 108 | public DataBufferFloat(float dataArray[], int size) { | ||
| 109 | super(UNTRACKABLE, TYPE_FLOAT, size); | ||
| 110 | data = dataArray; | ||
| 111 | bankdata = new float[1][]; | ||
| 112 | bankdata[0] = data; | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Constructs a <code>float</code>-based <code>DataBuffer</code> | ||
| 117 | * with the specified data array. Only the elements between | ||
| 118 | * <code>offset</code> and <code>offset + size - 1</code> are | ||
| 119 | * available for use by this <code>DataBuffer</code>. The array | ||
| 120 | * must be large enough to hold <code>offset + size</code> | ||
| 121 | * elements. | ||
| 122 | * <p> | ||
| 123 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 124 | * may be incompatible with <a href="#optimizations">performance | ||
| 125 | * optimizations</a> used by some implementations (such as caching | ||
| 126 | * an associated image in video memory). | ||
| 127 | * | ||
| 128 | * @param dataArray An array of <code>float</code>s to be used as the | ||
| 129 | * first and only bank of this <code>DataBuffer</code>. | ||
| 130 | * @param size The number of elements of the array to be used. | ||
| 131 | * @param offset The offset of the first element of the array | ||
| 132 | * that will be used. | ||
| 133 | */ | ||
| 134 | public DataBufferFloat(float dataArray[], int size, int offset) { | ||
| 135 | super(UNTRACKABLE, TYPE_FLOAT, size, 1, offset); | ||
| 136 | data = dataArray; | ||
| 137 | bankdata = new float[1][]; | ||
| 138 | bankdata[0] = data; | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * Constructs a <code>float</code>-based <code>DataBuffer</code> | ||
| 143 | * with the specified data arrays. Only the first | ||
| 144 | * <code>size</code> elements of each array are available for use | ||
| 145 | * by this <code>DataBuffer</code>. The number of banks will be | ||
| 146 | * equal to <code>dataArray.length</code>. | ||
| 147 | * <p> | ||
| 148 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 149 | * may be incompatible with <a href="#optimizations">performance | ||
| 150 | * optimizations</a> used by some implementations (such as caching | ||
| 151 | * an associated image in video memory). | ||
| 152 | * | ||
| 153 | * @param dataArray An array of arrays of <code>float</code>s to be | ||
| 154 | * used as the banks of this <code>DataBuffer</code>. | ||
| 155 | * @param size The number of elements of each array to be used. | ||
| 156 | */ | ||
| 157 | public DataBufferFloat(float dataArray[][], int size) { | ||
| 158 | super(UNTRACKABLE, TYPE_FLOAT, size, dataArray.length); | ||
| 159 | bankdata = (float[][]) dataArray.clone(); | ||
| 160 | data = bankdata[0]; | ||
| 161 | } | ||
| 162 | |||
| 163 | /** | ||
| 164 | * Constructs a <code>float</code>-based <code>DataBuffer</code> | ||
| 165 | * with the specified data arrays, size, and per-bank offsets. | ||
| 166 | * The number of banks is equal to <code>dataArray.length</code>. | ||
| 167 | * Each array must be at least as large as <code>size</code> plus the | ||
| 168 | * corresponding offset. There must be an entry in the offsets | ||
| 169 | * array for each data array. | ||
| 170 | * <p> | ||
| 171 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 172 | * may be incompatible with <a href="#optimizations">performance | ||
| 173 | * optimizations</a> used by some implementations (such as caching | ||
| 174 | * an associated image in video memory). | ||
| 175 | * | ||
| 176 | * @param dataArray An array of arrays of <code>float</code>s to be | ||
| 177 | * used as the banks of this <code>DataBuffer</code>. | ||
| 178 | * @param size The number of elements of each array to be used. | ||
| 179 | * @param offsets An array of integer offsets, one for each bank. | ||
| 180 | */ | ||
| 181 | public DataBufferFloat(float dataArray[][], int size, int offsets[]) { | ||
| 182 | super(UNTRACKABLE, TYPE_FLOAT, size,dataArray.length, offsets); | ||
| 183 | bankdata = (float[][]) dataArray.clone(); | ||
| 184 | data = bankdata[0]; | ||
| 185 | } | ||
| 186 | |||
| 187 | /** | ||
| 188 | * Returns the default (first) <code>float</code> data array. | ||
| 189 | * <p> | ||
| 190 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 191 | * object to be incompatible with <a href="#optimizations">performance | ||
| 192 | * optimizations</a> used by some implementations (such as caching | ||
| 193 | * an associated image in video memory). | ||
| 194 | * | ||
| 195 | * @return the first float data array. | ||
| 196 | */ | ||
| 197 | public float[] getData() { | ||
| 198 | theTrackable.setUntrackable(); | ||
| 199 | return data; | ||
| 200 | } | ||
| 201 | |||
| 202 | /** | ||
| 203 | * Returns the data array for the specified bank. | ||
| 204 | * <p> | ||
| 205 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 206 | * object to be incompatible with <a href="#optimizations">performance | ||
| 207 | * optimizations</a> used by some implementations (such as caching | ||
| 208 | * an associated image in video memory). | ||
| 209 | * | ||
| 210 | * @param bank the data array | ||
| 211 | * @return the data array specified by <code>bank</code>. | ||
| 212 | */ | ||
| 213 | public float[] getData(int bank) { | ||
| 214 | theTrackable.setUntrackable(); | ||
| 215 | return bankdata[bank]; | ||
| 216 | } | ||
| 217 | |||
| 218 | /** | ||
| 219 | * Returns the data array for all banks. | ||
| 220 | * <p> | ||
| 221 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 222 | * object to be incompatible with <a href="#optimizations">performance | ||
| 223 | * optimizations</a> used by some implementations (such as caching | ||
| 224 | * an associated image in video memory). | ||
| 225 | * | ||
| 226 | * @return all data arrays for this data buffer. | ||
| 227 | */ | ||
| 228 | public float[][] getBankData() { | ||
| 229 | theTrackable.setUntrackable(); | ||
| 230 | return (float[][]) bankdata.clone(); | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * Returns the requested data array element from the first | ||
| 235 | * (default) bank as an <code>int</code>. | ||
| 236 | * | ||
| 237 | * @param i The desired data array element. | ||
| 238 | * | ||
| 239 | * @return The data entry as an <code>int</code>. | ||
| 240 | * @see #setElem(int, int) | ||
| 241 | * @see #setElem(int, int, int) | ||
| 242 | */ | ||
| 243 | public int getElem(int i) { | ||
| 244 | return (int)(data[i+offset]); | ||
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | * Returns the requested data array element from the specified | ||
| 249 | * bank as an <code>int</code>. | ||
| 250 | * | ||
| 251 | * @param bank The bank number. | ||
| 252 | * @param i The desired data array element. | ||
| 253 | * | ||
| 254 | * @return The data entry as an <code>int</code>. | ||
| 255 | * @see #setElem(int, int) | ||
| 256 | * @see #setElem(int, int, int) | ||
| 257 | */ | ||
| 258 | public int getElem(int bank, int i) { | ||
| 259 | return (int)(bankdata[bank][i+offsets[bank]]); | ||
| 260 | } | ||
| 261 | |||
| 262 | /** | ||
| 263 | * Sets the requested data array element in the first (default) | ||
| 264 | * bank to the given <code>int</code>. | ||
| 265 | * | ||
| 266 | * @param i The desired data array element. | ||
| 267 | * @param val The value to be set. | ||
| 268 | * @see #getElem(int) | ||
| 269 | * @see #getElem(int, int) | ||
| 270 | */ | ||
| 271 | public void setElem(int i, int val) { | ||
| 272 | data[i+offset] = (float)val; | ||
| 273 | theTrackable.markDirty(); | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * Sets the requested data array element in the specified bank to | ||
| 278 | * the given <code>int</code>. | ||
| 279 | * | ||
| 280 | * @param bank The bank number. | ||
| 281 | * @param i The desired data array element. | ||
| 282 | * @param val The value to be set. | ||
| 283 | * @see #getElem(int) | ||
| 284 | * @see #getElem(int, int) | ||
| 285 | */ | ||
| 286 | public void setElem(int bank, int i, int val) { | ||
| 287 | bankdata[bank][i+offsets[bank]] = (float)val; | ||
| 288 | theTrackable.markDirty(); | ||
| 289 | } | ||
| 290 | |||
| 291 | /** | ||
| 292 | * Returns the requested data array element from the first | ||
| 293 | * (default) bank as a <code>float</code>. | ||
| 294 | * | ||
| 295 | * @param i The desired data array element. | ||
| 296 | * | ||
| 297 | * @return The data entry as a <code>float</code>. | ||
| 298 | * @see #setElemFloat(int, float) | ||
| 299 | * @see #setElemFloat(int, int, float) | ||
| 300 | */ | ||
| 301 | public float getElemFloat(int i) { | ||
| 302 | return data[i+offset]; | ||
| 303 | } | ||
| 304 | |||
| 305 | /** | ||
| 306 | * Returns the requested data array element from the specified | ||
| 307 | * bank as a <code>float</code>. | ||
| 308 | * | ||
| 309 | * @param bank The bank number. | ||
| 310 | * @param i The desired data array element. | ||
| 311 | * | ||
| 312 | * @return The data entry as a <code>float</code>. | ||
| 313 | * @see #setElemFloat(int, float) | ||
| 314 | * @see #setElemFloat(int, int, float) | ||
| 315 | */ | ||
| 316 | public float getElemFloat(int bank, int i) { | ||
| 317 | return bankdata[bank][i+offsets[bank]]; | ||
| 318 | } | ||
| 319 | |||
| 320 | /** | ||
| 321 | * Sets the requested data array element in the first (default) | ||
| 322 | * bank to the given <code>float</code>. | ||
| 323 | * | ||
| 324 | * @param i The desired data array element. | ||
| 325 | * @param val The value to be set. | ||
| 326 | * @see #getElemFloat(int) | ||
| 327 | * @see #getElemFloat(int, int) | ||
| 328 | */ | ||
| 329 | public void setElemFloat(int i, float val) { | ||
| 330 | data[i+offset] = val; | ||
| 331 | theTrackable.markDirty(); | ||
| 332 | } | ||
| 333 | |||
| 334 | /** | ||
| 335 | * Sets the requested data array element in the specified bank to | ||
| 336 | * the given <code>float</code>. | ||
| 337 | * | ||
| 338 | * @param bank The bank number. | ||
| 339 | * @param i The desired data array element. | ||
| 340 | * @param val The value to be set. | ||
| 341 | * @see #getElemFloat(int) | ||
| 342 | * @see #getElemFloat(int, int) | ||
| 343 | */ | ||
| 344 | public void setElemFloat(int bank, int i, float val) { | ||
| 345 | bankdata[bank][i+offsets[bank]] = val; | ||
| 346 | theTrackable.markDirty(); | ||
| 347 | } | ||
| 348 | |||
| 349 | /** | ||
| 350 | * Returns the requested data array element from the first | ||
| 351 | * (default) bank as a <code>double</code>. | ||
| 352 | * | ||
| 353 | * @param i The desired data array element. | ||
| 354 | * | ||
| 355 | * @return The data entry as a <code>double</code>. | ||
| 356 | * @see #setElemDouble(int, double) | ||
| 357 | * @see #setElemDouble(int, int, double) | ||
| 358 | */ | ||
| 359 | public double getElemDouble(int i) { | ||
| 360 | return (double)data[i+offset]; | ||
| 361 | } | ||
| 362 | |||
| 363 | /** | ||
| 364 | * Returns the requested data array element from the specified | ||
| 365 | * bank as a <code>double</code>. | ||
| 366 | * | ||
| 367 | * @param bank The bank number. | ||
| 368 | * @param i The desired data array element. | ||
| 369 | * | ||
| 370 | * @return The data entry as a <code>double</code>. | ||
| 371 | * @see #setElemDouble(int, double) | ||
| 372 | * @see #setElemDouble(int, int, double) | ||
| 373 | */ | ||
| 374 | public double getElemDouble(int bank, int i) { | ||
| 375 | return (double)bankdata[bank][i+offsets[bank]]; | ||
| 376 | } | ||
| 377 | |||
| 378 | /** | ||
| 379 | * Sets the requested data array element in the first (default) | ||
| 380 | * bank to the given <code>double</code>. | ||
| 381 | * | ||
| 382 | * @param i The desired data array element. | ||
| 383 | * @param val The value to be set. | ||
| 384 | * @see #getElemDouble(int) | ||
| 385 | * @see #getElemDouble(int, int) | ||
| 386 | */ | ||
| 387 | public void setElemDouble(int i, double val) { | ||
| 388 | data[i+offset] = (float)val; | ||
| 389 | theTrackable.markDirty(); | ||
| 390 | } | ||
| 391 | |||
| 392 | /** | ||
| 393 | * Sets the requested data array element in the specified bank to | ||
| 394 | * the given <code>double</code>. | ||
| 395 | * | ||
| 396 | * @param bank The bank number. | ||
| 397 | * @param i The desired data array element. | ||
| 398 | * @param val The value to be set. | ||
| 399 | * @see #getElemDouble(int) | ||
| 400 | * @see #getElemDouble(int, int) | ||
| 401 | */ | ||
| 402 | public void setElemDouble(int bank, int i, double val) { | ||
| 403 | bankdata[bank][i+offsets[bank]] = (float)val; | ||
| 404 | theTrackable.markDirty(); | ||
| 405 | } | ||
| 406 | } | ||
Binary file not shown.
| @@ -0,0 +1,284 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 | /* **************************************************************** | ||
| 27 | ****************************************************************** | ||
| 28 | ****************************************************************** | ||
| 29 | *** COPYRIGHT (c) Eastman Kodak Company, 1997 | ||
| 30 | *** As an unpublished work pursuant to Title 17 of the United | ||
| 31 | *** States Code. All rights reserved. | ||
| 32 | ****************************************************************** | ||
| 33 | ****************************************************************** | ||
| 34 | ******************************************************************/ | ||
| 35 | |||
| 36 | package java.awt.image; | ||
| 37 | |||
| 38 | import static sun.java2d.StateTrackable.State.*; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * This class extends <CODE>DataBuffer</CODE> and stores data internally | ||
| 42 | * as integers. | ||
| 43 | * <p> | ||
| 44 | * <a name="optimizations"> | ||
| 45 | * Note that some implementations may function more efficiently | ||
| 46 | * if they can maintain control over how the data for an image is | ||
| 47 | * stored. | ||
| 48 | * For example, optimizations such as caching an image in video | ||
| 49 | * memory require that the implementation track all modifications | ||
| 50 | * to that data. | ||
| 51 | * Other implementations may operate better if they can store the | ||
| 52 | * data in locations other than a Java array. | ||
| 53 | * To maintain optimum compatibility with various optimizations | ||
| 54 | * it is best to avoid constructors and methods which expose the | ||
| 55 | * underlying storage as a Java array as noted below in the | ||
| 56 | * documentation for those methods. | ||
| 57 | * </a> | ||
| 58 | */ | ||
| 59 | public final class DataBufferInt extends DataBuffer | ||
| 60 | { | ||
| 61 | /** The default data bank. */ | ||
| 62 | int data[]; | ||
| 63 | |||
| 64 | /** All data banks */ | ||
| 65 | int bankdata[][]; | ||
| 66 | |||
| 67 | /** | ||
| 68 | * Constructs an integer-based <CODE>DataBuffer</CODE> with a single bank | ||
| 69 | * and the specified size. | ||
| 70 | * | ||
| 71 | * @param size The size of the <CODE>DataBuffer</CODE>. | ||
| 72 | */ | ||
| 73 | public DataBufferInt(int size) { | ||
| 74 | super(STABLE, TYPE_INT, size); | ||
| 75 | data = new int[size]; | ||
| 76 | bankdata = new int[1][]; | ||
| 77 | bankdata[0] = data; | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Constructs an integer-based <CODE>DataBuffer</CODE> with the specified number of | ||
| 82 | * banks, all of which are the specified size. | ||
| 83 | * | ||
| 84 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 85 | * @param numBanks The number of banks in the a<CODE>DataBuffer</CODE>. | ||
| 86 | */ | ||
| 87 | public DataBufferInt(int size, int numBanks) { | ||
| 88 | super(STABLE, TYPE_INT, size, numBanks); | ||
| 89 | bankdata = new int[numBanks][]; | ||
| 90 | for (int i= 0; i < numBanks; i++) { | ||
| 91 | bankdata[i] = new int[size]; | ||
| 92 | } | ||
| 93 | data = bankdata[0]; | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Constructs an integer-based <CODE>DataBuffer</CODE> with a single bank using the | ||
| 98 | * specified array. | ||
| 99 | * Only the first <CODE>size</CODE> elements should be used by accessors of | ||
| 100 | * this <CODE>DataBuffer</CODE>. <CODE>dataArray</CODE> must be large enough to | ||
| 101 | * hold <CODE>size</CODE> elements. | ||
| 102 | * <p> | ||
| 103 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 104 | * may be incompatible with <a href="#optimizations">performance | ||
| 105 | * optimizations</a> used by some implementations (such as caching | ||
| 106 | * an associated image in video memory). | ||
| 107 | * | ||
| 108 | * @param dataArray The integer array for the <CODE>DataBuffer</CODE>. | ||
| 109 | * @param size The size of the <CODE>DataBuffer</CODE> bank. | ||
| 110 | */ | ||
| 111 | public DataBufferInt(int dataArray[], int size) { | ||
| 112 | super(UNTRACKABLE, TYPE_INT, size); | ||
| 113 | data = dataArray; | ||
| 114 | bankdata = new int[1][]; | ||
| 115 | bankdata[0] = data; | ||
| 116 | } | ||
| 117 | |||
| 118 | /** | ||
| 119 | * Constructs an integer-based <CODE>DataBuffer</CODE> with a single bank using the | ||
| 120 | * specified array, size, and offset. <CODE>dataArray</CODE> must have at least | ||
| 121 | * <CODE>offset</CODE> + <CODE>size</CODE> elements. Only elements <CODE>offset</CODE> | ||
| 122 | * through <CODE>offset</CODE> + <CODE>size</CODE> - 1 | ||
| 123 | * should be used by accessors of this <CODE>DataBuffer</CODE>. | ||
| 124 | * <p> | ||
| 125 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 126 | * may be incompatible with <a href="#optimizations">performance | ||
| 127 | * optimizations</a> used by some implementations (such as caching | ||
| 128 | * an associated image in video memory). | ||
| 129 | * | ||
| 130 | * @param dataArray The integer array for the <CODE>DataBuffer</CODE>. | ||
| 131 | * @param size The size of the <CODE>DataBuffer</CODE> bank. | ||
| 132 | * @param offset The offset into the <CODE>dataArray</CODE>. | ||
| 133 | */ | ||
| 134 | public DataBufferInt(int dataArray[], int size, int offset) { | ||
| 135 | super(UNTRACKABLE, TYPE_INT, size, 1, offset); | ||
| 136 | data = dataArray; | ||
| 137 | bankdata = new int[1][]; | ||
| 138 | bankdata[0] = data; | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * Constructs an integer-based <CODE>DataBuffer</CODE> with the specified arrays. | ||
| 143 | * The number of banks will be equal to <CODE>dataArray.length</CODE>. | ||
| 144 | * Only the first <CODE>size</CODE> elements of each array should be used by | ||
| 145 | * accessors of this <CODE>DataBuffer</CODE>. | ||
| 146 | * <p> | ||
| 147 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 148 | * may be incompatible with <a href="#optimizations">performance | ||
| 149 | * optimizations</a> used by some implementations (such as caching | ||
| 150 | * an associated image in video memory). | ||
| 151 | * | ||
| 152 | * @param dataArray The integer arrays for the <CODE>DataBuffer</CODE>. | ||
| 153 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 154 | */ | ||
| 155 | public DataBufferInt(int dataArray[][], int size) { | ||
| 156 | super(UNTRACKABLE, TYPE_INT, size, dataArray.length); | ||
| 157 | bankdata = (int [][]) dataArray.clone(); | ||
| 158 | data = bankdata[0]; | ||
| 159 | } | ||
| 160 | |||
| 161 | /** | ||
| 162 | * Constructs an integer-based <CODE>DataBuffer</CODE> with the specified arrays, size, | ||
| 163 | * and offsets. | ||
| 164 | * The number of banks is equal to <CODE>dataArray.length</CODE>. Each array must | ||
| 165 | * be at least as large as <CODE>size</CODE> + the corresponding offset. There must | ||
| 166 | * be an entry in the offset array for each <CODE>dataArray</CODE> entry. For each | ||
| 167 | * bank, only elements <CODE>offset</CODE> through | ||
| 168 | * <CODE>offset</CODE> + <CODE>size</CODE> - 1 should be | ||
| 169 | * used by accessors of this <CODE>DataBuffer</CODE>. | ||
| 170 | * <p> | ||
| 171 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 172 | * may be incompatible with <a href="#optimizations">performance | ||
| 173 | * optimizations</a> used by some implementations (such as caching | ||
| 174 | * an associated image in video memory). | ||
| 175 | * | ||
| 176 | * @param dataArray The integer arrays for the <CODE>DataBuffer</CODE>. | ||
| 177 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 178 | * @param offsets The offsets into each array. | ||
| 179 | */ | ||
| 180 | public DataBufferInt(int dataArray[][], int size, int offsets[]) { | ||
| 181 | super(UNTRACKABLE, TYPE_INT, size, dataArray.length, offsets); | ||
| 182 | bankdata = (int [][]) dataArray.clone(); | ||
| 183 | data = bankdata[0]; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * Returns the default (first) int data array in <CODE>DataBuffer</CODE>. | ||
| 188 | * <p> | ||
| 189 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 190 | * object to be incompatible with <a href="#optimizations">performance | ||
| 191 | * optimizations</a> used by some implementations (such as caching | ||
| 192 | * an associated image in video memory). | ||
| 193 | * | ||
| 194 | * @return The first integer data array. | ||
| 195 | */ | ||
| 196 | public int[] getData() { | ||
| 197 | theTrackable.setUntrackable(); | ||
| 198 | return data; | ||
| 199 | } | ||
| 200 | |||
| 201 | /** | ||
| 202 | * Returns the data array for the specified bank. | ||
| 203 | * <p> | ||
| 204 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 205 | * object to be incompatible with <a href="#optimizations">performance | ||
| 206 | * optimizations</a> used by some implementations (such as caching | ||
| 207 | * an associated image in video memory). | ||
| 208 | * | ||
| 209 | * @param bank The bank whose data array you want to get. | ||
| 210 | * @return The data array for the specified bank. | ||
| 211 | */ | ||
| 212 | public int[] getData(int bank) { | ||
| 213 | theTrackable.setUntrackable(); | ||
| 214 | return bankdata[bank]; | ||
| 215 | } | ||
| 216 | |||
| 217 | /** | ||
| 218 | * Returns the data arrays for all banks. | ||
| 219 | * <p> | ||
| 220 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 221 | * object to be incompatible with <a href="#optimizations">performance | ||
| 222 | * optimizations</a> used by some implementations (such as caching | ||
| 223 | * an associated image in video memory). | ||
| 224 | * | ||
| 225 | * @return All of the data arrays. | ||
| 226 | */ | ||
| 227 | public int[][] getBankData() { | ||
| 228 | theTrackable.setUntrackable(); | ||
| 229 | return (int [][]) bankdata.clone(); | ||
| 230 | } | ||
| 231 | |||
| 232 | /** | ||
| 233 | * Returns the requested data array element from the first (default) bank. | ||
| 234 | * | ||
| 235 | * @param i The data array element you want to get. | ||
| 236 | * @return The requested data array element as an integer. | ||
| 237 | * @see #setElem(int, int) | ||
| 238 | * @see #setElem(int, int, int) | ||
| 239 | */ | ||
| 240 | public int getElem(int i) { | ||
| 241 | return data[i+offset]; | ||
| 242 | } | ||
| 243 | |||
| 244 | /** | ||
| 245 | * Returns the requested data array element from the specified bank. | ||
| 246 | * | ||
| 247 | * @param bank The bank from which you want to get a data array element. | ||
| 248 | * @param i The data array element you want to get. | ||
| 249 | * @return The requested data array element as an integer. | ||
| 250 | * @see #setElem(int, int) | ||
| 251 | * @see #setElem(int, int, int) | ||
| 252 | */ | ||
| 253 | public int getElem(int bank, int i) { | ||
| 254 | return bankdata[bank][i+offsets[bank]]; | ||
| 255 | } | ||
| 256 | |||
| 257 | /** | ||
| 258 | * Sets the requested data array element in the first (default) bank | ||
| 259 | * to the specified value. | ||
| 260 | * | ||
| 261 | * @param i The data array element you want to set. | ||
| 262 | * @param val The integer value to which you want to set the data array element. | ||
| 263 | * @see #getElem(int) | ||
| 264 | * @see #getElem(int, int) | ||
| 265 | */ | ||
| 266 | public void setElem(int i, int val) { | ||
| 267 | data[i+offset] = val; | ||
| 268 | theTrackable.markDirty(); | ||
| 269 | } | ||
| 270 | |||
| 271 | /** | ||
| 272 | * Sets the requested data array element in the specified bank | ||
| 273 | * to the integer value <CODE>i</CODE>. | ||
| 274 | * @param bank The bank in which you want to set the data array element. | ||
| 275 | * @param i The data array element you want to set. | ||
| 276 | * @param val The integer value to which you want to set the specified data array element. | ||
| 277 | * @see #getElem(int) | ||
| 278 | * @see #getElem(int, int) | ||
| 279 | */ | ||
| 280 | public void setElem(int bank, int i, int val) { | ||
| 281 | bankdata[bank][i+offsets[bank]] = (int)val; | ||
| 282 | theTrackable.markDirty(); | ||
| 283 | } | ||
| 284 | } | ||
Binary file not shown.
| @@ -0,0 +1,283 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 | /* **************************************************************** | ||
| 27 | ****************************************************************** | ||
| 28 | ****************************************************************** | ||
| 29 | *** COPYRIGHT (c) Eastman Kodak Company, 1997 | ||
| 30 | *** As an unpublished work pursuant to Title 17 of the United | ||
| 31 | *** States Code. All rights reserved. | ||
| 32 | ****************************************************************** | ||
| 33 | ****************************************************************** | ||
| 34 | ******************************************************************/ | ||
| 35 | |||
| 36 | package java.awt.image; | ||
| 37 | |||
| 38 | import static sun.java2d.StateTrackable.State.*; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * This class extends <CODE>DataBuffer</CODE> and stores data internally as shorts. | ||
| 42 | * <p> | ||
| 43 | * <a name="optimizations"> | ||
| 44 | * Note that some implementations may function more efficiently | ||
| 45 | * if they can maintain control over how the data for an image is | ||
| 46 | * stored. | ||
| 47 | * For example, optimizations such as caching an image in video | ||
| 48 | * memory require that the implementation track all modifications | ||
| 49 | * to that data. | ||
| 50 | * Other implementations may operate better if they can store the | ||
| 51 | * data in locations other than a Java array. | ||
| 52 | * To maintain optimum compatibility with various optimizations | ||
| 53 | * it is best to avoid constructors and methods which expose the | ||
| 54 | * underlying storage as a Java array as noted below in the | ||
| 55 | * documentation for those methods. | ||
| 56 | * </a> | ||
| 57 | */ | ||
| 58 | public final class DataBufferShort extends DataBuffer | ||
| 59 | { | ||
| 60 | /** The default data bank. */ | ||
| 61 | short data[]; | ||
| 62 | |||
| 63 | /** All data banks */ | ||
| 64 | short bankdata[][]; | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Constructs a short-based <CODE>DataBuffer</CODE> with a single bank and the | ||
| 68 | * specified size. | ||
| 69 | * | ||
| 70 | * @param size The size of the <CODE>DataBuffer</CODE>. | ||
| 71 | */ | ||
| 72 | public DataBufferShort(int size) { | ||
| 73 | super(STABLE, TYPE_SHORT,size); | ||
| 74 | data = new short[size]; | ||
| 75 | bankdata = new short[1][]; | ||
| 76 | bankdata[0] = data; | ||
| 77 | } | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Constructs a short-based <CODE>DataBuffer</CODE> with the specified number of | ||
| 81 | * banks all of which are the specified size. | ||
| 82 | * | ||
| 83 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 84 | * @param numBanks The number of banks in the a<CODE>DataBuffer</CODE>. | ||
| 85 | */ | ||
| 86 | public DataBufferShort(int size, int numBanks) { | ||
| 87 | super(STABLE, TYPE_SHORT,size,numBanks); | ||
| 88 | bankdata = new short[numBanks][]; | ||
| 89 | for (int i= 0; i < numBanks; i++) { | ||
| 90 | bankdata[i] = new short[size]; | ||
| 91 | } | ||
| 92 | data = bankdata[0]; | ||
| 93 | } | ||
| 94 | |||
| 95 | /** | ||
| 96 | * Constructs a short-based <CODE>DataBuffer</CODE> with a single bank using the | ||
| 97 | * specified array. | ||
| 98 | * Only the first <CODE>size</CODE> elements should be used by accessors of | ||
| 99 | * this <CODE>DataBuffer</CODE>. <CODE>dataArray</CODE> must be large enough to | ||
| 100 | * hold <CODE>size</CODE> elements. | ||
| 101 | * <p> | ||
| 102 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 103 | * may be incompatible with <a href="#optimizations">performance | ||
| 104 | * optimizations</a> used by some implementations (such as caching | ||
| 105 | * an associated image in video memory). | ||
| 106 | * | ||
| 107 | * @param dataArray The short array for the <CODE>DataBuffer</CODE>. | ||
| 108 | * @param size The size of the <CODE>DataBuffer</CODE> bank. | ||
| 109 | */ | ||
| 110 | public DataBufferShort(short dataArray[], int size) { | ||
| 111 | super(UNTRACKABLE, TYPE_SHORT, size); | ||
| 112 | data = dataArray; | ||
| 113 | bankdata = new short[1][]; | ||
| 114 | bankdata[0] = data; | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Constructs a short-based <CODE>DataBuffer</CODE> with a single bank using the | ||
| 119 | * specified array, size, and offset. <CODE>dataArray</CODE> must have at least | ||
| 120 | * <CODE>offset</CODE> + <CODE>size</CODE> elements. Only elements <CODE>offset</CODE> | ||
| 121 | * through <CODE>offset</CODE> + <CODE>size</CODE> - 1 | ||
| 122 | * should be used by accessors of this <CODE>DataBuffer</CODE>. | ||
| 123 | * <p> | ||
| 124 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 125 | * may be incompatible with <a href="#optimizations">performance | ||
| 126 | * optimizations</a> used by some implementations (such as caching | ||
| 127 | * an associated image in video memory). | ||
| 128 | * | ||
| 129 | * @param dataArray The short array for the <CODE>DataBuffer</CODE>. | ||
| 130 | * @param size The size of the <CODE>DataBuffer</CODE> bank. | ||
| 131 | * @param offset The offset into the <CODE>dataArray</CODE>. | ||
| 132 | */ | ||
| 133 | public DataBufferShort(short dataArray[], int size, int offset) { | ||
| 134 | super(UNTRACKABLE, TYPE_SHORT, size, 1, offset); | ||
| 135 | data = dataArray; | ||
| 136 | bankdata = new short[1][]; | ||
| 137 | bankdata[0] = data; | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Constructs a short-based <CODE>DataBuffer</CODE> with the specified arrays. | ||
| 142 | * The number of banks will be equal to <CODE>dataArray.length</CODE>. | ||
| 143 | * Only the first <CODE>size</CODE> elements of each array should be used by | ||
| 144 | * accessors of this <CODE>DataBuffer</CODE>. | ||
| 145 | * <p> | ||
| 146 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 147 | * may be incompatible with <a href="#optimizations">performance | ||
| 148 | * optimizations</a> used by some implementations (such as caching | ||
| 149 | * an associated image in video memory). | ||
| 150 | * | ||
| 151 | * @param dataArray The short arrays for the <CODE>DataBuffer</CODE>. | ||
| 152 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 153 | */ | ||
| 154 | public DataBufferShort(short dataArray[][], int size) { | ||
| 155 | super(UNTRACKABLE, TYPE_SHORT, size, dataArray.length); | ||
| 156 | bankdata = (short[][]) dataArray.clone(); | ||
| 157 | data = bankdata[0]; | ||
| 158 | } | ||
| 159 | |||
| 160 | /** | ||
| 161 | * Constructs a short-based <CODE>DataBuffer</CODE> with the specified arrays, size, | ||
| 162 | * and offsets. | ||
| 163 | * The number of banks is equal to <CODE>dataArray.length</CODE>. Each array must | ||
| 164 | * be at least as large as <CODE>size</CODE> + the corresponding offset. There must | ||
| 165 | * be an entry in the offset array for each <CODE>dataArray</CODE> entry. For each | ||
| 166 | * bank, only elements <CODE>offset</CODE> through | ||
| 167 | * <CODE>offset</CODE> + <CODE>size</CODE> - 1 should be | ||
| 168 | * used by accessors of this <CODE>DataBuffer</CODE>. | ||
| 169 | * <p> | ||
| 170 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 171 | * may be incompatible with <a href="#optimizations">performance | ||
| 172 | * optimizations</a> used by some implementations (such as caching | ||
| 173 | * an associated image in video memory). | ||
| 174 | * | ||
| 175 | * @param dataArray The short arrays for the <CODE>DataBuffer</CODE>. | ||
| 176 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 177 | * @param offsets The offsets into each array. | ||
| 178 | */ | ||
| 179 | public DataBufferShort(short dataArray[][], int size, int offsets[]) { | ||
| 180 | super(UNTRACKABLE, TYPE_SHORT, size, dataArray.length, offsets); | ||
| 181 | bankdata = (short[][]) dataArray.clone(); | ||
| 182 | data = bankdata[0]; | ||
| 183 | } | ||
| 184 | |||
| 185 | /** | ||
| 186 | * Returns the default (first) byte data array. | ||
| 187 | * <p> | ||
| 188 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 189 | * object to be incompatible with <a href="#optimizations">performance | ||
| 190 | * optimizations</a> used by some implementations (such as caching | ||
| 191 | * an associated image in video memory). | ||
| 192 | * | ||
| 193 | * @return The first short data array. | ||
| 194 | */ | ||
| 195 | public short[] getData() { | ||
| 196 | theTrackable.setUntrackable(); | ||
| 197 | return data; | ||
| 198 | } | ||
| 199 | |||
| 200 | /** | ||
| 201 | * Returns the data array for the specified bank. | ||
| 202 | * <p> | ||
| 203 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 204 | * object to be incompatible with <a href="#optimizations">performance | ||
| 205 | * optimizations</a> used by some implementations (such as caching | ||
| 206 | * an associated image in video memory). | ||
| 207 | * | ||
| 208 | * @param bank The bank whose data array you want to get. | ||
| 209 | * @return The data array for the specified bank. | ||
| 210 | */ | ||
| 211 | public short[] getData(int bank) { | ||
| 212 | theTrackable.setUntrackable(); | ||
| 213 | return bankdata[bank]; | ||
| 214 | } | ||
| 215 | |||
| 216 | /** | ||
| 217 | * Returns the data arrays for all banks. | ||
| 218 | * <p> | ||
| 219 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 220 | * object to be incompatible with <a href="#optimizations">performance | ||
| 221 | * optimizations</a> used by some implementations (such as caching | ||
| 222 | * an associated image in video memory). | ||
| 223 | * | ||
| 224 | * @return All of the data arrays. | ||
| 225 | */ | ||
| 226 | public short[][] getBankData() { | ||
| 227 | theTrackable.setUntrackable(); | ||
| 228 | return (short[][]) bankdata.clone(); | ||
| 229 | } | ||
| 230 | |||
| 231 | /** | ||
| 232 | * Returns the requested data array element from the first (default) bank. | ||
| 233 | * | ||
| 234 | * @param i The data array element you want to get. | ||
| 235 | * @return The requested data array element as an integer. | ||
| 236 | * @see #setElem(int, int) | ||
| 237 | * @see #setElem(int, int, int) | ||
| 238 | */ | ||
| 239 | public int getElem(int i) { | ||
| 240 | return (int)(data[i+offset]); | ||
| 241 | } | ||
| 242 | |||
| 243 | /** | ||
| 244 | * Returns the requested data array element from the specified bank. | ||
| 245 | * | ||
| 246 | * @param bank The bank from which you want to get a data array element. | ||
| 247 | * @param i The data array element you want to get. | ||
| 248 | * @return The requested data array element as an integer. | ||
| 249 | * @see #setElem(int, int) | ||
| 250 | * @see #setElem(int, int, int) | ||
| 251 | */ | ||
| 252 | public int getElem(int bank, int i) { | ||
| 253 | return (int)(bankdata[bank][i+offsets[bank]]); | ||
| 254 | } | ||
| 255 | |||
| 256 | /** | ||
| 257 | * Sets the requested data array element in the first (default) bank | ||
| 258 | * to the specified value. | ||
| 259 | * | ||
| 260 | * @param i The data array element you want to set. | ||
| 261 | * @param val The integer value to which you want to set the data array element. | ||
| 262 | * @see #getElem(int) | ||
| 263 | * @see #getElem(int, int) | ||
| 264 | */ | ||
| 265 | public void setElem(int i, int val) { | ||
| 266 | data[i+offset] = (short)val; | ||
| 267 | theTrackable.markDirty(); | ||
| 268 | } | ||
| 269 | |||
| 270 | /** | ||
| 271 | * Sets the requested data array element in the specified bank | ||
| 272 | * from the given integer. | ||
| 273 | * @param bank The bank in which you want to set the data array element. | ||
| 274 | * @param i The data array element you want to set. | ||
| 275 | * @param val The integer value to which you want to set the specified data array element. | ||
| 276 | * @see #getElem(int) | ||
| 277 | * @see #getElem(int, int) | ||
| 278 | */ | ||
| 279 | public void setElem(int bank, int i, int val) { | ||
| 280 | bankdata[bank][i+offsets[bank]] = (short)val; | ||
| 281 | theTrackable.markDirty(); | ||
| 282 | } | ||
| 283 | } | ||
Binary file not shown.
| @@ -0,0 +1,318 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 | /* **************************************************************** | ||
| 27 | ****************************************************************** | ||
| 28 | ****************************************************************** | ||
| 29 | *** COPYRIGHT (c) Eastman Kodak Company, 1997 | ||
| 30 | *** As an unpublished work pursuant to Title 17 of the United | ||
| 31 | *** States Code. All rights reserved. | ||
| 32 | ****************************************************************** | ||
| 33 | ****************************************************************** | ||
| 34 | ******************************************************************/ | ||
| 35 | |||
| 36 | package java.awt.image; | ||
| 37 | |||
| 38 | import static sun.java2d.StateTrackable.State.*; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * This class extends <CODE>DataBuffer</CODE> and stores data internally as | ||
| 42 | * shorts. Values stored in the short array(s) of this <CODE>DataBuffer</CODE> | ||
| 43 | * are treated as unsigned values. | ||
| 44 | * <p> | ||
| 45 | * <a name="optimizations"> | ||
| 46 | * Note that some implementations may function more efficiently | ||
| 47 | * if they can maintain control over how the data for an image is | ||
| 48 | * stored. | ||
| 49 | * For example, optimizations such as caching an image in video | ||
| 50 | * memory require that the implementation track all modifications | ||
| 51 | * to that data. | ||
| 52 | * Other implementations may operate better if they can store the | ||
| 53 | * data in locations other than a Java array. | ||
| 54 | * To maintain optimum compatibility with various optimizations | ||
| 55 | * it is best to avoid constructors and methods which expose the | ||
| 56 | * underlying storage as a Java array as noted below in the | ||
| 57 | * documentation for those methods. | ||
| 58 | * </a> | ||
| 59 | */ | ||
| 60 | public final class DataBufferUShort extends DataBuffer | ||
| 61 | { | ||
| 62 | /** The default data bank. */ | ||
| 63 | short data[]; | ||
| 64 | |||
| 65 | /** All data banks */ | ||
| 66 | short bankdata[][]; | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with a single bank and the | ||
| 70 | * specified size. | ||
| 71 | * | ||
| 72 | * @param size The size of the <CODE>DataBuffer</CODE>. | ||
| 73 | */ | ||
| 74 | public DataBufferUShort(int size) { | ||
| 75 | super(STABLE, TYPE_USHORT, size); | ||
| 76 | data = new short[size]; | ||
| 77 | bankdata = new short[1][]; | ||
| 78 | bankdata[0] = data; | ||
| 79 | } | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with the specified number of | ||
| 83 | * banks, all of which are the specified size. | ||
| 84 | * | ||
| 85 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 86 | * @param numBanks The number of banks in the a<CODE>DataBuffer</CODE>. | ||
| 87 | */ | ||
| 88 | public DataBufferUShort(int size, int numBanks) { | ||
| 89 | super(STABLE, TYPE_USHORT, size, numBanks); | ||
| 90 | bankdata = new short[numBanks][]; | ||
| 91 | for (int i= 0; i < numBanks; i++) { | ||
| 92 | bankdata[i] = new short[size]; | ||
| 93 | } | ||
| 94 | data = bankdata[0]; | ||
| 95 | } | ||
| 96 | |||
| 97 | /** | ||
| 98 | * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with a single bank | ||
| 99 | * using the specified array. | ||
| 100 | * Only the first <CODE>size</CODE> elements should be used by accessors of | ||
| 101 | * this <CODE>DataBuffer</CODE>. <CODE>dataArray</CODE> must be large enough to | ||
| 102 | * hold <CODE>size</CODE> elements. | ||
| 103 | * <p> | ||
| 104 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 105 | * may be incompatible with <a href="#optimizations">performance | ||
| 106 | * optimizations</a> used by some implementations (such as caching | ||
| 107 | * an associated image in video memory). | ||
| 108 | * | ||
| 109 | * @param dataArray The unsigned-short array for the <CODE>DataBuffer</CODE>. | ||
| 110 | * @param size The size of the <CODE>DataBuffer</CODE> bank. | ||
| 111 | */ | ||
| 112 | public DataBufferUShort(short dataArray[], int size) { | ||
| 113 | super(UNTRACKABLE, TYPE_USHORT, size); | ||
| 114 | if (dataArray == null) { | ||
| 115 | throw new NullPointerException("dataArray is null"); | ||
| 116 | } | ||
| 117 | data = dataArray; | ||
| 118 | bankdata = new short[1][]; | ||
| 119 | bankdata[0] = data; | ||
| 120 | } | ||
| 121 | |||
| 122 | /** | ||
| 123 | * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with a single bank | ||
| 124 | * using the specified array, size, and offset. <CODE>dataArray</CODE> must have at | ||
| 125 | * least <CODE>offset</CODE> + <CODE>size</CODE> elements. Only elements | ||
| 126 | * <CODE>offset</CODE> through <CODE>offset</CODE> + <CODE>size</CODE> - 1 should | ||
| 127 | * be used by accessors of this <CODE>DataBuffer</CODE>. | ||
| 128 | * <p> | ||
| 129 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 130 | * may be incompatible with <a href="#optimizations">performance | ||
| 131 | * optimizations</a> used by some implementations (such as caching | ||
| 132 | * an associated image in video memory). | ||
| 133 | * | ||
| 134 | * @param dataArray The unsigned-short array for the <CODE>DataBuffer</CODE>. | ||
| 135 | * @param size The size of the <CODE>DataBuffer</CODE> bank. | ||
| 136 | * @param offset The offset into the <CODE>dataArray</CODE>. | ||
| 137 | */ | ||
| 138 | public DataBufferUShort(short dataArray[], int size, int offset) { | ||
| 139 | super(UNTRACKABLE, TYPE_USHORT, size, 1, offset); | ||
| 140 | if (dataArray == null) { | ||
| 141 | throw new NullPointerException("dataArray is null"); | ||
| 142 | } | ||
| 143 | if ((size+offset) > dataArray.length) { | ||
| 144 | throw new IllegalArgumentException("Length of dataArray is less "+ | ||
| 145 | " than size+offset."); | ||
| 146 | } | ||
| 147 | data = dataArray; | ||
| 148 | bankdata = new short[1][]; | ||
| 149 | bankdata[0] = data; | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with the specified arrays. | ||
| 154 | * The number of banks will be equal to <CODE>dataArray.length</CODE>. | ||
| 155 | * Only the first <CODE>size</CODE> elements of each array should be used by | ||
| 156 | * accessors of this <CODE>DataBuffer</CODE>. | ||
| 157 | * <p> | ||
| 158 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 159 | * may be incompatible with <a href="#optimizations">performance | ||
| 160 | * optimizations</a> used by some implementations (such as caching | ||
| 161 | * an associated image in video memory). | ||
| 162 | * | ||
| 163 | * @param dataArray The unsigned-short arrays for the <CODE>DataBuffer</CODE>. | ||
| 164 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 165 | */ | ||
| 166 | public DataBufferUShort(short dataArray[][], int size) { | ||
| 167 | super(UNTRACKABLE, TYPE_USHORT, size, dataArray.length); | ||
| 168 | if (dataArray == null) { | ||
| 169 | throw new NullPointerException("dataArray is null"); | ||
| 170 | } | ||
| 171 | for (int i=0; i < dataArray.length; i++) { | ||
| 172 | if (dataArray[i] == null) { | ||
| 173 | throw new NullPointerException("dataArray["+i+"] is null"); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | bankdata = (short[][]) dataArray.clone(); | ||
| 178 | data = bankdata[0]; | ||
| 179 | } | ||
| 180 | |||
| 181 | /** | ||
| 182 | * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with specified arrays, | ||
| 183 | * size, and offsets. | ||
| 184 | * The number of banks is equal to <CODE>dataArray.length</CODE>. Each array must | ||
| 185 | * be at least as large as <CODE>size</CODE> + the corresponding offset. There must | ||
| 186 | * be an entry in the offset array for each <CODE>dataArray</CODE> entry. For each | ||
| 187 | * bank, only elements <CODE>offset</CODE> through | ||
| 188 | * <CODE>offset</CODE> + <CODE>size</CODE> - 1 should be | ||
| 189 | * used by accessors of this <CODE>DataBuffer</CODE>. | ||
| 190 | * <p> | ||
| 191 | * Note that {@code DataBuffer} objects created by this constructor | ||
| 192 | * may be incompatible with <a href="#optimizations">performance | ||
| 193 | * optimizations</a> used by some implementations (such as caching | ||
| 194 | * an associated image in video memory). | ||
| 195 | * | ||
| 196 | * @param dataArray The unsigned-short arrays for the <CODE>DataBuffer</CODE>. | ||
| 197 | * @param size The size of the banks in the <CODE>DataBuffer</CODE>. | ||
| 198 | * @param offsets The offsets into each array. | ||
| 199 | */ | ||
| 200 | public DataBufferUShort(short dataArray[][], int size, int offsets[]) { | ||
| 201 | super(UNTRACKABLE, TYPE_USHORT, size, dataArray.length, offsets); | ||
| 202 | if (dataArray == null) { | ||
| 203 | throw new NullPointerException("dataArray is null"); | ||
| 204 | } | ||
| 205 | for (int i=0; i < dataArray.length; i++) { | ||
| 206 | if (dataArray[i] == null) { | ||
| 207 | throw new NullPointerException("dataArray["+i+"] is null"); | ||
| 208 | } | ||
| 209 | if ((size+offsets[i]) > dataArray[i].length) { | ||
| 210 | throw new IllegalArgumentException("Length of dataArray["+i+ | ||
| 211 | "] is less than size+"+ | ||
| 212 | "offsets["+i+"]."); | ||
| 213 | } | ||
| 214 | |||
| 215 | } | ||
| 216 | bankdata = (short[][]) dataArray.clone(); | ||
| 217 | data = bankdata[0]; | ||
| 218 | } | ||
| 219 | |||
| 220 | /** | ||
| 221 | * Returns the default (first) unsigned-short data array. | ||
| 222 | * <p> | ||
| 223 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 224 | * object to be incompatible with <a href="#optimizations">performance | ||
| 225 | * optimizations</a> used by some implementations (such as caching | ||
| 226 | * an associated image in video memory). | ||
| 227 | * | ||
| 228 | * @return The first unsigned-short data array. | ||
| 229 | */ | ||
| 230 | public short[] getData() { | ||
| 231 | theTrackable.setUntrackable(); | ||
| 232 | return data; | ||
| 233 | } | ||
| 234 | |||
| 235 | /** | ||
| 236 | * Returns the data array for the specified bank. | ||
| 237 | * <p> | ||
| 238 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 239 | * object to be incompatible with <a href="#optimizations">performance | ||
| 240 | * optimizations</a> used by some implementations (such as caching | ||
| 241 | * an associated image in video memory). | ||
| 242 | * | ||
| 243 | * @param bank The bank whose data array you want to get. | ||
| 244 | * @return The data array for the specified bank. | ||
| 245 | */ | ||
| 246 | public short[] getData(int bank) { | ||
| 247 | theTrackable.setUntrackable(); | ||
| 248 | return bankdata[bank]; | ||
| 249 | } | ||
| 250 | |||
| 251 | /** | ||
| 252 | * Returns the data arrays for all banks. | ||
| 253 | * <p> | ||
| 254 | * Note that calling this method may cause this {@code DataBuffer} | ||
| 255 | * object to be incompatible with <a href="#optimizations">performance | ||
| 256 | * optimizations</a> used by some implementations (such as caching | ||
| 257 | * an associated image in video memory). | ||
| 258 | * | ||
| 259 | * @return All of the data arrays. | ||
| 260 | */ | ||
| 261 | public short[][] getBankData() { | ||
| 262 | theTrackable.setUntrackable(); | ||
| 263 | return (short[][]) bankdata.clone(); | ||
| 264 | } | ||
| 265 | |||
| 266 | /** | ||
| 267 | * Returns the requested data array element from the first (default) bank. | ||
| 268 | * | ||
| 269 | * @param i The data array element you want to get. | ||
| 270 | * @return The requested data array element as an integer. | ||
| 271 | * @see #setElem(int, int) | ||
| 272 | * @see #setElem(int, int, int) | ||
| 273 | */ | ||
| 274 | public int getElem(int i) { | ||
| 275 | return (int)(data[i+offset]&0xffff); | ||
| 276 | } | ||
| 277 | |||
| 278 | /** | ||
| 279 | * Returns the requested data array element from the specified bank. | ||
| 280 | * | ||
| 281 | * @param bank The bank from which you want to get a data array element. | ||
| 282 | * @param i The data array element you want to get. | ||
| 283 | * @return The requested data array element as an integer. | ||
| 284 | * @see #setElem(int, int) | ||
| 285 | * @see #setElem(int, int, int) | ||
| 286 | */ | ||
| 287 | public int getElem(int bank, int i) { | ||
| 288 | return (int)(bankdata[bank][i+offsets[bank]]&0xffff); | ||
| 289 | } | ||
| 290 | |||
| 291 | /** | ||
| 292 | * Sets the requested data array element in the first (default) bank | ||
| 293 | * to the specified value. | ||
| 294 | * | ||
| 295 | * @param i The data array element you want to set. | ||
| 296 | * @param val The integer value to which you want to set the data array element. | ||
| 297 | * @see #getElem(int) | ||
| 298 | * @see #getElem(int, int) | ||
| 299 | */ | ||
| 300 | public void setElem(int i, int val) { | ||
| 301 | data[i+offset] = (short)(val&0xffff); | ||
| 302 | theTrackable.markDirty(); | ||
| 303 | } | ||
| 304 | |||
| 305 | /** | ||
| 306 | * Sets the requested data array element in the specified bank | ||
| 307 | * from the given integer. | ||
| 308 | * @param bank The bank in which you want to set the data array element. | ||
| 309 | * @param i The data array element you want to set. | ||
| 310 | * @param val The integer value to which you want to set the specified data array element. | ||
| 311 | * @see #getElem(int) | ||
| 312 | * @see #getElem(int, int) | ||
| 313 | */ | ||
| 314 | public void setElem(int bank, int i, int val) { | ||
| 315 | bankdata[bank][i+offsets[bank]] = (short)(val&0xffff); | ||
| 316 | theTrackable.markDirty(); | ||
| 317 | } | ||
| 318 | } | ||
Binary file not shown.
| @@ -0,0 +1,1416 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 2001, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.color.ColorSpace; | ||
| 29 | import java.awt.Transparency; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * The <code>DirectColorModel</code> class is a <code>ColorModel</code> | ||
| 33 | * class that works with pixel values that represent RGB | ||
| 34 | * color and alpha information as separate samples and that pack all | ||
| 35 | * samples for a single pixel into a single int, short, or byte quantity. | ||
| 36 | * This class can be used only with ColorSpaces of type ColorSpace.TYPE_RGB. | ||
| 37 | * In addition, for each component of the ColorSpace, the minimum | ||
| 38 | * normalized component value obtained via the <code>getMinValue()</code> | ||
| 39 | * method of ColorSpace must be 0.0, and the maximum value obtained via | ||
| 40 | * the <code>getMaxValue()</code> method must be 1.0 (these min/max | ||
| 41 | * values are typical for RGB spaces). | ||
| 42 | * There must be three color samples in the pixel values and there can | ||
| 43 | * be a single alpha sample. For those methods that use a primitive array | ||
| 44 | * pixel representation of type <code>transferType</code>, the array | ||
| 45 | * length is always one. The transfer | ||
| 46 | * types supported are DataBuffer.TYPE_BYTE, | ||
| 47 | * DataBuffer.TYPE_USHORT, and DataBuffer.TYPE_INT. | ||
| 48 | * Color and alpha samples are stored in the single | ||
| 49 | * element of the array in bits indicated by bit masks. Each bit mask | ||
| 50 | * must be contiguous and masks must not overlap. The same masks apply to | ||
| 51 | * the single int pixel representation used by other methods. The | ||
| 52 | * correspondence of masks and color/alpha samples is as follows: | ||
| 53 | * <ul> | ||
| 54 | * <li> Masks are identified by indices running from 0 through 2 | ||
| 55 | * if no alpha is present, or 3 if an alpha is present. | ||
| 56 | * <li> The first three indices refer to color samples; | ||
| 57 | * index 0 corresponds to red, index 1 to green, and index 2 to blue. | ||
| 58 | * <li> Index 3 corresponds to the alpha sample, if present. | ||
| 59 | * </ul> | ||
| 60 | * <p> | ||
| 61 | * The translation from pixel values to color/alpha components for | ||
| 62 | * display or processing purposes is a one-to-one correspondence of | ||
| 63 | * samples to components. A <code>DirectColorModel</code> is | ||
| 64 | * typically used with image data which uses masks to define packed | ||
| 65 | * samples. For example, a <code>DirectColorModel</code> can be used in | ||
| 66 | * conjunction with a <code>SinglePixelPackedSampleModel</code> to | ||
| 67 | * construct a {@link BufferedImage}. Normally the masks used by the | ||
| 68 | * {@link SampleModel} and the <code>ColorModel</code> would be the | ||
| 69 | * same. However, if they are different, the color interpretation | ||
| 70 | * of pixel data will be done according to the masks of the | ||
| 71 | * <code>ColorModel</code>. | ||
| 72 | * <p> | ||
| 73 | * A single int pixel representation is valid for all objects of this | ||
| 74 | * class, since it is always possible to represent pixel values used with | ||
| 75 | * this class in a single int. Therefore, methods which use this | ||
| 76 | * representation will not throw an <code>IllegalArgumentException</code> | ||
| 77 | * due to an invalid pixel value. | ||
| 78 | * <p> | ||
| 79 | * This color model is similar to an X11 TrueColor visual. | ||
| 80 | * The default RGB ColorModel specified by the | ||
| 81 | * {@link ColorModel#getRGBdefault() getRGBdefault} method is a | ||
| 82 | * <code>DirectColorModel</code> with the following parameters: | ||
| 83 | * <pre> | ||
| 84 | * Number of bits: 32 | ||
| 85 | * Red mask: 0x00ff0000 | ||
| 86 | * Green mask: 0x0000ff00 | ||
| 87 | * Blue mask: 0x000000ff | ||
| 88 | * Alpha mask: 0xff000000 | ||
| 89 | * Color space: sRGB | ||
| 90 | * isAlphaPremultiplied: False | ||
| 91 | * Transparency: Transparency.TRANSLUCENT | ||
| 92 | * transferType: DataBuffer.TYPE_INT | ||
| 93 | * </pre> | ||
| 94 | * <p> | ||
| 95 | * Many of the methods in this class are final. This is because the | ||
| 96 | * underlying native graphics code makes assumptions about the layout | ||
| 97 | * and operation of this class and those assumptions are reflected in | ||
| 98 | * the implementations of the methods here that are marked final. You | ||
| 99 | * can subclass this class for other reasons, but you cannot override | ||
| 100 | * or modify the behavior of those methods. | ||
| 101 | * | ||
| 102 | * @see ColorModel | ||
| 103 | * @see ColorSpace | ||
| 104 | * @see SinglePixelPackedSampleModel | ||
| 105 | * @see BufferedImage | ||
| 106 | * @see ColorModel#getRGBdefault | ||
| 107 | * | ||
| 108 | */ | ||
| 109 | public class DirectColorModel extends PackedColorModel { | ||
| 110 | private int red_mask; | ||
| 111 | private int green_mask; | ||
| 112 | private int blue_mask; | ||
| 113 | private int alpha_mask; | ||
| 114 | private int red_offset; | ||
| 115 | private int green_offset; | ||
| 116 | private int blue_offset; | ||
| 117 | private int alpha_offset; | ||
| 118 | private int red_scale; | ||
| 119 | private int green_scale; | ||
| 120 | private int blue_scale; | ||
| 121 | private int alpha_scale; | ||
| 122 | private boolean is_LinearRGB; | ||
| 123 | private int lRGBprecision; | ||
| 124 | private byte[] tosRGB8LUT; | ||
| 125 | private byte[] fromsRGB8LUT8; | ||
| 126 | private short[] fromsRGB8LUT16; | ||
| 127 | |||
| 128 | /** | ||
| 129 | * Constructs a <code>DirectColorModel</code> from the specified masks | ||
| 130 | * that indicate which bits in an <code>int</code> pixel representation | ||
| 131 | * contain the red, green and blue color samples. As pixel values do not | ||
| 132 | * contain alpha information, all pixels are treated as opaque, which | ||
| 133 | * means that alpha = 1.0. All of the bits | ||
| 134 | * in each mask must be contiguous and fit in the specified number | ||
| 135 | * of least significant bits of an <code>int</code> pixel representation. | ||
| 136 | * The <code>ColorSpace</code> is the default sRGB space. The | ||
| 137 | * transparency value is Transparency.OPAQUE. The transfer type | ||
| 138 | * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, | ||
| 139 | * or DataBuffer.TYPE_INT that can hold a single pixel. | ||
| 140 | * @param bits the number of bits in the pixel values; for example, | ||
| 141 | * the sum of the number of bits in the masks. | ||
| 142 | * @param rmask specifies a mask indicating which bits in an | ||
| 143 | * integer pixel contain the red component | ||
| 144 | * @param gmask specifies a mask indicating which bits in an | ||
| 145 | * integer pixel contain the green component | ||
| 146 | * @param bmask specifies a mask indicating which bits in an | ||
| 147 | * integer pixel contain the blue component | ||
| 148 | * | ||
| 149 | */ | ||
| 150 | public DirectColorModel(int bits, | ||
| 151 | int rmask, int gmask, int bmask) { | ||
| 152 | this(bits, rmask, gmask, bmask, 0); | ||
| 153 | } | ||
| 154 | |||
| 155 | /** | ||
| 156 | * Constructs a <code>DirectColorModel</code> from the specified masks | ||
| 157 | * that indicate which bits in an <code>int</code> pixel representation | ||
| 158 | * contain the red, green and blue color samples and the alpha sample, | ||
| 159 | * if present. If <code>amask</code> is 0, pixel values do not contain | ||
| 160 | * alpha information and all pixels are treated as opaque, which means | ||
| 161 | * that alpha = 1.0. All of the bits in each mask must | ||
| 162 | * be contiguous and fit in the specified number of least significant bits | ||
| 163 | * of an <code>int</code> pixel representation. Alpha, if present, is not | ||
| 164 | * premultiplied. The <code>ColorSpace</code> is the default sRGB space. | ||
| 165 | * The transparency value is Transparency.OPAQUE if no alpha is | ||
| 166 | * present, or Transparency.TRANSLUCENT otherwise. The transfer type | ||
| 167 | * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, | ||
| 168 | * or DataBuffer.TYPE_INT that can hold a single pixel. | ||
| 169 | * @param bits the number of bits in the pixel values; for example, | ||
| 170 | * the sum of the number of bits in the masks. | ||
| 171 | * @param rmask specifies a mask indicating which bits in an | ||
| 172 | * integer pixel contain the red component | ||
| 173 | * @param gmask specifies a mask indicating which bits in an | ||
| 174 | * integer pixel contain the green component | ||
| 175 | * @param bmask specifies a mask indicating which bits in an | ||
| 176 | * integer pixel contain the blue component | ||
| 177 | * @param amask specifies a mask indicating which bits in an | ||
| 178 | * integer pixel contain the alpha component | ||
| 179 | */ | ||
| 180 | public DirectColorModel(int bits, int rmask, int gmask, | ||
| 181 | int bmask, int amask) { | ||
| 182 | super (ColorSpace.getInstance(ColorSpace.CS_sRGB), | ||
| 183 | bits, rmask, gmask, bmask, amask, false, | ||
| 184 | amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT, | ||
| 185 | ColorModel.getDefaultTransferType(bits)); | ||
| 186 | setFields(); | ||
| 187 | } | ||
| 188 | |||
| 189 | /** | ||
| 190 | * Constructs a <code>DirectColorModel</code> from the specified | ||
| 191 | * parameters. Color components are in the specified | ||
| 192 | * <code>ColorSpace</code>, which must be of type ColorSpace.TYPE_RGB | ||
| 193 | * and have minimum normalized component values which are all 0.0 | ||
| 194 | * and maximum values which are all 1.0. | ||
| 195 | * The masks specify which bits in an <code>int</code> pixel | ||
| 196 | * representation contain the red, green and blue color samples and | ||
| 197 | * the alpha sample, if present. If <code>amask</code> is 0, pixel | ||
| 198 | * values do not contain alpha information and all pixels are treated | ||
| 199 | * as opaque, which means that alpha = 1.0. All of the | ||
| 200 | * bits in each mask must be contiguous and fit in the specified number | ||
| 201 | * of least significant bits of an <code>int</code> pixel | ||
| 202 | * representation. If there is alpha, the <code>boolean</code> | ||
| 203 | * <code>isAlphaPremultiplied</code> specifies how to interpret | ||
| 204 | * color and alpha samples in pixel values. If the <code>boolean</code> | ||
| 205 | * is <code>true</code>, color samples are assumed to have been | ||
| 206 | * multiplied by the alpha sample. The transparency value is | ||
| 207 | * Transparency.OPAQUE, if no alpha is present, or | ||
| 208 | * Transparency.TRANSLUCENT otherwise. The transfer type | ||
| 209 | * is the type of primitive array used to represent pixel values and | ||
| 210 | * must be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or | ||
| 211 | * DataBuffer.TYPE_INT. | ||
| 212 | * @param space the specified <code>ColorSpace</code> | ||
| 213 | * @param bits the number of bits in the pixel values; for example, | ||
| 214 | * the sum of the number of bits in the masks. | ||
| 215 | * @param rmask specifies a mask indicating which bits in an | ||
| 216 | * integer pixel contain the red component | ||
| 217 | * @param gmask specifies a mask indicating which bits in an | ||
| 218 | * integer pixel contain the green component | ||
| 219 | * @param bmask specifies a mask indicating which bits in an | ||
| 220 | * integer pixel contain the blue component | ||
| 221 | * @param amask specifies a mask indicating which bits in an | ||
| 222 | * integer pixel contain the alpha component | ||
| 223 | * @param isAlphaPremultiplied <code>true</code> if color samples are | ||
| 224 | * premultiplied by the alpha sample; <code>false</code> otherwise | ||
| 225 | * @param transferType the type of array used to represent pixel values | ||
| 226 | * @throws IllegalArgumentException if <code>space</code> is not a | ||
| 227 | * TYPE_RGB space or if the min/max normalized component | ||
| 228 | * values are not 0.0/1.0. | ||
| 229 | */ | ||
| 230 | public DirectColorModel(ColorSpace space, int bits, int rmask, | ||
| 231 | int gmask, int bmask, int amask, | ||
| 232 | boolean isAlphaPremultiplied, | ||
| 233 | int transferType) { | ||
| 234 | super (space, bits, rmask, gmask, bmask, amask, | ||
| 235 | isAlphaPremultiplied, | ||
| 236 | amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT, | ||
| 237 | transferType); | ||
| 238 | if (ColorModel.isLinearRGBspace(colorSpace)) { | ||
| 239 | is_LinearRGB = true; | ||
| 240 | if (maxBits <= 8) { | ||
| 241 | lRGBprecision = 8; | ||
| 242 | tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT(); | ||
| 243 | fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT(); | ||
| 244 | } else { | ||
| 245 | lRGBprecision = 16; | ||
| 246 | tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT(); | ||
| 247 | fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); | ||
| 248 | } | ||
| 249 | } else if (!is_sRGB) { | ||
| 250 | for (int i = 0; i < 3; i++) { | ||
| 251 | // super constructor checks that space is TYPE_RGB | ||
| 252 | // check here that min/max are all 0.0/1.0 | ||
| 253 | if ((space.getMinValue(i) != 0.0f) || | ||
| 254 | (space.getMaxValue(i) != 1.0f)) { | ||
| 255 | throw new IllegalArgumentException( | ||
| 256 | "Illegal min/max RGB component value"); | ||
| 257 | } | ||
| 258 | } | ||
| 259 | } | ||
| 260 | setFields(); | ||
| 261 | } | ||
| 262 | |||
| 263 | /** | ||
| 264 | * Returns the mask indicating which bits in an <code>int</code> pixel | ||
| 265 | * representation contain the red color component. | ||
| 266 | * @return the mask, which indicates which bits of the <code>int</code> | ||
| 267 | * pixel representation contain the red color sample. | ||
| 268 | */ | ||
| 269 | final public int getRedMask() { | ||
| 270 | return maskArray[0]; | ||
| 271 | } | ||
| 272 | |||
| 273 | /** | ||
| 274 | * Returns the mask indicating which bits in an <code>int</code> pixel | ||
| 275 | * representation contain the green color component. | ||
| 276 | * @return the mask, which indicates which bits of the <code>int</code> | ||
| 277 | * pixel representation contain the green color sample. | ||
| 278 | */ | ||
| 279 | final public int getGreenMask() { | ||
| 280 | return maskArray[1]; | ||
| 281 | } | ||
| 282 | |||
| 283 | /** | ||
| 284 | * Returns the mask indicating which bits in an <code>int</code> pixel | ||
| 285 | * representation contain the blue color component. | ||
| 286 | * @return the mask, which indicates which bits of the <code>int</code> | ||
| 287 | * pixel representation contain the blue color sample. | ||
| 288 | */ | ||
| 289 | final public int getBlueMask() { | ||
| 290 | return maskArray[2]; | ||
| 291 | } | ||
| 292 | |||
| 293 | /** | ||
| 294 | * Returns the mask indicating which bits in an <code>int</code> pixel | ||
| 295 | * representation contain the alpha component. | ||
| 296 | * @return the mask, which indicates which bits of the <code>int</code> | ||
| 297 | * pixel representation contain the alpha sample. | ||
| 298 | */ | ||
| 299 | final public int getAlphaMask() { | ||
| 300 | if (supportsAlpha) { | ||
| 301 | return maskArray[3]; | ||
| 302 | } else { | ||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | |||
| 308 | /* | ||
| 309 | * Given an int pixel in this ColorModel's ColorSpace, converts | ||
| 310 | * it to the default sRGB ColorSpace and returns the R, G, and B | ||
| 311 | * components as float values between 0.0 and 1.0. | ||
| 312 | */ | ||
| 313 | private float[] getDefaultRGBComponents(int pixel) { | ||
| 314 | int components[] = getComponents(pixel, null, 0); | ||
| 315 | float norm[] = getNormalizedComponents(components, 0, null, 0); | ||
| 316 | // Note that getNormalizedComponents returns non-premultiplied values | ||
| 317 | return colorSpace.toRGB(norm); | ||
| 318 | } | ||
| 319 | |||
| 320 | |||
| 321 | private int getsRGBComponentFromsRGB(int pixel, int idx) { | ||
| 322 | int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]); | ||
| 323 | if (isAlphaPremultiplied) { | ||
| 324 | int a = ((pixel & maskArray[3]) >>> maskOffsets[3]); | ||
| 325 | c = (a == 0) ? 0 : | ||
| 326 | (int) (((c * scaleFactors[idx]) * 255.0f / | ||
| 327 | (a * scaleFactors[3])) + 0.5f); | ||
| 328 | } else if (scaleFactors[idx] != 1.0f) { | ||
| 329 | c = (int) ((c * scaleFactors[idx]) + 0.5f); | ||
| 330 | } | ||
| 331 | return c; | ||
| 332 | } | ||
| 333 | |||
| 334 | |||
| 335 | private int getsRGBComponentFromLinearRGB(int pixel, int idx) { | ||
| 336 | int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]); | ||
| 337 | if (isAlphaPremultiplied) { | ||
| 338 | float factor = (float) ((1 << lRGBprecision) - 1); | ||
| 339 | int a = ((pixel & maskArray[3]) >>> maskOffsets[3]); | ||
| 340 | c = (a == 0) ? 0 : | ||
| 341 | (int) (((c * scaleFactors[idx]) * factor / | ||
| 342 | (a * scaleFactors[3])) + 0.5f); | ||
| 343 | } else if (nBits[idx] != lRGBprecision) { | ||
| 344 | if (lRGBprecision == 16) { | ||
| 345 | c = (int) ((c * scaleFactors[idx] * 257.0f) + 0.5f); | ||
| 346 | } else { | ||
| 347 | c = (int) ((c * scaleFactors[idx]) + 0.5f); | ||
| 348 | } | ||
| 349 | } | ||
| 350 | // now range of c is 0-255 or 0-65535, depending on lRGBprecision | ||
| 351 | return tosRGB8LUT[c] & 0xff; | ||
| 352 | } | ||
| 353 | |||
| 354 | |||
| 355 | /** | ||
| 356 | * Returns the red color component for the specified pixel, scaled | ||
| 357 | * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A | ||
| 358 | * color conversion is done if necessary. The pixel value is specified | ||
| 359 | * as an <code>int</code>. | ||
| 360 | * The returned value is a non pre-multiplied value. Thus, if the | ||
| 361 | * alpha is premultiplied, this method divides it out before returning | ||
| 362 | * the value. If the alpha value is 0, for example, the red value | ||
| 363 | * is 0. | ||
| 364 | * @param pixel the specified pixel | ||
| 365 | * @return the red color component for the specified pixel, from | ||
| 366 | * 0 to 255 in the sRGB <code>ColorSpace</code>. | ||
| 367 | */ | ||
| 368 | final public int getRed(int pixel) { | ||
| 369 | if (is_sRGB) { | ||
| 370 | return getsRGBComponentFromsRGB(pixel, 0); | ||
| 371 | } else if (is_LinearRGB) { | ||
| 372 | return getsRGBComponentFromLinearRGB(pixel, 0); | ||
| 373 | } | ||
| 374 | float rgb[] = getDefaultRGBComponents(pixel); | ||
| 375 | return (int) (rgb[0] * 255.0f + 0.5f); | ||
| 376 | } | ||
| 377 | |||
| 378 | /** | ||
| 379 | * Returns the green color component for the specified pixel, scaled | ||
| 380 | * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A | ||
| 381 | * color conversion is done if necessary. The pixel value is specified | ||
| 382 | * as an <code>int</code>. | ||
| 383 | * The returned value is a non pre-multiplied value. Thus, if the | ||
| 384 | * alpha is premultiplied, this method divides it out before returning | ||
| 385 | * the value. If the alpha value is 0, for example, the green value | ||
| 386 | * is 0. | ||
| 387 | * @param pixel the specified pixel | ||
| 388 | * @return the green color component for the specified pixel, from | ||
| 389 | * 0 to 255 in the sRGB <code>ColorSpace</code>. | ||
| 390 | */ | ||
| 391 | final public int getGreen(int pixel) { | ||
| 392 | if (is_sRGB) { | ||
| 393 | return getsRGBComponentFromsRGB(pixel, 1); | ||
| 394 | } else if (is_LinearRGB) { | ||
| 395 | return getsRGBComponentFromLinearRGB(pixel, 1); | ||
| 396 | } | ||
| 397 | float rgb[] = getDefaultRGBComponents(pixel); | ||
| 398 | return (int) (rgb[1] * 255.0f + 0.5f); | ||
| 399 | } | ||
| 400 | |||
| 401 | /** | ||
| 402 | * Returns the blue color component for the specified pixel, scaled | ||
| 403 | * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A | ||
| 404 | * color conversion is done if necessary. The pixel value is specified | ||
| 405 | * as an <code>int</code>. | ||
| 406 | * The returned value is a non pre-multiplied value. Thus, if the | ||
| 407 | * alpha is premultiplied, this method divides it out before returning | ||
| 408 | * the value. If the alpha value is 0, for example, the blue value | ||
| 409 | * is 0. | ||
| 410 | * @param pixel the specified pixel | ||
| 411 | * @return the blue color component for the specified pixel, from | ||
| 412 | * 0 to 255 in the sRGB <code>ColorSpace</code>. | ||
| 413 | */ | ||
| 414 | final public int getBlue(int pixel) { | ||
| 415 | if (is_sRGB) { | ||
| 416 | return getsRGBComponentFromsRGB(pixel, 2); | ||
| 417 | } else if (is_LinearRGB) { | ||
| 418 | return getsRGBComponentFromLinearRGB(pixel, 2); | ||
| 419 | } | ||
| 420 | float rgb[] = getDefaultRGBComponents(pixel); | ||
| 421 | return (int) (rgb[2] * 255.0f + 0.5f); | ||
| 422 | } | ||
| 423 | |||
| 424 | /** | ||
| 425 | * Returns the alpha component for the specified pixel, scaled | ||
| 426 | * from 0 to 255. The pixel value is specified as an <code>int</code>. | ||
| 427 | * @param pixel the specified pixel | ||
| 428 | * @return the value of the alpha component of <code>pixel</code> | ||
| 429 | * from 0 to 255. | ||
| 430 | */ | ||
| 431 | final public int getAlpha(int pixel) { | ||
| 432 | if (!supportsAlpha) return 255; | ||
| 433 | int a = ((pixel & maskArray[3]) >>> maskOffsets[3]); | ||
| 434 | if (scaleFactors[3] != 1.0f) { | ||
| 435 | a = (int)(a * scaleFactors[3] + 0.5f); | ||
| 436 | } | ||
| 437 | return a; | ||
| 438 | } | ||
| 439 | |||
| 440 | /** | ||
| 441 | * Returns the color/alpha components of the pixel in the default | ||
| 442 | * RGB color model format. A color conversion is done if necessary. | ||
| 443 | * The pixel value is specified as an <code>int</code>. | ||
| 444 | * The returned value is in a non pre-multiplied format. Thus, if | ||
| 445 | * the alpha is premultiplied, this method divides it out of the | ||
| 446 | * color components. If the alpha value is 0, for example, the color | ||
| 447 | * values are each 0. | ||
| 448 | * @param pixel the specified pixel | ||
| 449 | * @return the RGB value of the color/alpha components of the specified | ||
| 450 | * pixel. | ||
| 451 | * @see ColorModel#getRGBdefault | ||
| 452 | */ | ||
| 453 | final public int getRGB(int pixel) { | ||
| 454 | if (is_sRGB || is_LinearRGB) { | ||
| 455 | return (getAlpha(pixel) << 24) | ||
| 456 | | (getRed(pixel) << 16) | ||
| 457 | | (getGreen(pixel) << 8) | ||
| 458 | | (getBlue(pixel) << 0); | ||
| 459 | } | ||
| 460 | float rgb[] = getDefaultRGBComponents(pixel); | ||
| 461 | return (getAlpha(pixel) << 24) | ||
| 462 | | (((int) (rgb[0] * 255.0f + 0.5f)) << 16) | ||
| 463 | | (((int) (rgb[1] * 255.0f + 0.5f)) << 8) | ||
| 464 | | (((int) (rgb[2] * 255.0f + 0.5f)) << 0); | ||
| 465 | } | ||
| 466 | |||
| 467 | /** | ||
| 468 | * Returns the red color component for the specified pixel, scaled | ||
| 469 | * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A | ||
| 470 | * color conversion is done if necessary. The pixel value is specified | ||
| 471 | * by an array of data elements of type <code>transferType</code> passed | ||
| 472 | * in as an object reference. | ||
| 473 | * The returned value is a non pre-multiplied value. Thus, if the | ||
| 474 | * alpha is premultiplied, this method divides it out before returning | ||
| 475 | * the value. If the alpha value is 0, for example, the red value | ||
| 476 | * is 0. | ||
| 477 | * If <code>inData</code> is not a primitive array of type | ||
| 478 | * <code>transferType</code>, a <code>ClassCastException</code> is | ||
| 479 | * thrown. An <code>ArrayIndexOutOfBoundsException</code> is | ||
| 480 | * thrown if <code>inData</code> is not large enough to hold a | ||
| 481 | * pixel value for this <code>ColorModel</code>. Since | ||
| 482 | * <code>DirectColorModel</code> can be subclassed, subclasses inherit | ||
| 483 | * the implementation of this method and if they don't override it | ||
| 484 | * then they throw an exception if they use an unsupported | ||
| 485 | * <code>transferType</code>. | ||
| 486 | * An <code>UnsupportedOperationException</code> is thrown if this | ||
| 487 | * <code>transferType</code> is not supported by this | ||
| 488 | * <code>ColorModel</code>. | ||
| 489 | * @param inData the array containing the pixel value | ||
| 490 | * @return the value of the red component of the specified pixel. | ||
| 491 | * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not | ||
| 492 | * large enough to hold a pixel value for this color model | ||
| 493 | * @throws ClassCastException if <code>inData</code> is not a | ||
| 494 | * primitive array of type <code>transferType</code> | ||
| 495 | * @throws UnsupportedOperationException if this <code>transferType</code> | ||
| 496 | * is not supported by this color model | ||
| 497 | */ | ||
| 498 | public int getRed(Object inData) { | ||
| 499 | int pixel=0; | ||
| 500 | switch (transferType) { | ||
| 501 | case DataBuffer.TYPE_BYTE: | ||
| 502 | byte bdata[] = (byte[])inData; | ||
| 503 | pixel = bdata[0] & 0xff; | ||
| 504 | break; | ||
| 505 | case DataBuffer.TYPE_USHORT: | ||
| 506 | short sdata[] = (short[])inData; | ||
| 507 | pixel = sdata[0] & 0xffff; | ||
| 508 | break; | ||
| 509 | case DataBuffer.TYPE_INT: | ||
| 510 | int idata[] = (int[])inData; | ||
| 511 | pixel = idata[0]; | ||
| 512 | break; | ||
| 513 | default: | ||
| 514 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 515 | "implemented for transferType " + transferType); | ||
| 516 | } | ||
| 517 | return getRed(pixel); | ||
| 518 | } | ||
| 519 | |||
| 520 | |||
| 521 | /** | ||
| 522 | * Returns the green color component for the specified pixel, scaled | ||
| 523 | * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A | ||
| 524 | * color conversion is done if necessary. The pixel value is specified | ||
| 525 | * by an array of data elements of type <code>transferType</code> passed | ||
| 526 | * in as an object reference. | ||
| 527 | * The returned value is a non pre-multiplied value. Thus, if the | ||
| 528 | * alpha is premultiplied, this method divides it out before returning | ||
| 529 | * the value. If the alpha value is 0, for example, the green value | ||
| 530 | * is 0. If <code>inData</code> is not a primitive array of type | ||
| 531 | * <code>transferType</code>, a <code>ClassCastException</code> is thrown. | ||
| 532 | * An <code>ArrayIndexOutOfBoundsException</code> is | ||
| 533 | * thrown if <code>inData</code> is not large enough to hold a pixel | ||
| 534 | * value for this <code>ColorModel</code>. Since | ||
| 535 | * <code>DirectColorModel</code> can be subclassed, subclasses inherit | ||
| 536 | * the implementation of this method and if they don't override it | ||
| 537 | * then they throw an exception if they use an unsupported | ||
| 538 | * <code>transferType</code>. | ||
| 539 | * An <code>UnsupportedOperationException</code> is | ||
| 540 | * thrown if this <code>transferType</code> is not supported by this | ||
| 541 | * <code>ColorModel</code>. | ||
| 542 | * @param inData the array containing the pixel value | ||
| 543 | * @return the value of the green component of the specified pixel. | ||
| 544 | * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not | ||
| 545 | * large enough to hold a pixel value for this color model | ||
| 546 | * @throws ClassCastException if <code>inData</code> is not a | ||
| 547 | * primitive array of type <code>transferType</code> | ||
| 548 | * @throws UnsupportedOperationException if this <code>transferType</code> | ||
| 549 | * is not supported by this color model | ||
| 550 | */ | ||
| 551 | public int getGreen(Object inData) { | ||
| 552 | int pixel=0; | ||
| 553 | switch (transferType) { | ||
| 554 | case DataBuffer.TYPE_BYTE: | ||
| 555 | byte bdata[] = (byte[])inData; | ||
| 556 | pixel = bdata[0] & 0xff; | ||
| 557 | break; | ||
| 558 | case DataBuffer.TYPE_USHORT: | ||
| 559 | short sdata[] = (short[])inData; | ||
| 560 | pixel = sdata[0] & 0xffff; | ||
| 561 | break; | ||
| 562 | case DataBuffer.TYPE_INT: | ||
| 563 | int idata[] = (int[])inData; | ||
| 564 | pixel = idata[0]; | ||
| 565 | break; | ||
| 566 | default: | ||
| 567 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 568 | "implemented for transferType " + transferType); | ||
| 569 | } | ||
| 570 | return getGreen(pixel); | ||
| 571 | } | ||
| 572 | |||
| 573 | |||
| 574 | /** | ||
| 575 | * Returns the blue color component for the specified pixel, scaled | ||
| 576 | * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A | ||
| 577 | * color conversion is done if necessary. The pixel value is specified | ||
| 578 | * by an array of data elements of type <code>transferType</code> passed | ||
| 579 | * in as an object reference. | ||
| 580 | * The returned value is a non pre-multiplied value. Thus, if the | ||
| 581 | * alpha is premultiplied, this method divides it out before returning | ||
| 582 | * the value. If the alpha value is 0, for example, the blue value | ||
| 583 | * is 0. If <code>inData</code> is not a primitive array of type | ||
| 584 | * <code>transferType</code>, a <code>ClassCastException</code> is thrown. | ||
| 585 | * An <code>ArrayIndexOutOfBoundsException</code> is | ||
| 586 | * thrown if <code>inData</code> is not large enough to hold a pixel | ||
| 587 | * value for this <code>ColorModel</code>. Since | ||
| 588 | * <code>DirectColorModel</code> can be subclassed, subclasses inherit | ||
| 589 | * the implementation of this method and if they don't override it | ||
| 590 | * then they throw an exception if they use an unsupported | ||
| 591 | * <code>transferType</code>. | ||
| 592 | * An <code>UnsupportedOperationException</code> is | ||
| 593 | * thrown if this <code>transferType</code> is not supported by this | ||
| 594 | * <code>ColorModel</code>. | ||
| 595 | * @param inData the array containing the pixel value | ||
| 596 | * @return the value of the blue component of the specified pixel. | ||
| 597 | * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not | ||
| 598 | * large enough to hold a pixel value for this color model | ||
| 599 | * @throws ClassCastException if <code>inData</code> is not a | ||
| 600 | * primitive array of type <code>transferType</code> | ||
| 601 | * @throws UnsupportedOperationException if this <code>transferType</code> | ||
| 602 | * is not supported by this color model | ||
| 603 | */ | ||
| 604 | public int getBlue(Object inData) { | ||
| 605 | int pixel=0; | ||
| 606 | switch (transferType) { | ||
| 607 | case DataBuffer.TYPE_BYTE: | ||
| 608 | byte bdata[] = (byte[])inData; | ||
| 609 | pixel = bdata[0] & 0xff; | ||
| 610 | break; | ||
| 611 | case DataBuffer.TYPE_USHORT: | ||
| 612 | short sdata[] = (short[])inData; | ||
| 613 | pixel = sdata[0] & 0xffff; | ||
| 614 | break; | ||
| 615 | case DataBuffer.TYPE_INT: | ||
| 616 | int idata[] = (int[])inData; | ||
| 617 | pixel = idata[0]; | ||
| 618 | break; | ||
| 619 | default: | ||
| 620 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 621 | "implemented for transferType " + transferType); | ||
| 622 | } | ||
| 623 | return getBlue(pixel); | ||
| 624 | } | ||
| 625 | |||
| 626 | /** | ||
| 627 | * Returns the alpha component for the specified pixel, scaled | ||
| 628 | * from 0 to 255. The pixel value is specified by an array of data | ||
| 629 | * elements of type <code>transferType</code> passed in as an object | ||
| 630 | * reference. | ||
| 631 | * If <code>inData</code> is not a primitive array of type | ||
| 632 | * <code>transferType</code>, a <code>ClassCastException</code> is | ||
| 633 | * thrown. An <code>ArrayIndexOutOfBoundsException</code> is | ||
| 634 | * thrown if <code>inData</code> is not large enough to hold a pixel | ||
| 635 | * value for this <code>ColorModel</code>. Since | ||
| 636 | * <code>DirectColorModel</code> can be subclassed, subclasses inherit | ||
| 637 | * the implementation of this method and if they don't override it | ||
| 638 | * then they throw an exception if they use an unsupported | ||
| 639 | * <code>transferType</code>. | ||
| 640 | * If this <code>transferType</code> is not supported, an | ||
| 641 | * <code>UnsupportedOperationException</code> is thrown. | ||
| 642 | * @param inData the specified pixel | ||
| 643 | * @return the alpha component of the specified pixel, scaled from | ||
| 644 | * 0 to 255. | ||
| 645 | * @exception <code>ClassCastException</code> if <code>inData</code> | ||
| 646 | * is not a primitive array of type <code>transferType</code> | ||
| 647 | * @exception <code>ArrayIndexOutOfBoundsException</code> if | ||
| 648 | * <code>inData</code> is not large enough to hold a pixel value | ||
| 649 | * for this <code>ColorModel</code> | ||
| 650 | * @exception <code>UnsupportedOperationException</code> if this | ||
| 651 | * <code>tranferType</code> is not supported by this | ||
| 652 | * <code>ColorModel</code> | ||
| 653 | */ | ||
| 654 | public int getAlpha(Object inData) { | ||
| 655 | int pixel=0; | ||
| 656 | switch (transferType) { | ||
| 657 | case DataBuffer.TYPE_BYTE: | ||
| 658 | byte bdata[] = (byte[])inData; | ||
| 659 | pixel = bdata[0] & 0xff; | ||
| 660 | break; | ||
| 661 | case DataBuffer.TYPE_USHORT: | ||
| 662 | short sdata[] = (short[])inData; | ||
| 663 | pixel = sdata[0] & 0xffff; | ||
| 664 | break; | ||
| 665 | case DataBuffer.TYPE_INT: | ||
| 666 | int idata[] = (int[])inData; | ||
| 667 | pixel = idata[0]; | ||
| 668 | break; | ||
| 669 | default: | ||
| 670 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 671 | "implemented for transferType " + transferType); | ||
| 672 | } | ||
| 673 | return getAlpha(pixel); | ||
| 674 | } | ||
| 675 | |||
| 676 | /** | ||
| 677 | * Returns the color/alpha components for the specified pixel in the | ||
| 678 | * default RGB color model format. A color conversion is done if | ||
| 679 | * necessary. The pixel value is specified by an array of data | ||
| 680 | * elements of type <code>transferType</code> passed in as an object | ||
| 681 | * reference. If <code>inData</code> is not a primitive array of type | ||
| 682 | * <code>transferType</code>, a <code>ClassCastException</code> is | ||
| 683 | * thrown. An <code>ArrayIndexOutOfBoundsException</code> is | ||
| 684 | * thrown if <code>inData</code> is not large enough to hold a pixel | ||
| 685 | * value for this <code>ColorModel</code>. | ||
| 686 | * The returned value is in a non pre-multiplied format. Thus, if | ||
| 687 | * the alpha is premultiplied, this method divides it out of the | ||
| 688 | * color components. If the alpha value is 0, for example, the color | ||
| 689 | * values is 0. Since <code>DirectColorModel</code> can be | ||
| 690 | * subclassed, subclasses inherit the implementation of this method | ||
| 691 | * and if they don't override it then | ||
| 692 | * they throw an exception if they use an unsupported | ||
| 693 | * <code>transferType</code>. | ||
| 694 | * | ||
| 695 | * @param inData the specified pixel | ||
| 696 | * @return the color and alpha components of the specified pixel. | ||
| 697 | * @exception UnsupportedOperationException if this | ||
| 698 | * <code>transferType</code> is not supported by this | ||
| 699 | * <code>ColorModel</code> | ||
| 700 | * @see ColorModel#getRGBdefault | ||
| 701 | */ | ||
| 702 | public int getRGB(Object inData) { | ||
| 703 | int pixel=0; | ||
| 704 | switch (transferType) { | ||
| 705 | case DataBuffer.TYPE_BYTE: | ||
| 706 | byte bdata[] = (byte[])inData; | ||
| 707 | pixel = bdata[0] & 0xff; | ||
| 708 | break; | ||
| 709 | case DataBuffer.TYPE_USHORT: | ||
| 710 | short sdata[] = (short[])inData; | ||
| 711 | pixel = sdata[0] & 0xffff; | ||
| 712 | break; | ||
| 713 | case DataBuffer.TYPE_INT: | ||
| 714 | int idata[] = (int[])inData; | ||
| 715 | pixel = idata[0]; | ||
| 716 | break; | ||
| 717 | default: | ||
| 718 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 719 | "implemented for transferType " + transferType); | ||
| 720 | } | ||
| 721 | return getRGB(pixel); | ||
| 722 | } | ||
| 723 | |||
| 724 | /** | ||
| 725 | * Returns a data element array representation of a pixel in this | ||
| 726 | * <code>ColorModel</code>, given an integer pixel representation in the | ||
| 727 | * default RGB color model. | ||
| 728 | * This array can then be passed to the <code>setDataElements</code> | ||
| 729 | * method of a <code>WritableRaster</code> object. If the pixel variable | ||
| 730 | * is <code>null</code>, a new array is allocated. If <code>pixel</code> | ||
| 731 | * is not <code>null</code>, it must be a primitive array of type | ||
| 732 | * <code>transferType</code>; otherwise, a | ||
| 733 | * <code>ClassCastException</code> is thrown. An | ||
| 734 | * <code>ArrayIndexOutOfBoundsException</code> is | ||
| 735 | * thrown if <code>pixel</code> is not large enough to hold a pixel | ||
| 736 | * value for this <code>ColorModel</code>. The pixel array is returned. | ||
| 737 | * Since <code>DirectColorModel</code> can be subclassed, subclasses | ||
| 738 | * inherit the implementation of this method and if they don't | ||
| 739 | * override it then they throw an exception if they use an unsupported | ||
| 740 | * <code>transferType</code>. | ||
| 741 | * | ||
| 742 | * @param rgb the integer pixel representation in the default RGB | ||
| 743 | * color model | ||
| 744 | * @param pixel the specified pixel | ||
| 745 | * @return an array representation of the specified pixel in this | ||
| 746 | * <code>ColorModel</code> | ||
| 747 | * @exception ClassCastException if <code>pixel</code> | ||
| 748 | * is not a primitive array of type <code>transferType</code> | ||
| 749 | * @exception ArrayIndexOutOfBoundsException if | ||
| 750 | * <code>pixel</code> is not large enough to hold a pixel value | ||
| 751 | * for this <code>ColorModel</code> | ||
| 752 | * @exception UnsupportedOperationException if this | ||
| 753 | * <code>transferType</code> is not supported by this | ||
| 754 | * <code>ColorModel</code> | ||
| 755 | * @see WritableRaster#setDataElements | ||
| 756 | * @see SampleModel#setDataElements | ||
| 757 | */ | ||
| 758 | public Object getDataElements(int rgb, Object pixel) { | ||
| 759 | //REMIND: maybe more efficient not to use int array for | ||
| 760 | //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT | ||
| 761 | int intpixel[] = null; | ||
| 762 | if (transferType == DataBuffer.TYPE_INT && | ||
| 763 | pixel != null) { | ||
| 764 | intpixel = (int[])pixel; | ||
| 765 | intpixel[0] = 0; | ||
| 766 | } else { | ||
| 767 | intpixel = new int[1]; | ||
| 768 | } | ||
| 769 | |||
| 770 | ColorModel defaultCM = ColorModel.getRGBdefault(); | ||
| 771 | if (this == defaultCM || equals(defaultCM)) { | ||
| 772 | intpixel[0] = rgb; | ||
| 773 | return intpixel; | ||
| 774 | } | ||
| 775 | |||
| 776 | int red, grn, blu, alp; | ||
| 777 | red = (rgb>>16) & 0xff; | ||
| 778 | grn = (rgb>>8) & 0xff; | ||
| 779 | blu = rgb & 0xff; | ||
| 780 | if (is_sRGB || is_LinearRGB) { | ||
| 781 | int precision; | ||
| 782 | float factor; | ||
| 783 | if (is_LinearRGB) { | ||
| 784 | if (lRGBprecision == 8) { | ||
| 785 | red = fromsRGB8LUT8[red] & 0xff; | ||
| 786 | grn = fromsRGB8LUT8[grn] & 0xff; | ||
| 787 | blu = fromsRGB8LUT8[blu] & 0xff; | ||
| 788 | precision = 8; | ||
| 789 | factor = 1.0f / 255.0f; | ||
| 790 | } else { | ||
| 791 | red = fromsRGB8LUT16[red] & 0xffff; | ||
| 792 | grn = fromsRGB8LUT16[grn] & 0xffff; | ||
| 793 | blu = fromsRGB8LUT16[blu] & 0xffff; | ||
| 794 | precision = 16; | ||
| 795 | factor = 1.0f / 65535.0f; | ||
| 796 | } | ||
| 797 | } else { | ||
| 798 | precision = 8; | ||
| 799 | factor = 1.0f / 255.0f; | ||
| 800 | } | ||
| 801 | if (supportsAlpha) { | ||
| 802 | alp = (rgb>>24) & 0xff; | ||
| 803 | if (isAlphaPremultiplied) { | ||
| 804 | factor *= (alp * (1.0f / 255.0f)); | ||
| 805 | precision = -1; // force component calculations below | ||
| 806 | } | ||
| 807 | if (nBits[3] != 8) { | ||
| 808 | alp = (int) | ||
| 809 | ((alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1)) + 0.5f); | ||
| 810 | if (alp > ((1<<nBits[3]) - 1)) { | ||
| 811 | // fix 4412670 - see comment below | ||
| 812 | alp = (1<<nBits[3]) - 1; | ||
| 813 | } | ||
| 814 | } | ||
| 815 | intpixel[0] = alp << maskOffsets[3]; | ||
| 816 | } | ||
| 817 | if (nBits[0] != precision) { | ||
| 818 | red = (int) ((red * factor * ((1<<nBits[0]) - 1)) + 0.5f); | ||
| 819 | } | ||
| 820 | if (nBits[1] != precision) { | ||
| 821 | grn = (int) ((grn * factor * ((1<<nBits[1]) - 1)) + 0.5f); | ||
| 822 | } | ||
| 823 | if (nBits[2] != precision) { | ||
| 824 | blu = (int) ((blu * factor * ((1<<nBits[2]) - 1)) + 0.5f); | ||
| 825 | } | ||
| 826 | } else { | ||
| 827 | // Need to convert the color | ||
| 828 | float[] norm = new float[3]; | ||
| 829 | float factor = 1.0f / 255.0f; | ||
| 830 | norm[0] = red * factor; | ||
| 831 | norm[1] = grn * factor; | ||
| 832 | norm[2] = blu * factor; | ||
| 833 | norm = colorSpace.fromRGB(norm); | ||
| 834 | if (supportsAlpha) { | ||
| 835 | alp = (rgb>>24) & 0xff; | ||
| 836 | if (isAlphaPremultiplied) { | ||
| 837 | factor *= alp; | ||
| 838 | for (int i = 0; i < 3; i++) { | ||
| 839 | norm[i] *= factor; | ||
| 840 | } | ||
| 841 | } | ||
| 842 | if (nBits[3] != 8) { | ||
| 843 | alp = (int) | ||
| 844 | ((alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1)) + 0.5f); | ||
| 845 | if (alp > ((1<<nBits[3]) - 1)) { | ||
| 846 | // fix 4412670 - see comment below | ||
| 847 | alp = (1<<nBits[3]) - 1; | ||
| 848 | } | ||
| 849 | } | ||
| 850 | intpixel[0] = alp << maskOffsets[3]; | ||
| 851 | } | ||
| 852 | red = (int) ((norm[0] * ((1<<nBits[0]) - 1)) + 0.5f); | ||
| 853 | grn = (int) ((norm[1] * ((1<<nBits[1]) - 1)) + 0.5f); | ||
| 854 | blu = (int) ((norm[2] * ((1<<nBits[2]) - 1)) + 0.5f); | ||
| 855 | } | ||
| 856 | |||
| 857 | if (maxBits > 23) { | ||
| 858 | // fix 4412670 - for components of 24 or more bits | ||
| 859 | // some calculations done above with float precision | ||
| 860 | // may lose enough precision that the integer result | ||
| 861 | // overflows nBits, so we need to clamp. | ||
| 862 | if (red > ((1<<nBits[0]) - 1)) { | ||
| 863 | red = (1<<nBits[0]) - 1; | ||
| 864 | } | ||
| 865 | if (grn > ((1<<nBits[1]) - 1)) { | ||
| 866 | grn = (1<<nBits[1]) - 1; | ||
| 867 | } | ||
| 868 | if (blu > ((1<<nBits[2]) - 1)) { | ||
| 869 | blu = (1<<nBits[2]) - 1; | ||
| 870 | } | ||
| 871 | } | ||
| 872 | |||
| 873 | intpixel[0] |= (red << maskOffsets[0]) | | ||
| 874 | (grn << maskOffsets[1]) | | ||
| 875 | (blu << maskOffsets[2]); | ||
| 876 | |||
| 877 | switch (transferType) { | ||
| 878 | case DataBuffer.TYPE_BYTE: { | ||
| 879 | byte bdata[]; | ||
| 880 | if (pixel == null) { | ||
| 881 | bdata = new byte[1]; | ||
| 882 | } else { | ||
| 883 | bdata = (byte[])pixel; | ||
| 884 | } | ||
| 885 | bdata[0] = (byte)(0xff&intpixel[0]); | ||
| 886 | return bdata; | ||
| 887 | } | ||
| 888 | case DataBuffer.TYPE_USHORT:{ | ||
| 889 | short sdata[]; | ||
| 890 | if (pixel == null) { | ||
| 891 | sdata = new short[1]; | ||
| 892 | } else { | ||
| 893 | sdata = (short[])pixel; | ||
| 894 | } | ||
| 895 | sdata[0] = (short)(intpixel[0]&0xffff); | ||
| 896 | return sdata; | ||
| 897 | } | ||
| 898 | case DataBuffer.TYPE_INT: | ||
| 899 | return intpixel; | ||
| 900 | } | ||
| 901 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 902 | "implemented for transferType " + transferType); | ||
| 903 | |||
| 904 | } | ||
| 905 | |||
| 906 | /** | ||
| 907 | * Returns an array of unnormalized color/alpha components given a pixel | ||
| 908 | * in this <code>ColorModel</code>. The pixel value is specified as an | ||
| 909 | * <code>int</code>. If the <code>components</code> array is | ||
| 910 | * <code>null</code>, a new array is allocated. The | ||
| 911 | * <code>components</code> array is returned. Color/alpha components are | ||
| 912 | * stored in the <code>components</code> array starting at | ||
| 913 | * <code>offset</code>, even if the array is allocated by this method. | ||
| 914 | * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the | ||
| 915 | * <code>components</code> array is not <code>null</code> and is not large | ||
| 916 | * enough to hold all the color and alpha components, starting at | ||
| 917 | * <code>offset</code>. | ||
| 918 | * @param pixel the specified pixel | ||
| 919 | * @param components the array to receive the color and alpha | ||
| 920 | * components of the specified pixel | ||
| 921 | * @param offset the offset into the <code>components</code> array at | ||
| 922 | * which to start storing the color and alpha components | ||
| 923 | * @return an array containing the color and alpha components of the | ||
| 924 | * specified pixel starting at the specified offset. | ||
| 925 | */ | ||
| 926 | final public int[] getComponents(int pixel, int[] components, int offset) { | ||
| 927 | if (components == null) { | ||
| 928 | components = new int[offset+numComponents]; | ||
| 929 | } | ||
| 930 | |||
| 931 | for (int i=0; i < numComponents; i++) { | ||
| 932 | components[offset+i] = (pixel & maskArray[i]) >>> maskOffsets[i]; | ||
| 933 | } | ||
| 934 | |||
| 935 | return components; | ||
| 936 | } | ||
| 937 | |||
| 938 | /** | ||
| 939 | * Returns an array of unnormalized color/alpha components given a pixel | ||
| 940 | * in this <code>ColorModel</code>. The pixel value is specified by an | ||
| 941 | * array of data elements of type <code>transferType</code> passed in as | ||
| 942 | * an object reference. If <code>pixel</code> is not a primitive array | ||
| 943 | * of type <code>transferType</code>, a <code>ClassCastException</code> | ||
| 944 | * is thrown. An <code>ArrayIndexOutOfBoundsException</code> is | ||
| 945 | * thrown if <code>pixel</code> is not large enough to hold a | ||
| 946 | * pixel value for this <code>ColorModel</code>. If the | ||
| 947 | * <code>components</code> array is <code>null</code>, a new | ||
| 948 | * array is allocated. The <code>components</code> array is returned. | ||
| 949 | * Color/alpha components are stored in the <code>components</code> array | ||
| 950 | * starting at <code>offset</code>, even if the array is allocated by | ||
| 951 | * this method. An <code>ArrayIndexOutOfBoundsException</code> | ||
| 952 | * is thrown if the <code>components</code> array is not | ||
| 953 | * <code>null</code> and is not large enough to hold all the color and | ||
| 954 | * alpha components, starting at <code>offset</code>. | ||
| 955 | * Since <code>DirectColorModel</code> can be subclassed, subclasses | ||
| 956 | * inherit the implementation of this method and if they don't | ||
| 957 | * override it then they throw an exception if they use an unsupported | ||
| 958 | * <code>transferType</code>. | ||
| 959 | * @param pixel the specified pixel | ||
| 960 | * @param components the array to receive the color and alpha | ||
| 961 | * components of the specified pixel | ||
| 962 | * @param offset the offset into the <code>components</code> array at | ||
| 963 | * which to start storing the color and alpha components | ||
| 964 | * @return an array containing the color and alpha components of the | ||
| 965 | * specified pixel starting at the specified offset. | ||
| 966 | * @exception ClassCastException if <code>pixel</code> | ||
| 967 | * is not a primitive array of type <code>transferType</code> | ||
| 968 | * @exception ArrayIndexOutOfBoundsException if | ||
| 969 | * <code>pixel</code> is not large enough to hold a pixel value | ||
| 970 | * for this <code>ColorModel</code>, or if <code>components</code> | ||
| 971 | * is not <code>null</code> and is not large enough to hold all the | ||
| 972 | * color and alpha components, starting at <code>offset</code> | ||
| 973 | * @exception UnsupportedOperationException if this | ||
| 974 | * <code>transferType</code> is not supported by this | ||
| 975 | * color model | ||
| 976 | */ | ||
| 977 | final public int[] getComponents(Object pixel, int[] components, | ||
| 978 | int offset) { | ||
| 979 | int intpixel=0; | ||
| 980 | switch (transferType) { | ||
| 981 | case DataBuffer.TYPE_BYTE: | ||
| 982 | byte bdata[] = (byte[])pixel; | ||
| 983 | intpixel = bdata[0] & 0xff; | ||
| 984 | break; | ||
| 985 | case DataBuffer.TYPE_USHORT: | ||
| 986 | short sdata[] = (short[])pixel; | ||
| 987 | intpixel = sdata[0] & 0xffff; | ||
| 988 | break; | ||
| 989 | case DataBuffer.TYPE_INT: | ||
| 990 | int idata[] = (int[])pixel; | ||
| 991 | intpixel = idata[0]; | ||
| 992 | break; | ||
| 993 | default: | ||
| 994 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 995 | "implemented for transferType " + transferType); | ||
| 996 | } | ||
| 997 | return getComponents(intpixel, components, offset); | ||
| 998 | } | ||
| 999 | |||
| 1000 | /** | ||
| 1001 | * Creates a <code>WritableRaster</code> with the specified width and | ||
| 1002 | * height that has a data layout (<code>SampleModel</code>) compatible | ||
| 1003 | * with this <code>ColorModel</code>. | ||
| 1004 | * @param w the width to apply to the new <code>WritableRaster</code> | ||
| 1005 | * @param h the height to apply to the new <code>WritableRaster</code> | ||
| 1006 | * @return a <code>WritableRaster</code> object with the specified | ||
| 1007 | * width and height. | ||
| 1008 | * @throws IllegalArgumentException if <code>w</code> or <code>h</code> | ||
| 1009 | * is less than or equal to zero | ||
| 1010 | * @see WritableRaster | ||
| 1011 | * @see SampleModel | ||
| 1012 | */ | ||
| 1013 | final public WritableRaster createCompatibleWritableRaster (int w, | ||
| 1014 | int h) { | ||
| 1015 | if ((w <= 0) || (h <= 0)) { | ||
| 1016 | throw new IllegalArgumentException("Width (" + w + ") and height (" + h + | ||
| 1017 | ") cannot be <= 0"); | ||
| 1018 | } | ||
| 1019 | int[] bandmasks; | ||
| 1020 | if (supportsAlpha) { | ||
| 1021 | bandmasks = new int[4]; | ||
| 1022 | bandmasks[3] = alpha_mask; | ||
| 1023 | } | ||
| 1024 | else { | ||
| 1025 | bandmasks = new int[3]; | ||
| 1026 | } | ||
| 1027 | bandmasks[0] = red_mask; | ||
| 1028 | bandmasks[1] = green_mask; | ||
| 1029 | bandmasks[2] = blue_mask; | ||
| 1030 | |||
| 1031 | if (pixel_bits > 16) { | ||
| 1032 | return Raster.createPackedRaster(DataBuffer.TYPE_INT, | ||
| 1033 | w,h,bandmasks,null); | ||
| 1034 | } | ||
| 1035 | else if (pixel_bits > 8) { | ||
| 1036 | return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, | ||
| 1037 | w,h,bandmasks,null); | ||
| 1038 | } | ||
| 1039 | else { | ||
| 1040 | return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, | ||
| 1041 | w,h,bandmasks,null); | ||
| 1042 | } | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | /** | ||
| 1046 | * Returns a pixel value represented as an <code>int</code> in this | ||
| 1047 | * <code>ColorModel</code>, given an array of unnormalized color/alpha | ||
| 1048 | * components. An <code>ArrayIndexOutOfBoundsException</code> is | ||
| 1049 | * thrown if the <code>components</code> array is | ||
| 1050 | * not large enough to hold all the color and alpha components, starting | ||
| 1051 | * at <code>offset</code>. | ||
| 1052 | * @param components an array of unnormalized color and alpha | ||
| 1053 | * components | ||
| 1054 | * @param offset the index into <code>components</code> at which to | ||
| 1055 | * begin retrieving the color and alpha components | ||
| 1056 | * @return an <code>int</code> pixel value in this | ||
| 1057 | * <code>ColorModel</code> corresponding to the specified components. | ||
| 1058 | * @exception <code>ArrayIndexOutOfBoundsException</code> if | ||
| 1059 | * the <code>components</code> array is not large enough to | ||
| 1060 | * hold all of the color and alpha components starting at | ||
| 1061 | * <code>offset</code> | ||
| 1062 | */ | ||
| 1063 | public int getDataElement(int[] components, int offset) { | ||
| 1064 | int pixel = 0; | ||
| 1065 | for (int i=0; i < numComponents; i++) { | ||
| 1066 | pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]); | ||
| 1067 | } | ||
| 1068 | return pixel; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | /** | ||
| 1072 | * Returns a data element array representation of a pixel in this | ||
| 1073 | * <code>ColorModel</code>, given an array of unnormalized color/alpha | ||
| 1074 | * components. | ||
| 1075 | * This array can then be passed to the <code>setDataElements</code> | ||
| 1076 | * method of a <code>WritableRaster</code> object. | ||
| 1077 | * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the | ||
| 1078 | * <code>components</code> array | ||
| 1079 | * is not large enough to hold all the color and alpha components, | ||
| 1080 | * starting at offset. If the <code>obj</code> variable is | ||
| 1081 | * <code>null</code>, a new array is allocated. If <code>obj</code> is | ||
| 1082 | * not <code>null</code>, it must be a primitive array | ||
| 1083 | * of type <code>transferType</code>; otherwise, a | ||
| 1084 | * <code>ClassCastException</code> is thrown. | ||
| 1085 | * An <code>ArrayIndexOutOfBoundsException</code> is thrown if | ||
| 1086 | * <code>obj</code> is not large enough to hold a pixel value for this | ||
| 1087 | * <code>ColorModel</code>. | ||
| 1088 | * Since <code>DirectColorModel</code> can be subclassed, subclasses | ||
| 1089 | * inherit the implementation of this method and if they don't | ||
| 1090 | * override it then they throw an exception if they use an unsupported | ||
| 1091 | * <code>transferType</code>. | ||
| 1092 | * @param components an array of unnormalized color and alpha | ||
| 1093 | * components | ||
| 1094 | * @param offset the index into <code>components</code> at which to | ||
| 1095 | * begin retrieving color and alpha components | ||
| 1096 | * @param obj the <code>Object</code> representing an array of color | ||
| 1097 | * and alpha components | ||
| 1098 | * @return an <code>Object</code> representing an array of color and | ||
| 1099 | * alpha components. | ||
| 1100 | * @exception <code>ClassCastException</code> if <code>obj</code> | ||
| 1101 | * is not a primitive array of type <code>transferType</code> | ||
| 1102 | * @exception <code>ArrayIndexOutOfBoundsException</code> if | ||
| 1103 | * <code>obj</code> is not large enough to hold a pixel value | ||
| 1104 | * for this <code>ColorModel</code> or the <code>components</code> | ||
| 1105 | * array is not large enough to hold all of the color and alpha | ||
| 1106 | * components starting at <code>offset</code> | ||
| 1107 | * @exception UnsupportedOperationException if this | ||
| 1108 | * <code>transferType</code> is not supported by this | ||
| 1109 | * color model | ||
| 1110 | * @see WritableRaster#setDataElements | ||
| 1111 | * @see SampleModel#setDataElements | ||
| 1112 | */ | ||
| 1113 | public Object getDataElements(int[] components, int offset, Object obj) { | ||
| 1114 | int pixel = 0; | ||
| 1115 | for (int i=0; i < numComponents; i++) { | ||
| 1116 | pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]); | ||
| 1117 | } | ||
| 1118 | switch (transferType) { | ||
| 1119 | case DataBuffer.TYPE_BYTE: | ||
| 1120 | if (obj instanceof byte[]) { | ||
| 1121 | byte bdata[] = (byte[])obj; | ||
| 1122 | bdata[0] = (byte)(pixel&0xff); | ||
| 1123 | return bdata; | ||
| 1124 | } else { | ||
| 1125 | byte bdata[] = {(byte)(pixel&0xff)}; | ||
| 1126 | return bdata; | ||
| 1127 | } | ||
| 1128 | case DataBuffer.TYPE_USHORT: | ||
| 1129 | if (obj instanceof short[]) { | ||
| 1130 | short sdata[] = (short[])obj; | ||
| 1131 | sdata[0] = (short)(pixel&0xffff); | ||
| 1132 | return sdata; | ||
| 1133 | } else { | ||
| 1134 | short sdata[] = {(short)(pixel&0xffff)}; | ||
| 1135 | return sdata; | ||
| 1136 | } | ||
| 1137 | case DataBuffer.TYPE_INT: | ||
| 1138 | if (obj instanceof int[]) { | ||
| 1139 | int idata[] = (int[])obj; | ||
| 1140 | idata[0] = pixel; | ||
| 1141 | return idata; | ||
| 1142 | } else { | ||
| 1143 | int idata[] = {pixel}; | ||
| 1144 | return idata; | ||
| 1145 | } | ||
| 1146 | default: | ||
| 1147 | throw new ClassCastException("This method has not been "+ | ||
| 1148 | "implemented for transferType " + transferType); | ||
| 1149 | } | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | /** | ||
| 1153 | * Forces the raster data to match the state specified in the | ||
| 1154 | * <code>isAlphaPremultiplied</code> variable, assuming the data is | ||
| 1155 | * currently correctly described by this <code>ColorModel</code>. It | ||
| 1156 | * may multiply or divide the color raster data by alpha, or do | ||
| 1157 | * nothing if the data is in the correct state. If the data needs to | ||
| 1158 | * be coerced, this method will also return an instance of this | ||
| 1159 | * <code>ColorModel</code> with the <code>isAlphaPremultiplied</code> | ||
| 1160 | * flag set appropriately. This method will throw a | ||
| 1161 | * <code>UnsupportedOperationException</code> if this transferType is | ||
| 1162 | * not supported by this <code>ColorModel</code>. Since | ||
| 1163 | * <code>ColorModel</code> can be subclassed, subclasses inherit the | ||
| 1164 | * implementation of this method and if they don't override it then | ||
| 1165 | * they throw an exception if they use an unsupported transferType. | ||
| 1166 | * | ||
| 1167 | * @param raster the <code>WritableRaster</code> data | ||
| 1168 | * @param isAlphaPremultiplied <code>true</code> if the alpha is | ||
| 1169 | * premultiplied; <code>false</code> otherwise | ||
| 1170 | * @return a <code>ColorModel</code> object that represents the | ||
| 1171 | * coerced data. | ||
| 1172 | * @exception UnsupportedOperationException if this | ||
| 1173 | * <code>transferType</code> is not supported by this | ||
| 1174 | * color model | ||
| 1175 | */ | ||
| 1176 | final public ColorModel coerceData (WritableRaster raster, | ||
| 1177 | boolean isAlphaPremultiplied) | ||
| 1178 | { | ||
| 1179 | if (!supportsAlpha || | ||
| 1180 | this.isAlphaPremultiplied() == isAlphaPremultiplied) { | ||
| 1181 | return this; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | int w = raster.getWidth(); | ||
| 1185 | int h = raster.getHeight(); | ||
| 1186 | int aIdx = numColorComponents; | ||
| 1187 | float normAlpha; | ||
| 1188 | float alphaScale = 1.0f / ((float) ((1 << nBits[aIdx]) - 1)); | ||
| 1189 | |||
| 1190 | int rminX = raster.getMinX(); | ||
| 1191 | int rY = raster.getMinY(); | ||
| 1192 | int rX; | ||
| 1193 | int pixel[] = null; | ||
| 1194 | int zpixel[] = null; | ||
| 1195 | |||
| 1196 | if (isAlphaPremultiplied) { | ||
| 1197 | // Must mean that we are currently not premultiplied so | ||
| 1198 | // multiply by alpha | ||
| 1199 | switch (transferType) { | ||
| 1200 | case DataBuffer.TYPE_BYTE: { | ||
| 1201 | for (int y = 0; y < h; y++, rY++) { | ||
| 1202 | rX = rminX; | ||
| 1203 | for (int x = 0; x < w; x++, rX++) { | ||
| 1204 | pixel = raster.getPixel(rX, rY, pixel); | ||
| 1205 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 1206 | if (normAlpha != 0.f) { | ||
| 1207 | for (int c=0; c < aIdx; c++) { | ||
| 1208 | pixel[c] = (int) (pixel[c] * normAlpha + | ||
| 1209 | 0.5f); | ||
| 1210 | } | ||
| 1211 | raster.setPixel(rX, rY, pixel); | ||
| 1212 | } else { | ||
| 1213 | if (zpixel == null) { | ||
| 1214 | zpixel = new int[numComponents]; | ||
| 1215 | java.util.Arrays.fill(zpixel, 0); | ||
| 1216 | } | ||
| 1217 | raster.setPixel(rX, rY, zpixel); | ||
| 1218 | } | ||
| 1219 | } | ||
| 1220 | } | ||
| 1221 | } | ||
| 1222 | break; | ||
| 1223 | case DataBuffer.TYPE_USHORT: { | ||
| 1224 | for (int y = 0; y < h; y++, rY++) { | ||
| 1225 | rX = rminX; | ||
| 1226 | for (int x = 0; x < w; x++, rX++) { | ||
| 1227 | pixel = raster.getPixel(rX, rY, pixel); | ||
| 1228 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 1229 | if (normAlpha != 0.f) { | ||
| 1230 | for (int c=0; c < aIdx; c++) { | ||
| 1231 | pixel[c] = (int) (pixel[c] * normAlpha + | ||
| 1232 | 0.5f); | ||
| 1233 | } | ||
| 1234 | raster.setPixel(rX, rY, pixel); | ||
| 1235 | } else { | ||
| 1236 | if (zpixel == null) { | ||
| 1237 | zpixel = new int[numComponents]; | ||
| 1238 | java.util.Arrays.fill(zpixel, 0); | ||
| 1239 | } | ||
| 1240 | raster.setPixel(rX, rY, zpixel); | ||
| 1241 | } | ||
| 1242 | } | ||
| 1243 | } | ||
| 1244 | } | ||
| 1245 | break; | ||
| 1246 | case DataBuffer.TYPE_INT: { | ||
| 1247 | for (int y = 0; y < h; y++, rY++) { | ||
| 1248 | rX = rminX; | ||
| 1249 | for (int x = 0; x < w; x++, rX++) { | ||
| 1250 | pixel = raster.getPixel(rX, rY, pixel); | ||
| 1251 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 1252 | if (normAlpha != 0.f) { | ||
| 1253 | for (int c=0; c < aIdx; c++) { | ||
| 1254 | pixel[c] = (int) (pixel[c] * normAlpha + | ||
| 1255 | 0.5f); | ||
| 1256 | } | ||
| 1257 | raster.setPixel(rX, rY, pixel); | ||
| 1258 | } else { | ||
| 1259 | if (zpixel == null) { | ||
| 1260 | zpixel = new int[numComponents]; | ||
| 1261 | java.util.Arrays.fill(zpixel, 0); | ||
| 1262 | } | ||
| 1263 | raster.setPixel(rX, rY, zpixel); | ||
| 1264 | } | ||
| 1265 | } | ||
| 1266 | } | ||
| 1267 | } | ||
| 1268 | break; | ||
| 1269 | default: | ||
| 1270 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 1271 | "implemented for transferType " + transferType); | ||
| 1272 | } | ||
| 1273 | } | ||
| 1274 | else { | ||
| 1275 | // We are premultiplied and want to divide it out | ||
| 1276 | switch (transferType) { | ||
| 1277 | case DataBuffer.TYPE_BYTE: { | ||
| 1278 | for (int y = 0; y < h; y++, rY++) { | ||
| 1279 | rX = rminX; | ||
| 1280 | for (int x = 0; x < w; x++, rX++) { | ||
| 1281 | pixel = raster.getPixel(rX, rY, pixel); | ||
| 1282 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 1283 | if (normAlpha != 0.0f) { | ||
| 1284 | float invAlpha = 1.0f / normAlpha; | ||
| 1285 | for (int c=0; c < aIdx; c++) { | ||
| 1286 | pixel[c] = (int) (pixel[c] * invAlpha + | ||
| 1287 | 0.5f); | ||
| 1288 | } | ||
| 1289 | raster.setPixel(rX, rY, pixel); | ||
| 1290 | } | ||
| 1291 | } | ||
| 1292 | } | ||
| 1293 | } | ||
| 1294 | break; | ||
| 1295 | case DataBuffer.TYPE_USHORT: { | ||
| 1296 | for (int y = 0; y < h; y++, rY++) { | ||
| 1297 | rX = rminX; | ||
| 1298 | for (int x = 0; x < w; x++, rX++) { | ||
| 1299 | pixel = raster.getPixel(rX, rY, pixel); | ||
| 1300 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 1301 | if (normAlpha != 0) { | ||
| 1302 | float invAlpha = 1.0f / normAlpha; | ||
| 1303 | for (int c=0; c < aIdx; c++) { | ||
| 1304 | pixel[c] = (int) (pixel[c] * invAlpha + | ||
| 1305 | 0.5f); | ||
| 1306 | } | ||
| 1307 | raster.setPixel(rX, rY, pixel); | ||
| 1308 | } | ||
| 1309 | } | ||
| 1310 | } | ||
| 1311 | } | ||
| 1312 | break; | ||
| 1313 | case DataBuffer.TYPE_INT: { | ||
| 1314 | for (int y = 0; y < h; y++, rY++) { | ||
| 1315 | rX = rminX; | ||
| 1316 | for (int x = 0; x < w; x++, rX++) { | ||
| 1317 | pixel = raster.getPixel(rX, rY, pixel); | ||
| 1318 | normAlpha = pixel[aIdx] * alphaScale; | ||
| 1319 | if (normAlpha != 0) { | ||
| 1320 | float invAlpha = 1.0f / normAlpha; | ||
| 1321 | for (int c=0; c < aIdx; c++) { | ||
| 1322 | pixel[c] = (int) (pixel[c] * invAlpha + | ||
| 1323 | 0.5f); | ||
| 1324 | } | ||
| 1325 | raster.setPixel(rX, rY, pixel); | ||
| 1326 | } | ||
| 1327 | } | ||
| 1328 | } | ||
| 1329 | } | ||
| 1330 | break; | ||
| 1331 | default: | ||
| 1332 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 1333 | "implemented for transferType " + transferType); | ||
| 1334 | } | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | // Return a new color model | ||
| 1338 | return new DirectColorModel(colorSpace, pixel_bits, maskArray[0], | ||
| 1339 | maskArray[1], maskArray[2], maskArray[3], | ||
| 1340 | isAlphaPremultiplied, | ||
| 1341 | transferType); | ||
| 1342 | |||
| 1343 | } | ||
| 1344 | |||
| 1345 | /** | ||
| 1346 | * Returns <code>true</code> if <code>raster</code> is compatible | ||
| 1347 | * with this <code>ColorModel</code> and <code>false</code> if it is | ||
| 1348 | * not. | ||
| 1349 | * @param raster the {@link Raster} object to test for compatibility | ||
| 1350 | * @return <code>true</code> if <code>raster</code> is compatible | ||
| 1351 | * with this <code>ColorModel</code>; <code>false</code> otherwise. | ||
| 1352 | */ | ||
| 1353 | public boolean isCompatibleRaster(Raster raster) { | ||
| 1354 | SampleModel sm = raster.getSampleModel(); | ||
| 1355 | SinglePixelPackedSampleModel spsm; | ||
| 1356 | if (sm instanceof SinglePixelPackedSampleModel) { | ||
| 1357 | spsm = (SinglePixelPackedSampleModel) sm; | ||
| 1358 | } | ||
| 1359 | else { | ||
| 1360 | return false; | ||
| 1361 | } | ||
| 1362 | if (spsm.getNumBands() != getNumComponents()) { | ||
| 1363 | return false; | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | int[] bitMasks = spsm.getBitMasks(); | ||
| 1367 | for (int i=0; i<numComponents; i++) { | ||
| 1368 | if (bitMasks[i] != maskArray[i]) { | ||
| 1369 | return false; | ||
| 1370 | } | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | return (raster.getTransferType() == transferType); | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | private void setFields() { | ||
| 1377 | // Set the private fields | ||
| 1378 | // REMIND: Get rid of these from the native code | ||
| 1379 | red_mask = maskArray[0]; | ||
| 1380 | red_offset = maskOffsets[0]; | ||
| 1381 | green_mask = maskArray[1]; | ||
| 1382 | green_offset = maskOffsets[1]; | ||
| 1383 | blue_mask = maskArray[2]; | ||
| 1384 | blue_offset = maskOffsets[2]; | ||
| 1385 | if (nBits[0] < 8) { | ||
| 1386 | red_scale = (1 << nBits[0]) - 1; | ||
| 1387 | } | ||
| 1388 | if (nBits[1] < 8) { | ||
| 1389 | green_scale = (1 << nBits[1]) - 1; | ||
| 1390 | } | ||
| 1391 | if (nBits[2] < 8) { | ||
| 1392 | blue_scale = (1 << nBits[2]) - 1; | ||
| 1393 | } | ||
| 1394 | if (supportsAlpha) { | ||
| 1395 | alpha_mask = maskArray[3]; | ||
| 1396 | alpha_offset = maskOffsets[3]; | ||
| 1397 | if (nBits[3] < 8) { | ||
| 1398 | alpha_scale = (1 << nBits[3]) - 1; | ||
| 1399 | } | ||
| 1400 | } | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | /** | ||
| 1404 | * Returns a <code>String</code> that represents this | ||
| 1405 | * <code>DirectColorModel</code>. | ||
| 1406 | * @return a <code>String</code> representing this | ||
| 1407 | * <code>DirectColorModel</code>. | ||
| 1408 | */ | ||
| 1409 | public String toString() { | ||
| 1410 | return new String("DirectColorModel: rmask=" | ||
| 1411 | +Integer.toHexString(red_mask)+" gmask=" | ||
| 1412 | +Integer.toHexString(green_mask)+" bmask=" | ||
| 1413 | +Integer.toHexString(blue_mask)+" amask=" | ||
| 1414 | +Integer.toHexString(alpha_mask)); | ||
| 1415 | } | ||
| 1416 | } | ||
Binary file not shown.
| @@ -0,0 +1,209 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.Image; | ||
| 29 | import java.awt.image.ImageFilter; | ||
| 30 | import java.awt.image.ImageConsumer; | ||
| 31 | import java.awt.image.ImageProducer; | ||
| 32 | import java.util.Hashtable; | ||
| 33 | import java.awt.image.ColorModel; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * This class is an implementation of the ImageProducer interface which | ||
| 37 | * takes an existing image and a filter object and uses them to produce | ||
| 38 | * image data for a new filtered version of the original image. | ||
| 39 | * Here is an example which filters an image by swapping the red and | ||
| 40 | * blue compents: | ||
| 41 | * <pre> | ||
| 42 | * | ||
| 43 | * Image src = getImage("doc:///demo/images/duke/T1.gif"); | ||
| 44 | * ImageFilter colorfilter = new RedBlueSwapFilter(); | ||
| 45 | * Image img = createImage(new FilteredImageSource(src.getSource(), | ||
| 46 | * colorfilter)); | ||
| 47 | * | ||
| 48 | * </pre> | ||
| 49 | * | ||
| 50 | * @see ImageProducer | ||
| 51 | * | ||
| 52 | * @author Jim Graham | ||
| 53 | */ | ||
| 54 | public class FilteredImageSource implements ImageProducer { | ||
| 55 | ImageProducer src; | ||
| 56 | ImageFilter filter; | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Constructs an ImageProducer object from an existing ImageProducer | ||
| 60 | * and a filter object. | ||
| 61 | * @param orig the specified <code>ImageProducer</code> | ||
| 62 | * @param imgf the specified <code>ImageFilter</code> | ||
| 63 | * @see ImageFilter | ||
| 64 | * @see java.awt.Component#createImage | ||
| 65 | */ | ||
| 66 | public FilteredImageSource(ImageProducer orig, ImageFilter imgf) { | ||
| 67 | src = orig; | ||
| 68 | filter = imgf; | ||
| 69 | } | ||
| 70 | |||
| 71 | private Hashtable proxies; | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Adds the specified <code>ImageConsumer</code> | ||
| 75 | * to the list of consumers interested in data for the filtered image. | ||
| 76 | * An instance of the original <code>ImageFilter</code> | ||
| 77 | * is created | ||
| 78 | * (using the filter's <code>getFilterInstance</code> method) | ||
| 79 | * to manipulate the image data | ||
| 80 | * for the specified <code>ImageConsumer</code>. | ||
| 81 | * The newly created filter instance | ||
| 82 | * is then passed to the <code>addConsumer</code> method | ||
| 83 | * of the original <code>ImageProducer</code>. | ||
| 84 | * | ||
| 85 | * <p> | ||
| 86 | * This method is public as a side effect | ||
| 87 | * of this class implementing | ||
| 88 | * the <code>ImageProducer</code> interface. | ||
| 89 | * It should not be called from user code, | ||
| 90 | * and its behavior if called from user code is unspecified. | ||
| 91 | * | ||
| 92 | * @param ic the consumer for the filtered image | ||
| 93 | * @see ImageConsumer | ||
| 94 | */ | ||
| 95 | public synchronized void addConsumer(ImageConsumer ic) { | ||
| 96 | if (proxies == null) { | ||
| 97 | proxies = new Hashtable(); | ||
| 98 | } | ||
| 99 | if (!proxies.containsKey(ic)) { | ||
| 100 | ImageFilter imgf = filter.getFilterInstance(ic); | ||
| 101 | proxies.put(ic, imgf); | ||
| 102 | src.addConsumer(imgf); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Determines whether an ImageConsumer is on the list of consumers | ||
| 108 | * currently interested in data for this image. | ||
| 109 | * | ||
| 110 | * <p> | ||
| 111 | * This method is public as a side effect | ||
| 112 | * of this class implementing | ||
| 113 | * the <code>ImageProducer</code> interface. | ||
| 114 | * It should not be called from user code, | ||
| 115 | * and its behavior if called from user code is unspecified. | ||
| 116 | * | ||
| 117 | * @param ic the specified <code>ImageConsumer</code> | ||
| 118 | * @return true if the ImageConsumer is on the list; false otherwise | ||
| 119 | * @see ImageConsumer | ||
| 120 | */ | ||
| 121 | public synchronized boolean isConsumer(ImageConsumer ic) { | ||
| 122 | return (proxies != null && proxies.containsKey(ic)); | ||
| 123 | } | ||
| 124 | |||
| 125 | /** | ||
| 126 | * Removes an ImageConsumer from the list of consumers interested in | ||
| 127 | * data for this image. | ||
| 128 | * | ||
| 129 | * <p> | ||
| 130 | * This method is public as a side effect | ||
| 131 | * of this class implementing | ||
| 132 | * the <code>ImageProducer</code> interface. | ||
| 133 | * It should not be called from user code, | ||
| 134 | * and its behavior if called from user code is unspecified. | ||
| 135 | * | ||
| 136 | * @see ImageConsumer | ||
| 137 | */ | ||
| 138 | public synchronized void removeConsumer(ImageConsumer ic) { | ||
| 139 | if (proxies != null) { | ||
| 140 | ImageFilter imgf = (ImageFilter) proxies.get(ic); | ||
| 141 | if (imgf != null) { | ||
| 142 | src.removeConsumer(imgf); | ||
| 143 | proxies.remove(ic); | ||
| 144 | if (proxies.isEmpty()) { | ||
| 145 | proxies = null; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | /** | ||
| 152 | * Starts production of the filtered image. | ||
| 153 | * If the specified <code>ImageConsumer</code> | ||
| 154 | * isn't already a consumer of the filtered image, | ||
| 155 | * an instance of the original <code>ImageFilter</code> | ||
| 156 | * is created | ||
| 157 | * (using the filter's <code>getFilterInstance</code> method) | ||
| 158 | * to manipulate the image data | ||
| 159 | * for the <code>ImageConsumer</code>. | ||
| 160 | * The filter instance for the <code>ImageConsumer</code> | ||
| 161 | * is then passed to the <code>startProduction</code> method | ||
| 162 | * of the original <code>ImageProducer</code>. | ||
| 163 | * | ||
| 164 | * <p> | ||
| 165 | * This method is public as a side effect | ||
| 166 | * of this class implementing | ||
| 167 | * the <code>ImageProducer</code> interface. | ||
| 168 | * It should not be called from user code, | ||
| 169 | * and its behavior if called from user code is unspecified. | ||
| 170 | * | ||
| 171 | * @param ic the consumer for the filtered image | ||
| 172 | * @see ImageConsumer | ||
| 173 | */ | ||
| 174 | public void startProduction(ImageConsumer ic) { | ||
| 175 | if (proxies == null) { | ||
| 176 | proxies = new Hashtable(); | ||
| 177 | } | ||
| 178 | ImageFilter imgf = (ImageFilter) proxies.get(ic); | ||
| 179 | if (imgf == null) { | ||
| 180 | imgf = filter.getFilterInstance(ic); | ||
| 181 | proxies.put(ic, imgf); | ||
| 182 | } | ||
| 183 | src.startProduction(imgf); | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * Requests that a given ImageConsumer have the image data delivered | ||
| 188 | * one more time in top-down, left-right order. The request is | ||
| 189 | * handed to the ImageFilter for further processing, since the | ||
| 190 | * ability to preserve the pixel ordering depends on the filter. | ||
| 191 | * | ||
| 192 | * <p> | ||
| 193 | * This method is public as a side effect | ||
| 194 | * of this class implementing | ||
| 195 | * the <code>ImageProducer</code> interface. | ||
| 196 | * It should not be called from user code, | ||
| 197 | * and its behavior if called from user code is unspecified. | ||
| 198 | * | ||
| 199 | * @see ImageConsumer | ||
| 200 | */ | ||
| 201 | public void requestTopDownLeftRightResend(ImageConsumer ic) { | ||
| 202 | if (proxies != null) { | ||
| 203 | ImageFilter imgf = (ImageFilter) proxies.get(ic); | ||
| 204 | if (imgf != null) { | ||
| 205 | imgf.resendTopDownLeftRight(src); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | } | ||
| 209 | } | ||
Binary file not shown.
| @@ -0,0 +1,226 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.util.Hashtable; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * The interface for objects expressing interest in image data through | ||
| 32 | * the ImageProducer interfaces. When a consumer is added to an image | ||
| 33 | * producer, the producer delivers all of the data about the image | ||
| 34 | * using the method calls defined in this interface. | ||
| 35 | * | ||
| 36 | * @see ImageProducer | ||
| 37 | * | ||
| 38 | * @author Jim Graham | ||
| 39 | */ | ||
| 40 | public interface ImageConsumer { | ||
| 41 | /** | ||
| 42 | * The dimensions of the source image are reported using the | ||
| 43 | * setDimensions method call. | ||
| 44 | * @param width the width of the source image | ||
| 45 | * @param height the height of the source image | ||
| 46 | */ | ||
| 47 | void setDimensions(int width, int height); | ||
| 48 | |||
| 49 | /** | ||
| 50 | * Sets the extensible list of properties associated with this image. | ||
| 51 | * @param props the list of properties to be associated with this | ||
| 52 | * image | ||
| 53 | */ | ||
| 54 | void setProperties(Hashtable<?,?> props); | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Sets the ColorModel object used for the majority of | ||
| 58 | * the pixels reported using the setPixels method | ||
| 59 | * calls. Note that each set of pixels delivered using setPixels | ||
| 60 | * contains its own ColorModel object, so no assumption should | ||
| 61 | * be made that this model will be the only one used in delivering | ||
| 62 | * pixel values. A notable case where multiple ColorModel objects | ||
| 63 | * may be seen is a filtered image when for each set of pixels | ||
| 64 | * that it filters, the filter | ||
| 65 | * determines whether the | ||
| 66 | * pixels can be sent on untouched, using the original ColorModel, | ||
| 67 | * or whether the pixels should be modified (filtered) and passed | ||
| 68 | * on using a ColorModel more convenient for the filtering process. | ||
| 69 | * @param model the specified <code>ColorModel</code> | ||
| 70 | * @see ColorModel | ||
| 71 | */ | ||
| 72 | void setColorModel(ColorModel model); | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Sets the hints that the ImageConsumer uses to process the | ||
| 76 | * pixels delivered by the ImageProducer. | ||
| 77 | * The ImageProducer can deliver the pixels in any order, but | ||
| 78 | * the ImageConsumer may be able to scale or convert the pixels | ||
| 79 | * to the destination ColorModel more efficiently or with higher | ||
| 80 | * quality if it knows some information about how the pixels will | ||
| 81 | * be delivered up front. The setHints method should be called | ||
| 82 | * before any calls to any of the setPixels methods with a bit mask | ||
| 83 | * of hints about the manner in which the pixels will be delivered. | ||
| 84 | * If the ImageProducer does not follow the guidelines for the | ||
| 85 | * indicated hint, the results are undefined. | ||
| 86 | * @param hintflags a set of hints that the ImageConsumer uses to | ||
| 87 | * process the pixels | ||
| 88 | */ | ||
| 89 | void setHints(int hintflags); | ||
| 90 | |||
| 91 | /** | ||
| 92 | * The pixels will be delivered in a random order. This tells the | ||
| 93 | * ImageConsumer not to use any optimizations that depend on the | ||
| 94 | * order of pixel delivery, which should be the default assumption | ||
| 95 | * in the absence of any call to the setHints method. | ||
| 96 | * @see #setHints | ||
| 97 | */ | ||
| 98 | int RANDOMPIXELORDER = 1; | ||
| 99 | |||
| 100 | /** | ||
| 101 | * The pixels will be delivered in top-down, left-to-right order. | ||
| 102 | * @see #setHints | ||
| 103 | */ | ||
| 104 | int TOPDOWNLEFTRIGHT = 2; | ||
| 105 | |||
| 106 | /** | ||
| 107 | * The pixels will be delivered in (multiples of) complete scanlines | ||
| 108 | * at a time. | ||
| 109 | * @see #setHints | ||
| 110 | */ | ||
| 111 | int COMPLETESCANLINES = 4; | ||
| 112 | |||
| 113 | /** | ||
| 114 | * The pixels will be delivered in a single pass. Each pixel will | ||
| 115 | * appear in only one call to any of the setPixels methods. An | ||
| 116 | * example of an image format which does not meet this criterion | ||
| 117 | * is a progressive JPEG image which defines pixels in multiple | ||
| 118 | * passes, each more refined than the previous. | ||
| 119 | * @see #setHints | ||
| 120 | */ | ||
| 121 | int SINGLEPASS = 8; | ||
| 122 | |||
| 123 | /** | ||
| 124 | * The image contain a single static image. The pixels will be defined | ||
| 125 | * in calls to the setPixels methods and then the imageComplete method | ||
| 126 | * will be called with the STATICIMAGEDONE flag after which no more | ||
| 127 | * image data will be delivered. An example of an image type which | ||
| 128 | * would not meet these criteria would be the output of a video feed, | ||
| 129 | * or the representation of a 3D rendering being manipulated | ||
| 130 | * by the user. The end of each frame in those types of images will | ||
| 131 | * be indicated by calling imageComplete with the SINGLEFRAMEDONE flag. | ||
| 132 | * @see #setHints | ||
| 133 | * @see #imageComplete | ||
| 134 | */ | ||
| 135 | int SINGLEFRAME = 16; | ||
| 136 | |||
| 137 | /** | ||
| 138 | * Delivers the pixels of the image with one or more calls | ||
| 139 | * to this method. Each call specifies the location and | ||
| 140 | * size of the rectangle of source pixels that are contained in | ||
| 141 | * the array of pixels. The specified ColorModel object should | ||
| 142 | * be used to convert the pixels into their corresponding color | ||
| 143 | * and alpha components. Pixel (m,n) is stored in the pixels array | ||
| 144 | * at index (n * scansize + m + off). The pixels delivered using | ||
| 145 | * this method are all stored as bytes. | ||
| 146 | * @param x the X coordinate of the upper-left corner of the | ||
| 147 | * area of pixels to be set | ||
| 148 | * @param y the Y coordinate of the upper-left corner of the | ||
| 149 | * area of pixels to be set | ||
| 150 | * @param w the width of the area of pixels | ||
| 151 | * @param h the height of the area of pixels | ||
| 152 | * @param model the specified <code>ColorModel</code> | ||
| 153 | * @param pixels the array of pixels | ||
| 154 | * @param off the offset into the <code>pixels</code> array | ||
| 155 | * @param scansize the distance from one row of pixels to the next in | ||
| 156 | * the <code>pixels</code> array | ||
| 157 | * @see ColorModel | ||
| 158 | */ | ||
| 159 | void setPixels(int x, int y, int w, int h, | ||
| 160 | ColorModel model, byte pixels[], int off, int scansize); | ||
| 161 | |||
| 162 | /** | ||
| 163 | * The pixels of the image are delivered using one or more calls | ||
| 164 | * to the setPixels method. Each call specifies the location and | ||
| 165 | * size of the rectangle of source pixels that are contained in | ||
| 166 | * the array of pixels. The specified ColorModel object should | ||
| 167 | * be used to convert the pixels into their corresponding color | ||
| 168 | * and alpha components. Pixel (m,n) is stored in the pixels array | ||
| 169 | * at index (n * scansize + m + off). The pixels delivered using | ||
| 170 | * this method are all stored as ints. | ||
| 171 | * this method are all stored as ints. | ||
| 172 | * @param x the X coordinate of the upper-left corner of the | ||
| 173 | * area of pixels to be set | ||
| 174 | * @param y the Y coordinate of the upper-left corner of the | ||
| 175 | * area of pixels to be set | ||
| 176 | * @param w the width of the area of pixels | ||
| 177 | * @param h the height of the area of pixels | ||
| 178 | * @param model the specified <code>ColorModel</code> | ||
| 179 | * @param pixels the array of pixels | ||
| 180 | * @param off the offset into the <code>pixels</code> array | ||
| 181 | * @param scansize the distance from one row of pixels to the next in | ||
| 182 | * the <code>pixels</code> array | ||
| 183 | * @see ColorModel | ||
| 184 | */ | ||
| 185 | void setPixels(int x, int y, int w, int h, | ||
| 186 | ColorModel model, int pixels[], int off, int scansize); | ||
| 187 | |||
| 188 | /** | ||
| 189 | * The imageComplete method is called when the ImageProducer is | ||
| 190 | * finished delivering all of the pixels that the source image | ||
| 191 | * contains, or when a single frame of a multi-frame animation has | ||
| 192 | * been completed, or when an error in loading or producing the | ||
| 193 | * image has occured. The ImageConsumer should remove itself from the | ||
| 194 | * list of consumers registered with the ImageProducer at this time, | ||
| 195 | * unless it is interested in successive frames. | ||
| 196 | * @param status the status of image loading | ||
| 197 | * @see ImageProducer#removeConsumer | ||
| 198 | */ | ||
| 199 | void imageComplete(int status); | ||
| 200 | |||
| 201 | /** | ||
| 202 | * An error was encountered while producing the image. | ||
| 203 | * @see #imageComplete | ||
| 204 | */ | ||
| 205 | int IMAGEERROR = 1; | ||
| 206 | |||
| 207 | /** | ||
| 208 | * One frame of the image is complete but there are more frames | ||
| 209 | * to be delivered. | ||
| 210 | * @see #imageComplete | ||
| 211 | */ | ||
| 212 | int SINGLEFRAMEDONE = 2; | ||
| 213 | |||
| 214 | /** | ||
| 215 | * The image is complete and there are no more pixels or frames | ||
| 216 | * to be delivered. | ||
| 217 | * @see #imageComplete | ||
| 218 | */ | ||
| 219 | int STATICIMAGEDONE = 3; | ||
| 220 | |||
| 221 | /** | ||
| 222 | * The image creation process was deliberately aborted. | ||
| 223 | * @see #imageComplete | ||
| 224 | */ | ||
| 225 | int IMAGEABORTED = 4; | ||
| 226 | } | ||
Binary file not shown.
| @@ -0,0 +1,258 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.util.Hashtable; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * This class implements a filter for the set of interface methods that | ||
| 32 | * are used to deliver data from an ImageProducer to an ImageConsumer. | ||
| 33 | * It is meant to be used in conjunction with a FilteredImageSource | ||
| 34 | * object to produce filtered versions of existing images. It is a | ||
| 35 | * base class that provides the calls needed to implement a "Null filter" | ||
| 36 | * which has no effect on the data being passed through. Filters should | ||
| 37 | * subclass this class and override the methods which deal with the | ||
| 38 | * data that needs to be filtered and modify it as necessary. | ||
| 39 | * | ||
| 40 | * @see FilteredImageSource | ||
| 41 | * @see ImageConsumer | ||
| 42 | * | ||
| 43 | * @author Jim Graham | ||
| 44 | */ | ||
| 45 | public class ImageFilter implements ImageConsumer, Cloneable { | ||
| 46 | /** | ||
| 47 | * The consumer of the particular image data stream for which this | ||
| 48 | * instance of the ImageFilter is filtering data. It is not | ||
| 49 | * initialized during the constructor, but rather during the | ||
| 50 | * getFilterInstance() method call when the FilteredImageSource | ||
| 51 | * is creating a unique instance of this object for a particular | ||
| 52 | * image data stream. | ||
| 53 | * @see #getFilterInstance | ||
| 54 | * @see ImageConsumer | ||
| 55 | */ | ||
| 56 | protected ImageConsumer consumer; | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Returns a unique instance of an ImageFilter object which will | ||
| 60 | * actually perform the filtering for the specified ImageConsumer. | ||
| 61 | * The default implementation just clones this object. | ||
| 62 | * <p> | ||
| 63 | * Note: This method is intended to be called by the ImageProducer | ||
| 64 | * of the Image whose pixels are being filtered. Developers using | ||
| 65 | * this class to filter pixels from an image should avoid calling | ||
| 66 | * this method directly since that operation could interfere | ||
| 67 | * with the filtering operation. | ||
| 68 | * @param ic the specified <code>ImageConsumer</code> | ||
| 69 | * @return an <code>ImageFilter</code> used to perform the | ||
| 70 | * filtering for the specified <code>ImageConsumer</code>. | ||
| 71 | */ | ||
| 72 | public ImageFilter getFilterInstance(ImageConsumer ic) { | ||
| 73 | ImageFilter instance = (ImageFilter) clone(); | ||
| 74 | instance.consumer = ic; | ||
| 75 | return instance; | ||
| 76 | } | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Filters the information provided in the setDimensions method | ||
| 80 | * of the ImageConsumer interface. | ||
| 81 | * <p> | ||
| 82 | * Note: This method is intended to be called by the ImageProducer | ||
| 83 | * of the Image whose pixels are being filtered. Developers using | ||
| 84 | * this class to filter pixels from an image should avoid calling | ||
| 85 | * this method directly since that operation could interfere | ||
| 86 | * with the filtering operation. | ||
| 87 | * @see ImageConsumer#setDimensions | ||
| 88 | */ | ||
| 89 | public void setDimensions(int width, int height) { | ||
| 90 | consumer.setDimensions(width, height); | ||
| 91 | } | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Passes the properties from the source object along after adding a | ||
| 95 | * property indicating the stream of filters it has been run through. | ||
| 96 | * <p> | ||
| 97 | * Note: This method is intended to be called by the ImageProducer | ||
| 98 | * of the Image whose pixels are being filtered. Developers using | ||
| 99 | * this class to filter pixels from an image should avoid calling | ||
| 100 | * this method directly since that operation could interfere | ||
| 101 | * with the filtering operation. | ||
| 102 | * | ||
| 103 | * @param props the properties from the source object | ||
| 104 | * @exception NullPointerException if <code>props</code> is null | ||
| 105 | */ | ||
| 106 | public void setProperties(Hashtable<?,?> props) { | ||
| 107 | Hashtable<Object,Object> p = (Hashtable<Object,Object>)props.clone(); | ||
| 108 | Object o = p.get("filters"); | ||
| 109 | if (o == null) { | ||
| 110 | p.put("filters", toString()); | ||
| 111 | } else if (o instanceof String) { | ||
| 112 | p.put("filters", ((String) o)+toString()); | ||
| 113 | } | ||
| 114 | consumer.setProperties(p); | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Filter the information provided in the setColorModel method | ||
| 119 | * of the ImageConsumer interface. | ||
| 120 | * <p> | ||
| 121 | * Note: This method is intended to be called by the ImageProducer | ||
| 122 | * of the Image whose pixels are being filtered. Developers using | ||
| 123 | * this class to filter pixels from an image should avoid calling | ||
| 124 | * this method directly since that operation could interfere | ||
| 125 | * with the filtering operation. | ||
| 126 | * @see ImageConsumer#setColorModel | ||
| 127 | */ | ||
| 128 | public void setColorModel(ColorModel model) { | ||
| 129 | consumer.setColorModel(model); | ||
| 130 | } | ||
| 131 | |||
| 132 | /** | ||
| 133 | * Filters the information provided in the setHints method | ||
| 134 | * of the ImageConsumer interface. | ||
| 135 | * <p> | ||
| 136 | * Note: This method is intended to be called by the ImageProducer | ||
| 137 | * of the Image whose pixels are being filtered. Developers using | ||
| 138 | * this class to filter pixels from an image should avoid calling | ||
| 139 | * this method directly since that operation could interfere | ||
| 140 | * with the filtering operation. | ||
| 141 | * @see ImageConsumer#setHints | ||
| 142 | */ | ||
| 143 | public void setHints(int hints) { | ||
| 144 | consumer.setHints(hints); | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * Filters the information provided in the setPixels method of the | ||
| 149 | * ImageConsumer interface which takes an array of bytes. | ||
| 150 | * <p> | ||
| 151 | * Note: This method is intended to be called by the ImageProducer | ||
| 152 | * of the Image whose pixels are being filtered. Developers using | ||
| 153 | * this class to filter pixels from an image should avoid calling | ||
| 154 | * this method directly since that operation could interfere | ||
| 155 | * with the filtering operation. | ||
| 156 | * @see ImageConsumer#setPixels | ||
| 157 | */ | ||
| 158 | public void setPixels(int x, int y, int w, int h, | ||
| 159 | ColorModel model, byte pixels[], int off, | ||
| 160 | int scansize) { | ||
| 161 | consumer.setPixels(x, y, w, h, model, pixels, off, scansize); | ||
| 162 | } | ||
| 163 | |||
| 164 | /** | ||
| 165 | * Filters the information provided in the setPixels method of the | ||
| 166 | * ImageConsumer interface which takes an array of integers. | ||
| 167 | * <p> | ||
| 168 | * Note: This method is intended to be called by the ImageProducer | ||
| 169 | * of the Image whose pixels are being filtered. Developers using | ||
| 170 | * this class to filter pixels from an image should avoid calling | ||
| 171 | * this method directly since that operation could interfere | ||
| 172 | * with the filtering operation. | ||
| 173 | * @see ImageConsumer#setPixels | ||
| 174 | */ | ||
| 175 | public void setPixels(int x, int y, int w, int h, | ||
| 176 | ColorModel model, int pixels[], int off, | ||
| 177 | int scansize) { | ||
| 178 | consumer.setPixels(x, y, w, h, model, pixels, off, scansize); | ||
| 179 | } | ||
| 180 | |||
| 181 | /** | ||
| 182 | * Filters the information provided in the imageComplete method of | ||
| 183 | * the ImageConsumer interface. | ||
| 184 | * <p> | ||
| 185 | * Note: This method is intended to be called by the ImageProducer | ||
| 186 | * of the Image whose pixels are being filtered. Developers using | ||
| 187 | * this class to filter pixels from an image should avoid calling | ||
| 188 | * this method directly since that operation could interfere | ||
| 189 | * with the filtering operation. | ||
| 190 | * @see ImageConsumer#imageComplete | ||
| 191 | */ | ||
| 192 | public void imageComplete(int status) { | ||
| 193 | consumer.imageComplete(status); | ||
| 194 | } | ||
| 195 | |||
| 196 | /** | ||
| 197 | * Responds to a request for a TopDownLeftRight (TDLR) ordered resend | ||
| 198 | * of the pixel data from an <code>ImageConsumer</code>. | ||
| 199 | * When an <code>ImageConsumer</code> being fed | ||
| 200 | * by an instance of this <code>ImageFilter</code> | ||
| 201 | * requests a resend of the data in TDLR order, | ||
| 202 | * the <code>FilteredImageSource</code> | ||
| 203 | * invokes this method of the <code>ImageFilter</code>. | ||
| 204 | * | ||
| 205 | * <p> | ||
| 206 | * | ||
| 207 | * An <code>ImageFilter</code> subclass might override this method or not, | ||
| 208 | * depending on if and how it can send data in TDLR order. | ||
| 209 | * Three possibilities exist: | ||
| 210 | * | ||
| 211 | * <ul> | ||
| 212 | * <li> | ||
| 213 | * Do not override this method. | ||
| 214 | * This makes the subclass use the default implementation, | ||
| 215 | * which is to | ||
| 216 | * forward the request | ||
| 217 | * to the indicated <code>ImageProducer</code> | ||
| 218 | * using this filter as the requesting <code>ImageConsumer</code>. | ||
| 219 | * This behavior | ||
| 220 | * is appropriate if the filter can determine | ||
| 221 | * that it will forward the pixels | ||
| 222 | * in TDLR order if its upstream producer object | ||
| 223 | * sends them in TDLR order. | ||
| 224 | * | ||
| 225 | * <li> | ||
| 226 | * Override the method to simply send the data. | ||
| 227 | * This is appropriate if the filter can handle the request itself — | ||
| 228 | * for example, | ||
| 229 | * if the generated pixels have been saved in some sort of buffer. | ||
| 230 | * | ||
| 231 | * <li> | ||
| 232 | * Override the method to do nothing. | ||
| 233 | * This is appropriate | ||
| 234 | * if the filter cannot produce filtered data in TDLR order. | ||
| 235 | * </ul> | ||
| 236 | * | ||
| 237 | * @see ImageProducer#requestTopDownLeftRightResend | ||
| 238 | * @param ip the ImageProducer that is feeding this instance of | ||
| 239 | * the filter - also the ImageProducer that the request should be | ||
| 240 | * forwarded to if necessary | ||
| 241 | * @exception NullPointerException if <code>ip</code> is null | ||
| 242 | */ | ||
| 243 | public void resendTopDownLeftRight(ImageProducer ip) { | ||
| 244 | ip.requestTopDownLeftRightResend(this); | ||
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | * Clones this object. | ||
| 249 | */ | ||
| 250 | public Object clone() { | ||
| 251 | try { | ||
| 252 | return super.clone(); | ||
| 253 | } catch (CloneNotSupportedException e) { | ||
| 254 | // this shouldn't happen, since we are Cloneable | ||
| 255 | throw new InternalError(); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | } | ||
Binary file not shown.
| @@ -0,0 +1,170 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 1999, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.Image; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * An asynchronous update interface for receiving notifications about | ||
| 32 | * Image information as the Image is constructed. | ||
| 33 | * | ||
| 34 | * @author Jim Graham | ||
| 35 | */ | ||
| 36 | public interface ImageObserver { | ||
| 37 | /** | ||
| 38 | * This method is called when information about an image which was | ||
| 39 | * previously requested using an asynchronous interface becomes | ||
| 40 | * available. Asynchronous interfaces are method calls such as | ||
| 41 | * getWidth(ImageObserver) and drawImage(img, x, y, ImageObserver) | ||
| 42 | * which take an ImageObserver object as an argument. Those methods | ||
| 43 | * register the caller as interested either in information about | ||
| 44 | * the overall image itself (in the case of getWidth(ImageObserver)) | ||
| 45 | * or about an output version of an image (in the case of the | ||
| 46 | * drawImage(img, x, y, [w, h,] ImageObserver) call). | ||
| 47 | * | ||
| 48 | * <p>This method | ||
| 49 | * should return true if further updates are needed or false if the | ||
| 50 | * required information has been acquired. The image which was being | ||
| 51 | * tracked is passed in using the img argument. Various constants | ||
| 52 | * are combined to form the infoflags argument which indicates what | ||
| 53 | * information about the image is now available. The interpretation | ||
| 54 | * of the x, y, width, and height arguments depends on the contents | ||
| 55 | * of the infoflags argument. | ||
| 56 | * <p> | ||
| 57 | * The <code>infoflags</code> argument should be the bitwise inclusive | ||
| 58 | * <b>OR</b> of the following flags: <code>WIDTH</code>, | ||
| 59 | * <code>HEIGHT</code>, <code>PROPERTIES</code>, <code>SOMEBITS</code>, | ||
| 60 | * <code>FRAMEBITS</code>, <code>ALLBITS</code>, <code>ERROR</code>, | ||
| 61 | * <code>ABORT</code>. | ||
| 62 | * | ||
| 63 | * @param img the image being observed. | ||
| 64 | * @param infoflags the bitwise inclusive OR of the following | ||
| 65 | * flags: <code>WIDTH</code>, <code>HEIGHT</code>, | ||
| 66 | * <code>PROPERTIES</code>, <code>SOMEBITS</code>, | ||
| 67 | * <code>FRAMEBITS</code>, <code>ALLBITS</code>, | ||
| 68 | * <code>ERROR</code>, <code>ABORT</code>. | ||
| 69 | * @param x the <i>x</i> coordinate. | ||
| 70 | * @param y the <i>y</i> coordinate. | ||
| 71 | * @param width the width. | ||
| 72 | * @param height the height. | ||
| 73 | * @return <code>false</code> if the infoflags indicate that the | ||
| 74 | * image is completely loaded; <code>true</code> otherwise. | ||
| 75 | * | ||
| 76 | * @see #WIDTH | ||
| 77 | * @see #HEIGHT | ||
| 78 | * @see #PROPERTIES | ||
| 79 | * @see #SOMEBITS | ||
| 80 | * @see #FRAMEBITS | ||
| 81 | * @see #ALLBITS | ||
| 82 | * @see #ERROR | ||
| 83 | * @see #ABORT | ||
| 84 | * @see Image#getWidth | ||
| 85 | * @see Image#getHeight | ||
| 86 | * @see java.awt.Graphics#drawImage | ||
| 87 | */ | ||
| 88 | public boolean imageUpdate(Image img, int infoflags, | ||
| 89 | int x, int y, int width, int height); | ||
| 90 | |||
| 91 | /** | ||
| 92 | * This flag in the infoflags argument to imageUpdate indicates that | ||
| 93 | * the width of the base image is now available and can be taken | ||
| 94 | * from the width argument to the imageUpdate callback method. | ||
| 95 | * @see Image#getWidth | ||
| 96 | * @see #imageUpdate | ||
| 97 | */ | ||
| 98 | public static final int WIDTH = 1; | ||
| 99 | |||
| 100 | /** | ||
| 101 | * This flag in the infoflags argument to imageUpdate indicates that | ||
| 102 | * the height of the base image is now available and can be taken | ||
| 103 | * from the height argument to the imageUpdate callback method. | ||
| 104 | * @see Image#getHeight | ||
| 105 | * @see #imageUpdate | ||
| 106 | */ | ||
| 107 | public static final int HEIGHT = 2; | ||
| 108 | |||
| 109 | /** | ||
| 110 | * This flag in the infoflags argument to imageUpdate indicates that | ||
| 111 | * the properties of the image are now available. | ||
| 112 | * @see Image#getProperty | ||
| 113 | * @see #imageUpdate | ||
| 114 | */ | ||
| 115 | public static final int PROPERTIES = 4; | ||
| 116 | |||
| 117 | /** | ||
| 118 | * This flag in the infoflags argument to imageUpdate indicates that | ||
| 119 | * more pixels needed for drawing a scaled variation of the image | ||
| 120 | * are available. The bounding box of the new pixels can be taken | ||
| 121 | * from the x, y, width, and height arguments to the imageUpdate | ||
| 122 | * callback method. | ||
| 123 | * @see java.awt.Graphics#drawImage | ||
| 124 | * @see #imageUpdate | ||
| 125 | */ | ||
| 126 | public static final int SOMEBITS = 8; | ||
| 127 | |||
| 128 | /** | ||
| 129 | * This flag in the infoflags argument to imageUpdate indicates that | ||
| 130 | * another complete frame of a multi-frame image which was previously | ||
| 131 | * drawn is now available to be drawn again. The x, y, width, and height | ||
| 132 | * arguments to the imageUpdate callback method should be ignored. | ||
| 133 | * @see java.awt.Graphics#drawImage | ||
| 134 | * @see #imageUpdate | ||
| 135 | */ | ||
| 136 | public static final int FRAMEBITS = 16; | ||
| 137 | |||
| 138 | /** | ||
| 139 | * This flag in the infoflags argument to imageUpdate indicates that | ||
| 140 | * a static image which was previously drawn is now complete and can | ||
| 141 | * be drawn again in its final form. The x, y, width, and height | ||
| 142 | * arguments to the imageUpdate callback method should be ignored. | ||
| 143 | * @see java.awt.Graphics#drawImage | ||
| 144 | * @see #imageUpdate | ||
| 145 | */ | ||
| 146 | public static final int ALLBITS = 32; | ||
| 147 | |||
| 148 | /** | ||
| 149 | * This flag in the infoflags argument to imageUpdate indicates that | ||
| 150 | * an image which was being tracked asynchronously has encountered | ||
| 151 | * an error. No further information will become available and | ||
| 152 | * drawing the image will fail. | ||
| 153 | * As a convenience, the ABORT flag will be indicated at the same | ||
| 154 | * time to indicate that the image production was aborted. | ||
| 155 | * @see #imageUpdate | ||
| 156 | */ | ||
| 157 | public static final int ERROR = 64; | ||
| 158 | |||
| 159 | /** | ||
| 160 | * This flag in the infoflags argument to imageUpdate indicates that | ||
| 161 | * an image which was being tracked asynchronously was aborted before | ||
| 162 | * production was complete. No more information will become available | ||
| 163 | * without further action to trigger another image production sequence. | ||
| 164 | * If the ERROR flag was not also set in this image update, then | ||
| 165 | * accessing any of the data in the image will restart the production | ||
| 166 | * again, probably from the beginning. | ||
| 167 | * @see #imageUpdate | ||
| 168 | */ | ||
| 169 | public static final int ABORT = 128; | ||
| 170 | } | ||
Binary file not shown.
| @@ -0,0 +1,112 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 2000, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | /** | ||
| 29 | * The interface for objects which can produce the image data for Images. | ||
| 30 | * Each image contains an ImageProducer which is used to reconstruct | ||
| 31 | * the image whenever it is needed, for example, when a new size of the | ||
| 32 | * Image is scaled, or when the width or height of the Image is being | ||
| 33 | * requested. | ||
| 34 | * | ||
| 35 | * @see ImageConsumer | ||
| 36 | * | ||
| 37 | * @author Jim Graham | ||
| 38 | */ | ||
| 39 | public interface ImageProducer { | ||
| 40 | /** | ||
| 41 | * Registers an <code>ImageConsumer</code> with the | ||
| 42 | * <code>ImageProducer</code> for access to the image data | ||
| 43 | * during a later reconstruction of the <code>Image</code>. | ||
| 44 | * The <code>ImageProducer</code> may, at its discretion, | ||
| 45 | * start delivering the image data to the consumer | ||
| 46 | * using the <code>ImageConsumer</code> interface immediately, | ||
| 47 | * or when the next available image reconstruction is triggered | ||
| 48 | * by a call to the <code>startProduction</code> method. | ||
| 49 | * @param ic the specified <code>ImageConsumer</code> | ||
| 50 | * @see #startProduction | ||
| 51 | */ | ||
| 52 | public void addConsumer(ImageConsumer ic); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Determines if a specified <code>ImageConsumer</code> | ||
| 56 | * object is currently registered with this | ||
| 57 | * <code>ImageProducer</code> as one of its consumers. | ||
| 58 | * @param ic the specified <code>ImageConsumer</code> | ||
| 59 | * @return <code>true</code> if the specified | ||
| 60 | * <code>ImageConsumer</code> is registered with | ||
| 61 | * this <code>ImageProducer</code>; | ||
| 62 | * <code>false</code> otherwise. | ||
| 63 | */ | ||
| 64 | public boolean isConsumer(ImageConsumer ic); | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Removes the specified <code>ImageConsumer</code> object | ||
| 68 | * from the list of consumers currently registered to | ||
| 69 | * receive image data. It is not considered an error | ||
| 70 | * to remove a consumer that is not currently registered. | ||
| 71 | * The <code>ImageProducer</code> should stop sending data | ||
| 72 | * to this consumer as soon as is feasible. | ||
| 73 | * @param ic the specified <code>ImageConsumer</code> | ||
| 74 | */ | ||
| 75 | public void removeConsumer(ImageConsumer ic); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Registers the specified <code>ImageConsumer</code> object | ||
| 79 | * as a consumer and starts an immediate reconstruction of | ||
| 80 | * the image data which will then be delivered to this | ||
| 81 | * consumer and any other consumer which might have already | ||
| 82 | * been registered with the producer. This method differs | ||
| 83 | * from the addConsumer method in that a reproduction of | ||
| 84 | * the image data should be triggered as soon as possible. | ||
| 85 | * @param ic the specified <code>ImageConsumer</code> | ||
| 86 | * @see #addConsumer | ||
| 87 | */ | ||
| 88 | public void startProduction(ImageConsumer ic); | ||
| 89 | |||
| 90 | /** | ||
| 91 | * Requests, on behalf of the <code>ImageConsumer</code>, | ||
| 92 | * that the <code>ImageProducer</code> attempt to resend | ||
| 93 | * the image data one more time in TOPDOWNLEFTRIGHT order | ||
| 94 | * so that higher quality conversion algorithms which | ||
| 95 | * depend on receiving pixels in order can be used to | ||
| 96 | * produce a better output version of the image. The | ||
| 97 | * <code>ImageProducer</code> is free to | ||
| 98 | * ignore this call if it cannot resend the data in that | ||
| 99 | * order. If the data can be resent, the | ||
| 100 | * <code>ImageProducer</code> should respond by executing | ||
| 101 | * the following minimum set of <code>ImageConsumer</code> | ||
| 102 | * method calls: | ||
| 103 | * <pre> | ||
| 104 | * ic.setHints(TOPDOWNLEFTRIGHT | < otherhints >); | ||
| 105 | * ic.setPixels(...); // As many times as needed | ||
| 106 | * ic.imageComplete(); | ||
| 107 | * </pre> | ||
| 108 | * @param ic the specified <code>ImageConsumer</code> | ||
| 109 | * @see ImageConsumer#setHints | ||
| 110 | */ | ||
| 111 | public void requestTopDownLeftRightResend(ImageConsumer ic); | ||
| 112 | } | ||
Binary file not shown.
| @@ -0,0 +1,45 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | |||
| 29 | /** | ||
| 30 | * The <code>ImagingOpException</code> is thrown if one of the | ||
| 31 | * {@link BufferedImageOp} or {@link RasterOp} filter methods cannot | ||
| 32 | * process the image. | ||
| 33 | */ | ||
| 34 | public class ImagingOpException extends java.lang.RuntimeException { | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Constructs an <code>ImagingOpException</code> object with the | ||
| 38 | * specified message. | ||
| 39 | * @param s the message to generate when a | ||
| 40 | * <code>ImagingOpException</code> is thrown | ||
| 41 | */ | ||
| 42 | public ImagingOpException(String s) { | ||
| 43 | super (s); | ||
| 44 | } | ||
| 45 | } | ||
Binary file not shown.
| @@ -0,0 +1,1534 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.Transparency; | ||
| 29 | import java.awt.color.ColorSpace; | ||
| 30 | import java.math.BigInteger; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * The <code>IndexColorModel</code> class is a <code>ColorModel</code> | ||
| 34 | * class that works with pixel values consisting of a | ||
| 35 | * single sample that is an index into a fixed colormap in the default | ||
| 36 | * sRGB color space. The colormap specifies red, green, blue, and | ||
| 37 | * optional alpha components corresponding to each index. All components | ||
| 38 | * are represented in the colormap as 8-bit unsigned integral values. | ||
| 39 | * Some constructors allow the caller to specify "holes" in the colormap | ||
| 40 | * by indicating which colormap entries are valid and which represent | ||
| 41 | * unusable colors via the bits set in a <code>BigInteger</code> object. | ||
| 42 | * This color model is similar to an X11 PseudoColor visual. | ||
| 43 | * <p> | ||
| 44 | * Some constructors provide a means to specify an alpha component | ||
| 45 | * for each pixel in the colormap, while others either provide no | ||
| 46 | * such means or, in some cases, a flag to indicate whether the | ||
| 47 | * colormap data contains alpha values. If no alpha is supplied to | ||
| 48 | * the constructor, an opaque alpha component (alpha = 1.0) is | ||
| 49 | * assumed for each entry. | ||
| 50 | * An optional transparent pixel value can be supplied that indicates a | ||
| 51 | * pixel to be made completely transparent, regardless of any alpha | ||
| 52 | * component supplied or assumed for that pixel value. | ||
| 53 | * Note that the color components in the colormap of an | ||
| 54 | * <code>IndexColorModel</code> objects are never pre-multiplied with | ||
| 55 | * the alpha components. | ||
| 56 | * <p> | ||
| 57 | * <a name="transparency"> | ||
| 58 | * The transparency of an <code>IndexColorModel</code> object is | ||
| 59 | * determined by examining the alpha components of the colors in the | ||
| 60 | * colormap and choosing the most specific value after considering | ||
| 61 | * the optional alpha values and any transparent index specified. | ||
| 62 | * The transparency value is <code>Transparency.OPAQUE</code> | ||
| 63 | * only if all valid colors in | ||
| 64 | * the colormap are opaque and there is no valid transparent pixel. | ||
| 65 | * If all valid colors | ||
| 66 | * in the colormap are either completely opaque (alpha = 1.0) or | ||
| 67 | * completely transparent (alpha = 0.0), which typically occurs when | ||
| 68 | * a valid transparent pixel is specified, | ||
| 69 | * the value is <code>Transparency.BITMASK</code>. | ||
| 70 | * Otherwise, the value is <code>Transparency.TRANSLUCENT</code>, indicating | ||
| 71 | * that some valid color has an alpha component that is | ||
| 72 | * neither completely transparent nor completely opaque | ||
| 73 | * (0.0 < alpha < 1.0). | ||
| 74 | * </a> | ||
| 75 | * | ||
| 76 | * <p> | ||
| 77 | * If an <code>IndexColorModel</code> object has | ||
| 78 | * a transparency value of <code>Transparency.OPAQUE</code>, | ||
| 79 | * then the <code>hasAlpha</code> | ||
| 80 | * and <code>getNumComponents</code> methods | ||
| 81 | * (both inherited from <code>ColorModel</code>) | ||
| 82 | * return false and 3, respectively. | ||
| 83 | * For any other transparency value, | ||
| 84 | * <code>hasAlpha</code> returns true | ||
| 85 | * and <code>getNumComponents</code> returns 4. | ||
| 86 | * | ||
| 87 | * <p> | ||
| 88 | * <a name="index_values"> | ||
| 89 | * The values used to index into the colormap are taken from the least | ||
| 90 | * significant <em>n</em> bits of pixel representations where | ||
| 91 | * <em>n</em> is based on the pixel size specified in the constructor. | ||
| 92 | * For pixel sizes smaller than 8 bits, <em>n</em> is rounded up to a | ||
| 93 | * power of two (3 becomes 4 and 5,6,7 become 8). | ||
| 94 | * For pixel sizes between 8 and 16 bits, <em>n</em> is equal to the | ||
| 95 | * pixel size. | ||
| 96 | * Pixel sizes larger than 16 bits are not supported by this class. | ||
| 97 | * Higher order bits beyond <em>n</em> are ignored in pixel representations. | ||
| 98 | * Index values greater than or equal to the map size, but less than | ||
| 99 | * 2<sup><em>n</em></sup>, are undefined and return 0 for all color and | ||
| 100 | * alpha components. | ||
| 101 | * <p> | ||
| 102 | * For those methods that use a primitive array pixel representation of | ||
| 103 | * type <code>transferType</code>, the array length is always one. | ||
| 104 | * The transfer types supported are <code>DataBuffer.TYPE_BYTE</code> and | ||
| 105 | * <code>DataBuffer.TYPE_USHORT</code>. A single int pixel | ||
| 106 | * representation is valid for all objects of this class, since it is | ||
| 107 | * always possible to represent pixel values used with this class in a | ||
| 108 | * single int. Therefore, methods that use this representation do | ||
| 109 | * not throw an <code>IllegalArgumentException</code> due to an invalid | ||
| 110 | * pixel value. | ||
| 111 | * <p> | ||
| 112 | * Many of the methods in this class are final. The reason for | ||
| 113 | * this is that the underlying native graphics code makes assumptions | ||
| 114 | * about the layout and operation of this class and those assumptions | ||
| 115 | * are reflected in the implementations of the methods here that are | ||
| 116 | * marked final. You can subclass this class for other reasons, but | ||
| 117 | * you cannot override or modify the behaviour of those methods. | ||
| 118 | * | ||
| 119 | * @see ColorModel | ||
| 120 | * @see ColorSpace | ||
| 121 | * @see DataBuffer | ||
| 122 | * | ||
| 123 | */ | ||
| 124 | public class IndexColorModel extends ColorModel { | ||
| 125 | private int rgb[]; | ||
| 126 | private int map_size; | ||
| 127 | private int pixel_mask; | ||
| 128 | private int transparent_index = -1; | ||
| 129 | private boolean allgrayopaque; | ||
| 130 | private BigInteger validBits; | ||
| 131 | |||
| 132 | private sun.awt.image.BufImgSurfaceData.ICMColorData colorData = null; | ||
| 133 | |||
| 134 | private static int[] opaqueBits = {8, 8, 8}; | ||
| 135 | private static int[] alphaBits = {8, 8, 8, 8}; | ||
| 136 | |||
| 137 | static private native void initIDs(); | ||
| 138 | static { | ||
| 139 | ColorModel.loadLibraries(); | ||
| 140 | initIDs(); | ||
| 141 | } | ||
| 142 | /** | ||
| 143 | * Constructs an <code>IndexColorModel</code> from the specified | ||
| 144 | * arrays of red, green, and blue components. Pixels described | ||
| 145 | * by this color model all have alpha components of 255 | ||
| 146 | * unnormalized (1.0 normalized), which means they | ||
| 147 | * are fully opaque. All of the arrays specifying the color | ||
| 148 | * components must have at least the specified number of entries. | ||
| 149 | * The <code>ColorSpace</code> is the default sRGB space. | ||
| 150 | * Since there is no alpha information in any of the arguments | ||
| 151 | * to this constructor, the transparency value is always | ||
| 152 | * <code>Transparency.OPAQUE</code>. | ||
| 153 | * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code> | ||
| 154 | * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel. | ||
| 155 | * @param bits the number of bits each pixel occupies | ||
| 156 | * @param size the size of the color component arrays | ||
| 157 | * @param r the array of red color components | ||
| 158 | * @param g the array of green color components | ||
| 159 | * @param b the array of blue color components | ||
| 160 | * @throws IllegalArgumentException if <code>bits</code> is less | ||
| 161 | * than 1 or greater than 16 | ||
| 162 | * @throws IllegalArgumentException if <code>size</code> is less | ||
| 163 | * than 1 | ||
| 164 | */ | ||
| 165 | public IndexColorModel(int bits, int size, | ||
| 166 | byte r[], byte g[], byte b[]) { | ||
| 167 | super(bits, opaqueBits, | ||
| 168 | ColorSpace.getInstance(ColorSpace.CS_sRGB), | ||
| 169 | false, false, OPAQUE, | ||
| 170 | ColorModel.getDefaultTransferType(bits)); | ||
| 171 | if (bits < 1 || bits > 16) { | ||
| 172 | throw new IllegalArgumentException("Number of bits must be between" | ||
| 173 | +" 1 and 16."); | ||
| 174 | } | ||
| 175 | setRGBs(size, r, g, b, null); | ||
| 176 | calculatePixelMask(); | ||
| 177 | } | ||
| 178 | |||
| 179 | /** | ||
| 180 | * Constructs an <code>IndexColorModel</code> from the given arrays | ||
| 181 | * of red, green, and blue components. Pixels described by this color | ||
| 182 | * model all have alpha components of 255 unnormalized | ||
| 183 | * (1.0 normalized), which means they are fully opaque, except | ||
| 184 | * for the indicated pixel to be made transparent. All of the arrays | ||
| 185 | * specifying the color components must have at least the specified | ||
| 186 | * number of entries. | ||
| 187 | * The <code>ColorSpace</code> is the default sRGB space. | ||
| 188 | * The transparency value may be <code>Transparency.OPAQUE</code> or | ||
| 189 | * <code>Transparency.BITMASK</code> depending on the arguments, as | ||
| 190 | * specified in the <a href="#transparency">class description</a> above. | ||
| 191 | * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code> | ||
| 192 | * or <code>DataBuffer.TYPE_USHORT</code> that can hold a | ||
| 193 | * single pixel. | ||
| 194 | * @param bits the number of bits each pixel occupies | ||
| 195 | * @param size the size of the color component arrays | ||
| 196 | * @param r the array of red color components | ||
| 197 | * @param g the array of green color components | ||
| 198 | * @param b the array of blue color components | ||
| 199 | * @param trans the index of the transparent pixel | ||
| 200 | * @throws IllegalArgumentException if <code>bits</code> is less than | ||
| 201 | * 1 or greater than 16 | ||
| 202 | * @throws IllegalArgumentException if <code>size</code> is less than | ||
| 203 | * 1 | ||
| 204 | */ | ||
| 205 | public IndexColorModel(int bits, int size, | ||
| 206 | byte r[], byte g[], byte b[], int trans) { | ||
| 207 | super(bits, opaqueBits, | ||
| 208 | ColorSpace.getInstance(ColorSpace.CS_sRGB), | ||
| 209 | false, false, OPAQUE, | ||
| 210 | ColorModel.getDefaultTransferType(bits)); | ||
| 211 | if (bits < 1 || bits > 16) { | ||
| 212 | throw new IllegalArgumentException("Number of bits must be between" | ||
| 213 | +" 1 and 16."); | ||
| 214 | } | ||
| 215 | setRGBs(size, r, g, b, null); | ||
| 216 | setTransparentPixel(trans); | ||
| 217 | calculatePixelMask(); | ||
| 218 | } | ||
| 219 | |||
| 220 | /** | ||
| 221 | * Constructs an <code>IndexColorModel</code> from the given | ||
| 222 | * arrays of red, green, blue and alpha components. All of the | ||
| 223 | * arrays specifying the components must have at least the specified | ||
| 224 | * number of entries. | ||
| 225 | * The <code>ColorSpace</code> is the default sRGB space. | ||
| 226 | * The transparency value may be any of <code>Transparency.OPAQUE</code>, | ||
| 227 | * <code>Transparency.BITMASK</code>, | ||
| 228 | * or <code>Transparency.TRANSLUCENT</code> | ||
| 229 | * depending on the arguments, as specified | ||
| 230 | * in the <a href="#transparency">class description</a> above. | ||
| 231 | * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code> | ||
| 232 | * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel. | ||
| 233 | * @param bits the number of bits each pixel occupies | ||
| 234 | * @param size the size of the color component arrays | ||
| 235 | * @param r the array of red color components | ||
| 236 | * @param g the array of green color components | ||
| 237 | * @param b the array of blue color components | ||
| 238 | * @param a the array of alpha value components | ||
| 239 | * @throws IllegalArgumentException if <code>bits</code> is less | ||
| 240 | * than 1 or greater than 16 | ||
| 241 | * @throws IllegalArgumentException if <code>size</code> is less | ||
| 242 | * than 1 | ||
| 243 | */ | ||
| 244 | public IndexColorModel(int bits, int size, | ||
| 245 | byte r[], byte g[], byte b[], byte a[]) { | ||
| 246 | super (bits, alphaBits, | ||
| 247 | ColorSpace.getInstance(ColorSpace.CS_sRGB), | ||
| 248 | true, false, TRANSLUCENT, | ||
| 249 | ColorModel.getDefaultTransferType(bits)); | ||
| 250 | if (bits < 1 || bits > 16) { | ||
| 251 | throw new IllegalArgumentException("Number of bits must be between" | ||
| 252 | +" 1 and 16."); | ||
| 253 | } | ||
| 254 | setRGBs (size, r, g, b, a); | ||
| 255 | calculatePixelMask(); | ||
| 256 | } | ||
| 257 | |||
| 258 | /** | ||
| 259 | * Constructs an <code>IndexColorModel</code> from a single | ||
| 260 | * array of interleaved red, green, blue and optional alpha | ||
| 261 | * components. The array must have enough values in it to | ||
| 262 | * fill all of the needed component arrays of the specified | ||
| 263 | * size. The <code>ColorSpace</code> is the default sRGB space. | ||
| 264 | * The transparency value may be any of <code>Transparency.OPAQUE</code>, | ||
| 265 | * <code>Transparency.BITMASK</code>, | ||
| 266 | * or <code>Transparency.TRANSLUCENT</code> | ||
| 267 | * depending on the arguments, as specified | ||
| 268 | * in the <a href="#transparency">class description</a> above. | ||
| 269 | * The transfer type is the smallest of | ||
| 270 | * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code> | ||
| 271 | * that can hold a single pixel. | ||
| 272 | * | ||
| 273 | * @param bits the number of bits each pixel occupies | ||
| 274 | * @param size the size of the color component arrays | ||
| 275 | * @param cmap the array of color components | ||
| 276 | * @param start the starting offset of the first color component | ||
| 277 | * @param hasalpha indicates whether alpha values are contained in | ||
| 278 | * the <code>cmap</code> array | ||
| 279 | * @throws IllegalArgumentException if <code>bits</code> is less | ||
| 280 | * than 1 or greater than 16 | ||
| 281 | * @throws IllegalArgumentException if <code>size</code> is less | ||
| 282 | * than 1 | ||
| 283 | */ | ||
| 284 | public IndexColorModel(int bits, int size, byte cmap[], int start, | ||
| 285 | boolean hasalpha) { | ||
| 286 | this(bits, size, cmap, start, hasalpha, -1); | ||
| 287 | if (bits < 1 || bits > 16) { | ||
| 288 | throw new IllegalArgumentException("Number of bits must be between" | ||
| 289 | +" 1 and 16."); | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | /** | ||
| 294 | * Constructs an <code>IndexColorModel</code> from a single array of | ||
| 295 | * interleaved red, green, blue and optional alpha components. The | ||
| 296 | * specified transparent index represents a pixel that is made | ||
| 297 | * entirely transparent regardless of any alpha value specified | ||
| 298 | * for it. The array must have enough values in it to fill all | ||
| 299 | * of the needed component arrays of the specified size. | ||
| 300 | * The <code>ColorSpace</code> is the default sRGB space. | ||
| 301 | * The transparency value may be any of <code>Transparency.OPAQUE</code>, | ||
| 302 | * <code>Transparency.BITMASK</code>, | ||
| 303 | * or <code>Transparency.TRANSLUCENT</code> | ||
| 304 | * depending on the arguments, as specified | ||
| 305 | * in the <a href="#transparency">class description</a> above. | ||
| 306 | * The transfer type is the smallest of | ||
| 307 | * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code> | ||
| 308 | * that can hold a single pixel. | ||
| 309 | * @param bits the number of bits each pixel occupies | ||
| 310 | * @param size the size of the color component arrays | ||
| 311 | * @param cmap the array of color components | ||
| 312 | * @param start the starting offset of the first color component | ||
| 313 | * @param hasalpha indicates whether alpha values are contained in | ||
| 314 | * the <code>cmap</code> array | ||
| 315 | * @param trans the index of the fully transparent pixel | ||
| 316 | * @throws IllegalArgumentException if <code>bits</code> is less than | ||
| 317 | * 1 or greater than 16 | ||
| 318 | * @throws IllegalArgumentException if <code>size</code> is less than | ||
| 319 | * 1 | ||
| 320 | */ | ||
| 321 | public IndexColorModel(int bits, int size, byte cmap[], int start, | ||
| 322 | boolean hasalpha, int trans) { | ||
| 323 | // REMIND: This assumes the ordering: RGB[A] | ||
| 324 | super(bits, opaqueBits, | ||
| 325 | ColorSpace.getInstance(ColorSpace.CS_sRGB), | ||
| 326 | false, false, OPAQUE, | ||
| 327 | ColorModel.getDefaultTransferType(bits)); | ||
| 328 | |||
| 329 | if (bits < 1 || bits > 16) { | ||
| 330 | throw new IllegalArgumentException("Number of bits must be between" | ||
| 331 | +" 1 and 16."); | ||
| 332 | } | ||
| 333 | if (size < 1) { | ||
| 334 | throw new IllegalArgumentException("Map size ("+size+ | ||
| 335 | ") must be >= 1"); | ||
| 336 | } | ||
| 337 | map_size = size; | ||
| 338 | rgb = new int[calcRealMapSize(bits, size)]; | ||
| 339 | int j = start; | ||
| 340 | int alpha = 0xff; | ||
| 341 | boolean allgray = true; | ||
| 342 | int transparency = OPAQUE; | ||
| 343 | for (int i = 0; i < size; i++) { | ||
| 344 | int r = cmap[j++] & 0xff; | ||
| 345 | int g = cmap[j++] & 0xff; | ||
| 346 | int b = cmap[j++] & 0xff; | ||
| 347 | allgray = allgray && (r == g) && (g == b); | ||
| 348 | if (hasalpha) { | ||
| 349 | alpha = cmap[j++] & 0xff; | ||
| 350 | if (alpha != 0xff) { | ||
| 351 | if (alpha == 0x00) { | ||
| 352 | if (transparency == OPAQUE) { | ||
| 353 | transparency = BITMASK; | ||
| 354 | } | ||
| 355 | if (transparent_index < 0) { | ||
| 356 | transparent_index = i; | ||
| 357 | } | ||
| 358 | } else { | ||
| 359 | transparency = TRANSLUCENT; | ||
| 360 | } | ||
| 361 | allgray = false; | ||
| 362 | } | ||
| 363 | } | ||
| 364 | rgb[i] = (alpha << 24) | (r << 16) | (g << 8) | b; | ||
| 365 | } | ||
| 366 | this.allgrayopaque = allgray; | ||
| 367 | setTransparency(transparency); | ||
| 368 | setTransparentPixel(trans); | ||
| 369 | calculatePixelMask(); | ||
| 370 | } | ||
| 371 | |||
| 372 | /** | ||
| 373 | * Constructs an <code>IndexColorModel</code> from an array of | ||
| 374 | * ints where each int is comprised of red, green, blue, and | ||
| 375 | * optional alpha components in the default RGB color model format. | ||
| 376 | * The specified transparent index represents a pixel that is made | ||
| 377 | * entirely transparent regardless of any alpha value specified | ||
| 378 | * for it. The array must have enough values in it to fill all | ||
| 379 | * of the needed component arrays of the specified size. | ||
| 380 | * The <code>ColorSpace</code> is the default sRGB space. | ||
| 381 | * The transparency value may be any of <code>Transparency.OPAQUE</code>, | ||
| 382 | * <code>Transparency.BITMASK</code>, | ||
| 383 | * or <code>Transparency.TRANSLUCENT</code> | ||
| 384 | * depending on the arguments, as specified | ||
| 385 | * in the <a href="#transparency">class description</a> above. | ||
| 386 | * @param bits the number of bits each pixel occupies | ||
| 387 | * @param size the size of the color component arrays | ||
| 388 | * @param cmap the array of color components | ||
| 389 | * @param start the starting offset of the first color component | ||
| 390 | * @param hasalpha indicates whether alpha values are contained in | ||
| 391 | * the <code>cmap</code> array | ||
| 392 | * @param trans the index of the fully transparent pixel | ||
| 393 | * @param transferType the data type of the array used to represent | ||
| 394 | * pixel values. The data type must be either | ||
| 395 | * <code>DataBuffer.TYPE_BYTE</code> or | ||
| 396 | * <code>DataBuffer.TYPE_USHORT</code>. | ||
| 397 | * @throws IllegalArgumentException if <code>bits</code> is less | ||
| 398 | * than 1 or greater than 16 | ||
| 399 | * @throws IllegalArgumentException if <code>size</code> is less | ||
| 400 | * than 1 | ||
| 401 | * @throws IllegalArgumentException if <code>transferType</code> is not | ||
| 402 | * one of <code>DataBuffer.TYPE_BYTE</code> or | ||
| 403 | * <code>DataBuffer.TYPE_USHORT</code> | ||
| 404 | */ | ||
| 405 | public IndexColorModel(int bits, int size, | ||
| 406 | int cmap[], int start, | ||
| 407 | boolean hasalpha, int trans, int transferType) { | ||
| 408 | // REMIND: This assumes the ordering: RGB[A] | ||
| 409 | super(bits, opaqueBits, | ||
| 410 | ColorSpace.getInstance(ColorSpace.CS_sRGB), | ||
| 411 | false, false, OPAQUE, | ||
| 412 | transferType); | ||
| 413 | |||
| 414 | if (bits < 1 || bits > 16) { | ||
| 415 | throw new IllegalArgumentException("Number of bits must be between" | ||
| 416 | +" 1 and 16."); | ||
| 417 | } | ||
| 418 | if (size < 1) { | ||
| 419 | throw new IllegalArgumentException("Map size ("+size+ | ||
| 420 | ") must be >= 1"); | ||
| 421 | } | ||
| 422 | if ((transferType != DataBuffer.TYPE_BYTE) && | ||
| 423 | (transferType != DataBuffer.TYPE_USHORT)) { | ||
| 424 | throw new IllegalArgumentException("transferType must be either" + | ||
| 425 | "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); | ||
| 426 | } | ||
| 427 | |||
| 428 | setRGBs(size, cmap, start, hasalpha); | ||
| 429 | setTransparentPixel(trans); | ||
| 430 | calculatePixelMask(); | ||
| 431 | } | ||
| 432 | |||
| 433 | /** | ||
| 434 | * Constructs an <code>IndexColorModel</code> from an | ||
| 435 | * <code>int</code> array where each <code>int</code> is | ||
| 436 | * comprised of red, green, blue, and alpha | ||
| 437 | * components in the default RGB color model format. | ||
| 438 | * The array must have enough values in it to fill all | ||
| 439 | * of the needed component arrays of the specified size. | ||
| 440 | * The <code>ColorSpace</code> is the default sRGB space. | ||
| 441 | * The transparency value may be any of <code>Transparency.OPAQUE</code>, | ||
| 442 | * <code>Transparency.BITMASK</code>, | ||
| 443 | * or <code>Transparency.TRANSLUCENT</code> | ||
| 444 | * depending on the arguments, as specified | ||
| 445 | * in the <a href="#transparency">class description</a> above. | ||
| 446 | * The transfer type must be one of <code>DataBuffer.TYPE_BYTE</code> | ||
| 447 | * <code>DataBuffer.TYPE_USHORT</code>. | ||
| 448 | * The <code>BigInteger</code> object specifies the valid/invalid pixels | ||
| 449 | * in the <code>cmap</code> array. A pixel is valid if the | ||
| 450 | * <code>BigInteger</code> value at that index is set, and is invalid | ||
| 451 | * if the <code>BigInteger</code> bit at that index is not set. | ||
| 452 | * @param bits the number of bits each pixel occupies | ||
| 453 | * @param size the size of the color component array | ||
| 454 | * @param cmap the array of color components | ||
| 455 | * @param start the starting offset of the first color component | ||
| 456 | * @param transferType the specified data type | ||
| 457 | * @param validBits a <code>BigInteger</code> object. If a bit is | ||
| 458 | * set in the BigInteger, the pixel at that index is valid. | ||
| 459 | * If a bit is not set, the pixel at that index | ||
| 460 | * is considered invalid. If null, all pixels are valid. | ||
| 461 | * Only bits from 0 to the map size are considered. | ||
| 462 | * @throws IllegalArgumentException if <code>bits</code> is less | ||
| 463 | * than 1 or greater than 16 | ||
| 464 | * @throws IllegalArgumentException if <code>size</code> is less | ||
| 465 | * than 1 | ||
| 466 | * @throws IllegalArgumentException if <code>transferType</code> is not | ||
| 467 | * one of <code>DataBuffer.TYPE_BYTE</code> or | ||
| 468 | * <code>DataBuffer.TYPE_USHORT</code> | ||
| 469 | * | ||
| 470 | * @since 1.3 | ||
| 471 | */ | ||
| 472 | public IndexColorModel(int bits, int size, int cmap[], int start, | ||
| 473 | int transferType, BigInteger validBits) { | ||
| 474 | super (bits, alphaBits, | ||
| 475 | ColorSpace.getInstance(ColorSpace.CS_sRGB), | ||
| 476 | true, false, TRANSLUCENT, | ||
| 477 | transferType); | ||
| 478 | |||
| 479 | if (bits < 1 || bits > 16) { | ||
| 480 | throw new IllegalArgumentException("Number of bits must be between" | ||
| 481 | +" 1 and 16."); | ||
| 482 | } | ||
| 483 | if (size < 1) { | ||
| 484 | throw new IllegalArgumentException("Map size ("+size+ | ||
| 485 | ") must be >= 1"); | ||
| 486 | } | ||
| 487 | if ((transferType != DataBuffer.TYPE_BYTE) && | ||
| 488 | (transferType != DataBuffer.TYPE_USHORT)) { | ||
| 489 | throw new IllegalArgumentException("transferType must be either" + | ||
| 490 | "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); | ||
| 491 | } | ||
| 492 | |||
| 493 | if (validBits != null) { | ||
| 494 | // Check to see if it is all valid | ||
| 495 | for (int i=0; i < size; i++) { | ||
| 496 | if (!validBits.testBit(i)) { | ||
| 497 | this.validBits = validBits; | ||
| 498 | break; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | setRGBs(size, cmap, start, true); | ||
| 504 | calculatePixelMask(); | ||
| 505 | } | ||
| 506 | |||
| 507 | private void setRGBs(int size, byte r[], byte g[], byte b[], byte a[]) { | ||
| 508 | if (size < 1) { | ||
| 509 | throw new IllegalArgumentException("Map size ("+size+ | ||
| 510 | ") must be >= 1"); | ||
| 511 | } | ||
| 512 | map_size = size; | ||
| 513 | rgb = new int[calcRealMapSize(pixel_bits, size)]; | ||
| 514 | int alpha = 0xff; | ||
| 515 | int transparency = OPAQUE; | ||
| 516 | boolean allgray = true; | ||
| 517 | for (int i = 0; i < size; i++) { | ||
| 518 | int rc = r[i] & 0xff; | ||
| 519 | int gc = g[i] & 0xff; | ||
| 520 | int bc = b[i] & 0xff; | ||
| 521 | allgray = allgray && (rc == gc) && (gc == bc); | ||
| 522 | if (a != null) { | ||
| 523 | alpha = a[i] & 0xff; | ||
| 524 | if (alpha != 0xff) { | ||
| 525 | if (alpha == 0x00) { | ||
| 526 | if (transparency == OPAQUE) { | ||
| 527 | transparency = BITMASK; | ||
| 528 | } | ||
| 529 | if (transparent_index < 0) { | ||
| 530 | transparent_index = i; | ||
| 531 | } | ||
| 532 | } else { | ||
| 533 | transparency = TRANSLUCENT; | ||
| 534 | } | ||
| 535 | allgray = false; | ||
| 536 | } | ||
| 537 | } | ||
| 538 | rgb[i] = (alpha << 24) | (rc << 16) | (gc << 8) | bc; | ||
| 539 | } | ||
| 540 | this.allgrayopaque = allgray; | ||
| 541 | setTransparency(transparency); | ||
| 542 | } | ||
| 543 | |||
| 544 | private void setRGBs(int size, int cmap[], int start, boolean hasalpha) { | ||
| 545 | map_size = size; | ||
| 546 | rgb = new int[calcRealMapSize(pixel_bits, size)]; | ||
| 547 | int j = start; | ||
| 548 | int transparency = OPAQUE; | ||
| 549 | boolean allgray = true; | ||
| 550 | BigInteger validBits = this.validBits; | ||
| 551 | for (int i = 0; i < size; i++, j++) { | ||
| 552 | if (validBits != null && !validBits.testBit(i)) { | ||
| 553 | continue; | ||
| 554 | } | ||
| 555 | int cmaprgb = cmap[j]; | ||
| 556 | int r = (cmaprgb >> 16) & 0xff; | ||
| 557 | int g = (cmaprgb >> 8) & 0xff; | ||
| 558 | int b = (cmaprgb ) & 0xff; | ||
| 559 | allgray = allgray && (r == g) && (g == b); | ||
| 560 | if (hasalpha) { | ||
| 561 | int alpha = cmaprgb >>> 24; | ||
| 562 | if (alpha != 0xff) { | ||
| 563 | if (alpha == 0x00) { | ||
| 564 | if (transparency == OPAQUE) { | ||
| 565 | transparency = BITMASK; | ||
| 566 | } | ||
| 567 | if (transparent_index < 0) { | ||
| 568 | transparent_index = i; | ||
| 569 | } | ||
| 570 | } else { | ||
| 571 | transparency = TRANSLUCENT; | ||
| 572 | } | ||
| 573 | allgray = false; | ||
| 574 | } | ||
| 575 | } else { | ||
| 576 | cmaprgb |= 0xff000000; | ||
| 577 | } | ||
| 578 | rgb[i] = cmaprgb; | ||
| 579 | } | ||
| 580 | this.allgrayopaque = allgray; | ||
| 581 | setTransparency(transparency); | ||
| 582 | } | ||
| 583 | |||
| 584 | private int calcRealMapSize(int bits, int size) { | ||
| 585 | int newSize = Math.max(1 << bits, size); | ||
| 586 | return Math.max(newSize, 256); | ||
| 587 | } | ||
| 588 | |||
| 589 | private BigInteger getAllValid() { | ||
| 590 | int numbytes = (map_size+7)/8; | ||
| 591 | byte[] valid = new byte[numbytes]; | ||
| 592 | java.util.Arrays.fill(valid, (byte)0xff); | ||
| 593 | valid[0] = (byte)(0xff >>> (numbytes*8 - map_size)); | ||
| 594 | |||
| 595 | return new BigInteger(1, valid); | ||
| 596 | } | ||
| 597 | |||
| 598 | /** | ||
| 599 | * Returns the transparency. Returns either OPAQUE, BITMASK, | ||
| 600 | * or TRANSLUCENT | ||
| 601 | * @return the transparency of this <code>IndexColorModel</code> | ||
| 602 | * @see Transparency#OPAQUE | ||
| 603 | * @see Transparency#BITMASK | ||
| 604 | * @see Transparency#TRANSLUCENT | ||
| 605 | */ | ||
| 606 | public int getTransparency() { | ||
| 607 | return transparency; | ||
| 608 | } | ||
| 609 | |||
| 610 | /** | ||
| 611 | * Returns an array of the number of bits for each color/alpha component. | ||
| 612 | * The array contains the color components in the order red, green, | ||
| 613 | * blue, followed by the alpha component, if present. | ||
| 614 | * @return an array containing the number of bits of each color | ||
| 615 | * and alpha component of this <code>IndexColorModel</code> | ||
| 616 | */ | ||
| 617 | public int[] getComponentSize() { | ||
| 618 | if (nBits == null) { | ||
| 619 | if (supportsAlpha) { | ||
| 620 | nBits = new int[4]; | ||
| 621 | nBits[3] = 8; | ||
| 622 | } | ||
| 623 | else { | ||
| 624 | nBits = new int[3]; | ||
| 625 | } | ||
| 626 | nBits[0] = nBits[1] = nBits[2] = 8; | ||
| 627 | } | ||
| 628 | return nBits.clone(); | ||
| 629 | } | ||
| 630 | |||
| 631 | /** | ||
| 632 | * Returns the size of the color/alpha component arrays in this | ||
| 633 | * <code>IndexColorModel</code>. | ||
| 634 | * @return the size of the color and alpha component arrays. | ||
| 635 | */ | ||
| 636 | final public int getMapSize() { | ||
| 637 | return map_size; | ||
| 638 | } | ||
| 639 | |||
| 640 | /** | ||
| 641 | * Returns the index of a transparent pixel in this | ||
| 642 | * <code>IndexColorModel</code> or -1 if there is no pixel | ||
| 643 | * with an alpha value of 0. If a transparent pixel was | ||
| 644 | * explicitly specified in one of the constructors by its | ||
| 645 | * index, then that index will be preferred, otherwise, | ||
| 646 | * the index of any pixel which happens to be fully transparent | ||
| 647 | * may be returned. | ||
| 648 | * @return the index of a transparent pixel in this | ||
| 649 | * <code>IndexColorModel</code> object, or -1 if there | ||
| 650 | * is no such pixel | ||
| 651 | */ | ||
| 652 | final public int getTransparentPixel() { | ||
| 653 | return transparent_index; | ||
| 654 | } | ||
| 655 | |||
| 656 | /** | ||
| 657 | * Copies the array of red color components into the specified array. | ||
| 658 | * Only the initial entries of the array as specified by | ||
| 659 | * {@link #getMapSize() getMapSize} are written. | ||
| 660 | * @param r the specified array into which the elements of the | ||
| 661 | * array of red color components are copied | ||
| 662 | */ | ||
| 663 | final public void getReds(byte r[]) { | ||
| 664 | for (int i = 0; i < map_size; i++) { | ||
| 665 | r[i] = (byte) (rgb[i] >> 16); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | |||
| 669 | /** | ||
| 670 | * Copies the array of green color components into the specified array. | ||
| 671 | * Only the initial entries of the array as specified by | ||
| 672 | * <code>getMapSize</code> are written. | ||
| 673 | * @param g the specified array into which the elements of the | ||
| 674 | * array of green color components are copied | ||
| 675 | */ | ||
| 676 | final public void getGreens(byte g[]) { | ||
| 677 | for (int i = 0; i < map_size; i++) { | ||
| 678 | g[i] = (byte) (rgb[i] >> 8); | ||
| 679 | } | ||
| 680 | } | ||
| 681 | |||
| 682 | /** | ||
| 683 | * Copies the array of blue color components into the specified array. | ||
| 684 | * Only the initial entries of the array as specified by | ||
| 685 | * <code>getMapSize</code> are written. | ||
| 686 | * @param b the specified array into which the elements of the | ||
| 687 | * array of blue color components are copied | ||
| 688 | */ | ||
| 689 | final public void getBlues(byte b[]) { | ||
| 690 | for (int i = 0; i < map_size; i++) { | ||
| 691 | b[i] = (byte) rgb[i]; | ||
| 692 | } | ||
| 693 | } | ||
| 694 | |||
| 695 | /** | ||
| 696 | * Copies the array of alpha transparency components into the | ||
| 697 | * specified array. Only the initial entries of the array as specified | ||
| 698 | * by <code>getMapSize</code> are written. | ||
| 699 | * @param a the specified array into which the elements of the | ||
| 700 | * array of alpha components are copied | ||
| 701 | */ | ||
| 702 | final public void getAlphas(byte a[]) { | ||
| 703 | for (int i = 0; i < map_size; i++) { | ||
| 704 | a[i] = (byte) (rgb[i] >> 24); | ||
| 705 | } | ||
| 706 | } | ||
| 707 | |||
| 708 | /** | ||
| 709 | * Converts data for each index from the color and alpha component | ||
| 710 | * arrays to an int in the default RGB ColorModel format and copies | ||
| 711 | * the resulting 32-bit ARGB values into the specified array. Only | ||
| 712 | * the initial entries of the array as specified by | ||
| 713 | * <code>getMapSize</code> are | ||
| 714 | * written. | ||
| 715 | * @param rgb the specified array into which the converted ARGB | ||
| 716 | * values from this array of color and alpha components | ||
| 717 | * are copied. | ||
| 718 | */ | ||
| 719 | final public void getRGBs(int rgb[]) { | ||
| 720 | System.arraycopy(this.rgb, 0, rgb, 0, map_size); | ||
| 721 | } | ||
| 722 | |||
| 723 | private void setTransparentPixel(int trans) { | ||
| 724 | if (trans >= 0 && trans < map_size) { | ||
| 725 | rgb[trans] &= 0x00ffffff; | ||
| 726 | transparent_index = trans; | ||
| 727 | allgrayopaque = false; | ||
| 728 | if (this.transparency == OPAQUE) { | ||
| 729 | setTransparency(BITMASK); | ||
| 730 | } | ||
| 731 | } | ||
| 732 | } | ||
| 733 | |||
| 734 | private void setTransparency(int transparency) { | ||
| 735 | if (this.transparency != transparency) { | ||
| 736 | this.transparency = transparency; | ||
| 737 | if (transparency == OPAQUE) { | ||
| 738 | supportsAlpha = false; | ||
| 739 | numComponents = 3; | ||
| 740 | nBits = opaqueBits; | ||
| 741 | } else { | ||
| 742 | supportsAlpha = true; | ||
| 743 | numComponents = 4; | ||
| 744 | nBits = alphaBits; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | } | ||
| 748 | |||
| 749 | /** | ||
| 750 | * This method is called from the constructors to set the pixel_mask | ||
| 751 | * value, which is based on the value of pixel_bits. The pixel_mask | ||
| 752 | * value is used to mask off the pixel parameters for methods such | ||
| 753 | * as getRed(), getGreen(), getBlue(), getAlpha(), and getRGB(). | ||
| 754 | */ | ||
| 755 | private final void calculatePixelMask() { | ||
| 756 | // Note that we adjust the mask so that our masking behavior here | ||
| 757 | // is consistent with that of our native rendering loops. | ||
| 758 | int maskbits = pixel_bits; | ||
| 759 | if (maskbits == 3) { | ||
| 760 | maskbits = 4; | ||
| 761 | } else if (maskbits > 4 && maskbits < 8) { | ||
| 762 | maskbits = 8; | ||
| 763 | } | ||
| 764 | pixel_mask = (1 << maskbits) - 1; | ||
| 765 | } | ||
| 766 | |||
| 767 | /** | ||
| 768 | * Returns the red color component for the specified pixel, scaled | ||
| 769 | * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value | ||
| 770 | * is specified as an int. | ||
| 771 | * Only the lower <em>n</em> bits of the pixel value, as specified in the | ||
| 772 | * <a href="#index_values">class description</a> above, are used to | ||
| 773 | * calculate the returned value. | ||
| 774 | * The returned value is a non pre-multiplied value. | ||
| 775 | * @param pixel the specified pixel | ||
| 776 | * @return the value of the red color component for the specified pixel | ||
| 777 | */ | ||
| 778 | final public int getRed(int pixel) { | ||
| 779 | return (rgb[pixel & pixel_mask] >> 16) & 0xff; | ||
| 780 | } | ||
| 781 | |||
| 782 | /** | ||
| 783 | * Returns the green color component for the specified pixel, scaled | ||
| 784 | * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value | ||
| 785 | * is specified as an int. | ||
| 786 | * Only the lower <em>n</em> bits of the pixel value, as specified in the | ||
| 787 | * <a href="#index_values">class description</a> above, are used to | ||
| 788 | * calculate the returned value. | ||
| 789 | * The returned value is a non pre-multiplied value. | ||
| 790 | * @param pixel the specified pixel | ||
| 791 | * @return the value of the green color component for the specified pixel | ||
| 792 | */ | ||
| 793 | final public int getGreen(int pixel) { | ||
| 794 | return (rgb[pixel & pixel_mask] >> 8) & 0xff; | ||
| 795 | } | ||
| 796 | |||
| 797 | /** | ||
| 798 | * Returns the blue color component for the specified pixel, scaled | ||
| 799 | * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value | ||
| 800 | * is specified as an int. | ||
| 801 | * Only the lower <em>n</em> bits of the pixel value, as specified in the | ||
| 802 | * <a href="#index_values">class description</a> above, are used to | ||
| 803 | * calculate the returned value. | ||
| 804 | * The returned value is a non pre-multiplied value. | ||
| 805 | * @param pixel the specified pixel | ||
| 806 | * @return the value of the blue color component for the specified pixel | ||
| 807 | */ | ||
| 808 | final public int getBlue(int pixel) { | ||
| 809 | return rgb[pixel & pixel_mask] & 0xff; | ||
| 810 | } | ||
| 811 | |||
| 812 | /** | ||
| 813 | * Returns the alpha component for the specified pixel, scaled | ||
| 814 | * from 0 to 255. The pixel value is specified as an int. | ||
| 815 | * Only the lower <em>n</em> bits of the pixel value, as specified in the | ||
| 816 | * <a href="#index_values">class description</a> above, are used to | ||
| 817 | * calculate the returned value. | ||
| 818 | * @param pixel the specified pixel | ||
| 819 | * @return the value of the alpha component for the specified pixel | ||
| 820 | */ | ||
| 821 | final public int getAlpha(int pixel) { | ||
| 822 | return (rgb[pixel & pixel_mask] >> 24) & 0xff; | ||
| 823 | } | ||
| 824 | |||
| 825 | /** | ||
| 826 | * Returns the color/alpha components of the pixel in the default | ||
| 827 | * RGB color model format. The pixel value is specified as an int. | ||
| 828 | * Only the lower <em>n</em> bits of the pixel value, as specified in the | ||
| 829 | * <a href="#index_values">class description</a> above, are used to | ||
| 830 | * calculate the returned value. | ||
| 831 | * The returned value is in a non pre-multiplied format. | ||
| 832 | * @param pixel the specified pixel | ||
| 833 | * @return the color and alpha components of the specified pixel | ||
| 834 | * @see ColorModel#getRGBdefault | ||
| 835 | */ | ||
| 836 | final public int getRGB(int pixel) { | ||
| 837 | return rgb[pixel & pixel_mask]; | ||
| 838 | } | ||
| 839 | |||
| 840 | private static final int CACHESIZE = 40; | ||
| 841 | private int lookupcache[] = new int[CACHESIZE]; | ||
| 842 | |||
| 843 | /** | ||
| 844 | * Returns a data element array representation of a pixel in this | ||
| 845 | * ColorModel, given an integer pixel representation in the | ||
| 846 | * default RGB color model. This array can then be passed to the | ||
| 847 | * {@link WritableRaster#setDataElements(int, int, java.lang.Object) setDataElements} | ||
| 848 | * method of a {@link WritableRaster} object. If the pixel variable is | ||
| 849 | * <code>null</code>, a new array is allocated. If <code>pixel</code> | ||
| 850 | * is not <code>null</code>, it must be | ||
| 851 | * a primitive array of type <code>transferType</code>; otherwise, a | ||
| 852 | * <code>ClassCastException</code> is thrown. An | ||
| 853 | * <code>ArrayIndexOutOfBoundsException</code> is | ||
| 854 | * thrown if <code>pixel</code> is not large enough to hold a pixel | ||
| 855 | * value for this <code>ColorModel</code>. The pixel array is returned. | ||
| 856 | * <p> | ||
| 857 | * Since <code>IndexColorModel</code> can be subclassed, subclasses | ||
| 858 | * inherit the implementation of this method and if they don't | ||
| 859 | * override it then they throw an exception if they use an | ||
| 860 | * unsupported <code>transferType</code>. | ||
| 861 | * | ||
| 862 | * @param rgb the integer pixel representation in the default RGB | ||
| 863 | * color model | ||
| 864 | * @param pixel the specified pixel | ||
| 865 | * @return an array representation of the specified pixel in this | ||
| 866 | * <code>IndexColorModel</code>. | ||
| 867 | * @throws ClassCastException if <code>pixel</code> | ||
| 868 | * is not a primitive array of type <code>transferType</code> | ||
| 869 | * @throws ArrayIndexOutOfBoundsException if | ||
| 870 | * <code>pixel</code> is not large enough to hold a pixel value | ||
| 871 | * for this <code>ColorModel</code> | ||
| 872 | * @throws UnsupportedOperationException if <code>transferType</code> | ||
| 873 | * is invalid | ||
| 874 | * @see WritableRaster#setDataElements | ||
| 875 | * @see SampleModel#setDataElements | ||
| 876 | */ | ||
| 877 | public synchronized Object getDataElements(int rgb, Object pixel) { | ||
| 878 | int red = (rgb>>16) & 0xff; | ||
| 879 | int green = (rgb>>8) & 0xff; | ||
| 880 | int blue = rgb & 0xff; | ||
| 881 | int alpha = (rgb>>>24); | ||
| 882 | int pix = 0; | ||
| 883 | |||
| 884 | // Note that pixels are stored at lookupcache[2*i] | ||
| 885 | // and the rgb that was searched is stored at | ||
| 886 | // lookupcache[2*i+1]. Also, the pixel is first | ||
| 887 | // inverted using the unary complement operator | ||
| 888 | // before storing in the cache so it can never be 0. | ||
| 889 | for (int i = CACHESIZE - 2; i >= 0; i -= 2) { | ||
| 890 | if ((pix = lookupcache[i]) == 0) { | ||
| 891 | break; | ||
| 892 | } | ||
| 893 | if (rgb == lookupcache[i+1]) { | ||
| 894 | return installpixel(pixel, ~pix); | ||
| 895 | } | ||
| 896 | } | ||
| 897 | |||
| 898 | if (allgrayopaque) { | ||
| 899 | // IndexColorModel objects are all tagged as | ||
| 900 | // non-premultiplied so ignore the alpha value | ||
| 901 | // of the incoming color, convert the | ||
| 902 | // non-premultiplied color components to a | ||
| 903 | // grayscale value and search for the closest | ||
| 904 | // gray value in the palette. Since all colors | ||
| 905 | // in the palette are gray, we only need compare | ||
| 906 | // to one of the color components for a match | ||
| 907 | // using a simple linear distance formula. | ||
| 908 | |||
| 909 | int minDist = 256; | ||
| 910 | int d; | ||
| 911 | int gray = (int) (red*77 + green*150 + blue*29 + 128)/256; | ||
| 912 | |||
| 913 | for (int i = 0; i < map_size; i++) { | ||
| 914 | if (this.rgb[i] == 0x0) { | ||
| 915 | // For allgrayopaque colormaps, entries are 0 | ||
| 916 | // iff they are an invalid color and should be | ||
| 917 | // ignored during color searches. | ||
| 918 | continue; | ||
| 919 | } | ||
| 920 | d = (this.rgb[i] & 0xff) - gray; | ||
| 921 | if (d < 0) d = -d; | ||
| 922 | if (d < minDist) { | ||
| 923 | pix = i; | ||
| 924 | if (d == 0) { | ||
| 925 | break; | ||
| 926 | } | ||
| 927 | minDist = d; | ||
| 928 | } | ||
| 929 | } | ||
| 930 | } else if (transparency == OPAQUE) { | ||
| 931 | // IndexColorModel objects are all tagged as | ||
| 932 | // non-premultiplied so ignore the alpha value | ||
| 933 | // of the incoming color and search for closest | ||
| 934 | // color match independently using a 3 component | ||
| 935 | // Euclidean distance formula. | ||
| 936 | // For opaque colormaps, palette entries are 0 | ||
| 937 | // iff they are an invalid color and should be | ||
| 938 | // ignored during color searches. | ||
| 939 | // As an optimization, exact color searches are | ||
| 940 | // likely to be fairly common in opaque colormaps | ||
| 941 | // so first we will do a quick search for an | ||
| 942 | // exact match. | ||
| 943 | |||
| 944 | int smallestError = Integer.MAX_VALUE; | ||
| 945 | int lut[] = this.rgb; | ||
| 946 | int lutrgb; | ||
| 947 | for (int i=0; i < map_size; i++) { | ||
| 948 | lutrgb = lut[i]; | ||
| 949 | if (lutrgb == rgb && lutrgb != 0) { | ||
| 950 | pix = i; | ||
| 951 | smallestError = 0; | ||
| 952 | break; | ||
| 953 | } | ||
| 954 | } | ||
| 955 | |||
| 956 | if (smallestError != 0) { | ||
| 957 | for (int i=0; i < map_size; i++) { | ||
| 958 | lutrgb = lut[i]; | ||
| 959 | if (lutrgb == 0) { | ||
| 960 | continue; | ||
| 961 | } | ||
| 962 | |||
| 963 | int tmp = ((lutrgb >> 16) & 0xff) - red; | ||
| 964 | int currentError = tmp*tmp; | ||
| 965 | if (currentError < smallestError) { | ||
| 966 | tmp = ((lutrgb >> 8) & 0xff) - green; | ||
| 967 | currentError += tmp * tmp; | ||
| 968 | if (currentError < smallestError) { | ||
| 969 | tmp = (lutrgb & 0xff) - blue; | ||
| 970 | currentError += tmp * tmp; | ||
| 971 | if (currentError < smallestError) { | ||
| 972 | pix = i; | ||
| 973 | smallestError = currentError; | ||
| 974 | } | ||
| 975 | } | ||
| 976 | } | ||
| 977 | } | ||
| 978 | } | ||
| 979 | } else if (alpha == 0 && transparent_index >= 0) { | ||
| 980 | // Special case - transparent color maps to the | ||
| 981 | // specified transparent pixel, if there is one | ||
| 982 | |||
| 983 | pix = transparent_index; | ||
| 984 | } else { | ||
| 985 | // IndexColorModel objects are all tagged as | ||
| 986 | // non-premultiplied so use non-premultiplied | ||
| 987 | // color components in the distance calculations. | ||
| 988 | // Look for closest match using a 4 component | ||
| 989 | // Euclidean distance formula. | ||
| 990 | |||
| 991 | int smallestError = Integer.MAX_VALUE; | ||
| 992 | int lut[] = this.rgb; | ||
| 993 | for (int i=0; i < map_size; i++) { | ||
| 994 | int lutrgb = lut[i]; | ||
| 995 | if (lutrgb == rgb) { | ||
| 996 | if (validBits != null && !validBits.testBit(i)) { | ||
| 997 | continue; | ||
| 998 | } | ||
| 999 | pix = i; | ||
| 1000 | break; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | int tmp = ((lutrgb >> 16) & 0xff) - red; | ||
| 1004 | int currentError = tmp*tmp; | ||
| 1005 | if (currentError < smallestError) { | ||
| 1006 | tmp = ((lutrgb >> 8) & 0xff) - green; | ||
| 1007 | currentError += tmp * tmp; | ||
| 1008 | if (currentError < smallestError) { | ||
| 1009 | tmp = (lutrgb & 0xff) - blue; | ||
| 1010 | currentError += tmp * tmp; | ||
| 1011 | if (currentError < smallestError) { | ||
| 1012 | tmp = (lutrgb >>> 24) - alpha; | ||
| 1013 | currentError += tmp * tmp; | ||
| 1014 | if (currentError < smallestError && | ||
| 1015 | (validBits == null || validBits.testBit(i))) | ||
| 1016 | { | ||
| 1017 | pix = i; | ||
| 1018 | smallestError = currentError; | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | } | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | System.arraycopy(lookupcache, 2, lookupcache, 0, CACHESIZE - 2); | ||
| 1026 | lookupcache[CACHESIZE - 1] = rgb; | ||
| 1027 | lookupcache[CACHESIZE - 2] = ~pix; | ||
| 1028 | return installpixel(pixel, pix); | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | private Object installpixel(Object pixel, int pix) { | ||
| 1032 | switch (transferType) { | ||
| 1033 | case DataBuffer.TYPE_INT: | ||
| 1034 | int[] intObj; | ||
| 1035 | if (pixel == null) { | ||
| 1036 | pixel = intObj = new int[1]; | ||
| 1037 | } else { | ||
| 1038 | intObj = (int[]) pixel; | ||
| 1039 | } | ||
| 1040 | intObj[0] = pix; | ||
| 1041 | break; | ||
| 1042 | case DataBuffer.TYPE_BYTE: | ||
| 1043 | byte[] byteObj; | ||
| 1044 | if (pixel == null) { | ||
| 1045 | pixel = byteObj = new byte[1]; | ||
| 1046 | } else { | ||
| 1047 | byteObj = (byte[]) pixel; | ||
| 1048 | } | ||
| 1049 | byteObj[0] = (byte) pix; | ||
| 1050 | break; | ||
| 1051 | case DataBuffer.TYPE_USHORT: | ||
| 1052 | short[] shortObj; | ||
| 1053 | if (pixel == null) { | ||
| 1054 | pixel = shortObj = new short[1]; | ||
| 1055 | } else { | ||
| 1056 | shortObj = (short[]) pixel; | ||
| 1057 | } | ||
| 1058 | shortObj[0] = (short) pix; | ||
| 1059 | break; | ||
| 1060 | default: | ||
| 1061 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 1062 | "implemented for transferType " + transferType); | ||
| 1063 | } | ||
| 1064 | return pixel; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | /** | ||
| 1068 | * Returns an array of unnormalized color/alpha components for a | ||
| 1069 | * specified pixel in this <code>ColorModel</code>. The pixel value | ||
| 1070 | * is specified as an int. If the <code>components</code> array is <code>null</code>, | ||
| 1071 | * a new array is allocated that contains | ||
| 1072 | * <code>offset + getNumComponents()</code> elements. | ||
| 1073 | * The <code>components</code> array is returned, | ||
| 1074 | * with the alpha component included | ||
| 1075 | * only if <code>hasAlpha</code> returns true. | ||
| 1076 | * Color/alpha components are stored in the <code>components</code> array starting | ||
| 1077 | * at <code>offset</code> even if the array is allocated by this method. | ||
| 1078 | * An <code>ArrayIndexOutOfBoundsException</code> | ||
| 1079 | * is thrown if the <code>components</code> array is not <code>null</code> and is | ||
| 1080 | * not large enough to hold all the color and alpha components | ||
| 1081 | * starting at <code>offset</code>. | ||
| 1082 | * @param pixel the specified pixel | ||
| 1083 | * @param components the array to receive the color and alpha | ||
| 1084 | * components of the specified pixel | ||
| 1085 | * @param offset the offset into the <code>components</code> array at | ||
| 1086 | * which to start storing the color and alpha components | ||
| 1087 | * @return an array containing the color and alpha components of the | ||
| 1088 | * specified pixel starting at the specified offset. | ||
| 1089 | * @see ColorModel#hasAlpha | ||
| 1090 | * @see ColorModel#getNumComponents | ||
| 1091 | */ | ||
| 1092 | public int[] getComponents(int pixel, int[] components, int offset) { | ||
| 1093 | if (components == null) { | ||
| 1094 | components = new int[offset+numComponents]; | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | // REMIND: Needs to change if different color space | ||
| 1098 | components[offset+0] = getRed(pixel); | ||
| 1099 | components[offset+1] = getGreen(pixel); | ||
| 1100 | components[offset+2] = getBlue(pixel); | ||
| 1101 | if (supportsAlpha && (components.length-offset) > 3) { | ||
| 1102 | components[offset+3] = getAlpha(pixel); | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | return components; | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | /** | ||
| 1109 | * Returns an array of unnormalized color/alpha components for | ||
| 1110 | * a specified pixel in this <code>ColorModel</code>. The pixel | ||
| 1111 | * value is specified by an array of data elements of type | ||
| 1112 | * <code>transferType</code> passed in as an object reference. | ||
| 1113 | * If <code>pixel</code> is not a primitive array of type | ||
| 1114 | * <code>transferType</code>, a <code>ClassCastException</code> | ||
| 1115 | * is thrown. An <code>ArrayIndexOutOfBoundsException</code> | ||
| 1116 | * is thrown if <code>pixel</code> is not large enough to hold | ||
| 1117 | * a pixel value for this <code>ColorModel</code>. If the | ||
| 1118 | * <code>components</code> array is <code>null</code>, a new array | ||
| 1119 | * is allocated that contains | ||
| 1120 | * <code>offset + getNumComponents()</code> elements. | ||
| 1121 | * The <code>components</code> array is returned, | ||
| 1122 | * with the alpha component included | ||
| 1123 | * only if <code>hasAlpha</code> returns true. | ||
| 1124 | * Color/alpha components are stored in the <code>components</code> | ||
| 1125 | * array starting at <code>offset</code> even if the array is | ||
| 1126 | * allocated by this method. An | ||
| 1127 | * <code>ArrayIndexOutOfBoundsException</code> is also | ||
| 1128 | * thrown if the <code>components</code> array is not | ||
| 1129 | * <code>null</code> and is not large enough to hold all the color | ||
| 1130 | * and alpha components starting at <code>offset</code>. | ||
| 1131 | * <p> | ||
| 1132 | * Since <code>IndexColorModel</code> can be subclassed, subclasses | ||
| 1133 | * inherit the implementation of this method and if they don't | ||
| 1134 | * override it then they throw an exception if they use an | ||
| 1135 | * unsupported <code>transferType</code>. | ||
| 1136 | * | ||
| 1137 | * @param pixel the specified pixel | ||
| 1138 | * @param components an array that receives the color and alpha | ||
| 1139 | * components of the specified pixel | ||
| 1140 | * @param offset the index into the <code>components</code> array at | ||
| 1141 | * which to begin storing the color and alpha components of the | ||
| 1142 | * specified pixel | ||
| 1143 | * @return an array containing the color and alpha components of the | ||
| 1144 | * specified pixel starting at the specified offset. | ||
| 1145 | * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> | ||
| 1146 | * is not large enough to hold a pixel value for this | ||
| 1147 | * <code>ColorModel</code> or if the | ||
| 1148 | * <code>components</code> array is not <code>null</code> | ||
| 1149 | * and is not large enough to hold all the color | ||
| 1150 | * and alpha components starting at <code>offset</code> | ||
| 1151 | * @throws ClassCastException if <code>pixel</code> is not a | ||
| 1152 | * primitive array of type <code>transferType</code> | ||
| 1153 | * @throws UnsupportedOperationException if <code>transferType</code> | ||
| 1154 | * is not one of the supported transer types | ||
| 1155 | * @see ColorModel#hasAlpha | ||
| 1156 | * @see ColorModel#getNumComponents | ||
| 1157 | */ | ||
| 1158 | public int[] getComponents(Object pixel, int[] components, int offset) { | ||
| 1159 | int intpixel; | ||
| 1160 | switch (transferType) { | ||
| 1161 | case DataBuffer.TYPE_BYTE: | ||
| 1162 | byte bdata[] = (byte[])pixel; | ||
| 1163 | intpixel = bdata[0] & 0xff; | ||
| 1164 | break; | ||
| 1165 | case DataBuffer.TYPE_USHORT: | ||
| 1166 | short sdata[] = (short[])pixel; | ||
| 1167 | intpixel = sdata[0] & 0xffff; | ||
| 1168 | break; | ||
| 1169 | case DataBuffer.TYPE_INT: | ||
| 1170 | int idata[] = (int[])pixel; | ||
| 1171 | intpixel = idata[0]; | ||
| 1172 | break; | ||
| 1173 | default: | ||
| 1174 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 1175 | "implemented for transferType " + transferType); | ||
| 1176 | } | ||
| 1177 | return getComponents(intpixel, components, offset); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | /** | ||
| 1181 | * Returns a pixel value represented as an int in this | ||
| 1182 | * <code>ColorModel</code> given an array of unnormalized | ||
| 1183 | * color/alpha components. An | ||
| 1184 | * <code>ArrayIndexOutOfBoundsException</code> | ||
| 1185 | * is thrown if the <code>components</code> array is not large | ||
| 1186 | * enough to hold all of the color and alpha components starting | ||
| 1187 | * at <code>offset</code>. Since | ||
| 1188 | * <code>ColorModel</code> can be subclassed, subclasses inherit the | ||
| 1189 | * implementation of this method and if they don't override it then | ||
| 1190 | * they throw an exception if they use an unsupported transferType. | ||
| 1191 | * @param components an array of unnormalized color and alpha | ||
| 1192 | * components | ||
| 1193 | * @param offset the index into <code>components</code> at which to | ||
| 1194 | * begin retrieving the color and alpha components | ||
| 1195 | * @return an <code>int</code> pixel value in this | ||
| 1196 | * <code>ColorModel</code> corresponding to the specified components. | ||
| 1197 | * @throws ArrayIndexOutOfBoundsException if | ||
| 1198 | * the <code>components</code> array is not large enough to | ||
| 1199 | * hold all of the color and alpha components starting at | ||
| 1200 | * <code>offset</code> | ||
| 1201 | * @throws UnsupportedOperationException if <code>transferType</code> | ||
| 1202 | * is invalid | ||
| 1203 | */ | ||
| 1204 | public int getDataElement(int[] components, int offset) { | ||
| 1205 | int rgb = (components[offset+0]<<16) | ||
| 1206 | | (components[offset+1]<<8) | (components[offset+2]); | ||
| 1207 | if (supportsAlpha) { | ||
| 1208 | rgb |= (components[offset+3]<<24); | ||
| 1209 | } | ||
| 1210 | else { | ||
| 1211 | rgb |= 0xff000000; | ||
| 1212 | } | ||
| 1213 | Object inData = getDataElements(rgb, null); | ||
| 1214 | int pixel; | ||
| 1215 | switch (transferType) { | ||
| 1216 | case DataBuffer.TYPE_BYTE: | ||
| 1217 | byte bdata[] = (byte[])inData; | ||
| 1218 | pixel = bdata[0] & 0xff; | ||
| 1219 | break; | ||
| 1220 | case DataBuffer.TYPE_USHORT: | ||
| 1221 | short sdata[] = (short[])inData; | ||
| 1222 | pixel = sdata[0]; | ||
| 1223 | break; | ||
| 1224 | case DataBuffer.TYPE_INT: | ||
| 1225 | int idata[] = (int[])inData; | ||
| 1226 | pixel = idata[0]; | ||
| 1227 | break; | ||
| 1228 | default: | ||
| 1229 | throw new UnsupportedOperationException("This method has not been "+ | ||
| 1230 | "implemented for transferType " + transferType); | ||
| 1231 | } | ||
| 1232 | return pixel; | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | /** | ||
| 1236 | * Returns a data element array representation of a pixel in this | ||
| 1237 | * <code>ColorModel</code> given an array of unnormalized color/alpha | ||
| 1238 | * components. This array can then be passed to the | ||
| 1239 | * <code>setDataElements</code> method of a <code>WritableRaster</code> | ||
| 1240 | * object. An <code>ArrayIndexOutOfBoundsException</code> is | ||
| 1241 | * thrown if the | ||
| 1242 | * <code>components</code> array is not large enough to hold all of the | ||
| 1243 | * color and alpha components starting at <code>offset</code>. | ||
| 1244 | * If the pixel variable is <code>null</code>, a new array | ||
| 1245 | * is allocated. If <code>pixel</code> is not <code>null</code>, | ||
| 1246 | * it must be a primitive array of type <code>transferType</code>; | ||
| 1247 | * otherwise, a <code>ClassCastException</code> is thrown. | ||
| 1248 | * An <code>ArrayIndexOutOfBoundsException</code> is thrown if pixel | ||
| 1249 | * is not large enough to hold a pixel value for this | ||
| 1250 | * <code>ColorModel</code>. | ||
| 1251 | * <p> | ||
| 1252 | * Since <code>IndexColorModel</code> can be subclassed, subclasses | ||
| 1253 | * inherit the implementation of this method and if they don't | ||
| 1254 | * override it then they throw an exception if they use an | ||
| 1255 | * unsupported <code>transferType</code> | ||
| 1256 | * | ||
| 1257 | * @param components an array of unnormalized color and alpha | ||
| 1258 | * components | ||
| 1259 | * @param offset the index into <code>components</code> at which to | ||
| 1260 | * begin retrieving color and alpha components | ||
| 1261 | * @param pixel the <code>Object</code> representing an array of color | ||
| 1262 | * and alpha components | ||
| 1263 | * @return an <code>Object</code> representing an array of color and | ||
| 1264 | * alpha components. | ||
| 1265 | * @throws ClassCastException if <code>pixel</code> | ||
| 1266 | * is not a primitive array of type <code>transferType</code> | ||
| 1267 | * @throws ArrayIndexOutOfBoundsException if | ||
| 1268 | * <code>pixel</code> is not large enough to hold a pixel value | ||
| 1269 | * for this <code>ColorModel</code> or the <code>components</code> | ||
| 1270 | * array is not large enough to hold all of the color and alpha | ||
| 1271 | * components starting at <code>offset</code> | ||
| 1272 | * @throws UnsupportedOperationException if <code>transferType</code> | ||
| 1273 | * is not one of the supported transer types | ||
| 1274 | * @see WritableRaster#setDataElements | ||
| 1275 | * @see SampleModel#setDataElements | ||
| 1276 | */ | ||
| 1277 | public Object getDataElements(int[] components, int offset, Object pixel) { | ||
| 1278 | int rgb = (components[offset+0]<<16) | (components[offset+1]<<8) | ||
| 1279 | | (components[offset+2]); | ||
| 1280 | if (supportsAlpha) { | ||
| 1281 | rgb |= (components[offset+3]<<24); | ||
| 1282 | } | ||
| 1283 | else { | ||
| 1284 | rgb &= 0xff000000; | ||
| 1285 | } | ||
| 1286 | return getDataElements(rgb, pixel); | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | /** | ||
| 1290 | * Creates a <code>WritableRaster</code> with the specified width | ||
| 1291 | * and height that has a data layout (<code>SampleModel</code>) | ||
| 1292 | * compatible with this <code>ColorModel</code>. This method | ||
| 1293 | * only works for color models with 16 or fewer bits per pixel. | ||
| 1294 | * <p> | ||
| 1295 | * Since <code>IndexColorModel</code> can be subclassed, any | ||
| 1296 | * subclass that supports greater than 16 bits per pixel must | ||
| 1297 | * override this method. | ||
| 1298 | * | ||
| 1299 | * @param w the width to apply to the new <code>WritableRaster</code> | ||
| 1300 | * @param h the height to apply to the new <code>WritableRaster</code> | ||
| 1301 | * @return a <code>WritableRaster</code> object with the specified | ||
| 1302 | * width and height. | ||
| 1303 | * @throws UnsupportedOperationException if the number of bits in a | ||
| 1304 | * pixel is greater than 16 | ||
| 1305 | * @see WritableRaster | ||
| 1306 | * @see SampleModel | ||
| 1307 | */ | ||
| 1308 | public WritableRaster createCompatibleWritableRaster(int w, int h) { | ||
| 1309 | WritableRaster raster; | ||
| 1310 | |||
| 1311 | if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { | ||
| 1312 | // TYPE_BINARY | ||
| 1313 | raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, | ||
| 1314 | w, h, 1, pixel_bits, null); | ||
| 1315 | } | ||
| 1316 | else if (pixel_bits <= 8) { | ||
| 1317 | raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, | ||
| 1318 | w,h,1,null); | ||
| 1319 | } | ||
| 1320 | else if (pixel_bits <= 16) { | ||
| 1321 | raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, | ||
| 1322 | w,h,1,null); | ||
| 1323 | } | ||
| 1324 | else { | ||
| 1325 | throw new | ||
| 1326 | UnsupportedOperationException("This method is not supported "+ | ||
| 1327 | " for pixel bits > 16."); | ||
| 1328 | } | ||
| 1329 | return raster; | ||
| 1330 | } | ||
| 1331 | |||
| 1332 | /** | ||
| 1333 | * Returns <code>true</code> if <code>raster</code> is compatible | ||
| 1334 | * with this <code>ColorModel</code> or <code>false</code> if it | ||
| 1335 | * is not compatible with this <code>ColorModel</code>. | ||
| 1336 | * @param raster the {@link Raster} object to test for compatibility | ||
| 1337 | * @return <code>true</code> if <code>raster</code> is compatible | ||
| 1338 | * with this <code>ColorModel</code>; <code>false</code> otherwise. | ||
| 1339 | * | ||
| 1340 | */ | ||
| 1341 | public boolean isCompatibleRaster(Raster raster) { | ||
| 1342 | |||
| 1343 | int size = raster.getSampleModel().getSampleSize(0); | ||
| 1344 | return ((raster.getTransferType() == transferType) && | ||
| 1345 | (raster.getNumBands() == 1) && ((1 << size) >= map_size)); | ||
| 1346 | } | ||
| 1347 | |||
| 1348 | /** | ||
| 1349 | * Creates a <code>SampleModel</code> with the specified | ||
| 1350 | * width and height that has a data layout compatible with | ||
| 1351 | * this <code>ColorModel</code>. | ||
| 1352 | * @param w the width to apply to the new <code>SampleModel</code> | ||
| 1353 | * @param h the height to apply to the new <code>SampleModel</code> | ||
| 1354 | * @return a <code>SampleModel</code> object with the specified | ||
| 1355 | * width and height. | ||
| 1356 | * @throws IllegalArgumentException if <code>w</code> or | ||
| 1357 | * <code>h</code> is not greater than 0 | ||
| 1358 | * @see SampleModel | ||
| 1359 | */ | ||
| 1360 | public SampleModel createCompatibleSampleModel(int w, int h) { | ||
| 1361 | int[] off = new int[1]; | ||
| 1362 | off[0] = 0; | ||
| 1363 | if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { | ||
| 1364 | return new MultiPixelPackedSampleModel(transferType, w, h, | ||
| 1365 | pixel_bits); | ||
| 1366 | } | ||
| 1367 | else { | ||
| 1368 | return new ComponentSampleModel(transferType, w, h, 1, w, | ||
| 1369 | off); | ||
| 1370 | } | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | /** | ||
| 1374 | * Checks if the specified <code>SampleModel</code> is compatible | ||
| 1375 | * with this <code>ColorModel</code>. If <code>sm</code> is | ||
| 1376 | * <code>null</code>, this method returns <code>false</code>. | ||
| 1377 | * @param sm the specified <code>SampleModel</code>, | ||
| 1378 | * or <code>null</code> | ||
| 1379 | * @return <code>true</code> if the specified <code>SampleModel</code> | ||
| 1380 | * is compatible with this <code>ColorModel</code>; <code>false</code> | ||
| 1381 | * otherwise. | ||
| 1382 | * @see SampleModel | ||
| 1383 | */ | ||
| 1384 | public boolean isCompatibleSampleModel(SampleModel sm) { | ||
| 1385 | // fix 4238629 | ||
| 1386 | if (! (sm instanceof ComponentSampleModel) && | ||
| 1387 | ! (sm instanceof MultiPixelPackedSampleModel) ) { | ||
| 1388 | return false; | ||
| 1389 | } | ||
| 1390 | |||
| 1391 | // Transfer type must be the same | ||
| 1392 | if (sm.getTransferType() != transferType) { | ||
| 1393 | return false; | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | if (sm.getNumBands() != 1) { | ||
| 1397 | return false; | ||
| 1398 | } | ||
| 1399 | |||
| 1400 | return true; | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | /** | ||
| 1404 | * Returns a new <code>BufferedImage</code> of TYPE_INT_ARGB or | ||
| 1405 | * TYPE_INT_RGB that has a <code>Raster</code> with pixel data | ||
| 1406 | * computed by expanding the indices in the source <code>Raster</code> | ||
| 1407 | * using the color/alpha component arrays of this <code>ColorModel</code>. | ||
| 1408 | * Only the lower <em>n</em> bits of each index value in the source | ||
| 1409 | * <code>Raster</code>, as specified in the | ||
| 1410 | * <a href="#index_values">class description</a> above, are used to | ||
| 1411 | * compute the color/alpha values in the returned image. | ||
| 1412 | * If <code>forceARGB</code> is <code>true</code>, a TYPE_INT_ARGB image is | ||
| 1413 | * returned regardless of whether or not this <code>ColorModel</code> | ||
| 1414 | * has an alpha component array or a transparent pixel. | ||
| 1415 | * @param raster the specified <code>Raster</code> | ||
| 1416 | * @param forceARGB if <code>true</code>, the returned | ||
| 1417 | * <code>BufferedImage</code> is TYPE_INT_ARGB; otherwise it is | ||
| 1418 | * TYPE_INT_RGB | ||
| 1419 | * @return a <code>BufferedImage</code> created with the specified | ||
| 1420 | * <code>Raster</code> | ||
| 1421 | * @throws IllegalArgumentException if the raster argument is not | ||
| 1422 | * compatible with this IndexColorModel | ||
| 1423 | */ | ||
| 1424 | public BufferedImage convertToIntDiscrete(Raster raster, | ||
| 1425 | boolean forceARGB) { | ||
| 1426 | ColorModel cm; | ||
| 1427 | |||
| 1428 | if (!isCompatibleRaster(raster)) { | ||
| 1429 | throw new IllegalArgumentException("This raster is not compatible" + | ||
| 1430 | "with this IndexColorModel."); | ||
| 1431 | } | ||
| 1432 | if (forceARGB || transparency == TRANSLUCENT) { | ||
| 1433 | cm = ColorModel.getRGBdefault(); | ||
| 1434 | } | ||
| 1435 | else if (transparency == BITMASK) { | ||
| 1436 | cm = new DirectColorModel(25, 0xff0000, 0x00ff00, 0x0000ff, | ||
| 1437 | 0x1000000); | ||
| 1438 | } | ||
| 1439 | else { | ||
| 1440 | cm = new DirectColorModel(24, 0xff0000, 0x00ff00, 0x0000ff); | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | int w = raster.getWidth(); | ||
| 1444 | int h = raster.getHeight(); | ||
| 1445 | WritableRaster discreteRaster = | ||
| 1446 | cm.createCompatibleWritableRaster(w, h); | ||
| 1447 | Object obj = null; | ||
| 1448 | int[] data = null; | ||
| 1449 | |||
| 1450 | int rX = raster.getMinX(); | ||
| 1451 | int rY = raster.getMinY(); | ||
| 1452 | |||
| 1453 | for (int y=0; y < h; y++, rY++) { | ||
| 1454 | obj = raster.getDataElements(rX, rY, w, 1, obj); | ||
| 1455 | if (obj instanceof int[]) { | ||
| 1456 | data = (int[])obj; | ||
| 1457 | } else { | ||
| 1458 | data = DataBuffer.toIntArray(obj); | ||
| 1459 | } | ||
| 1460 | for (int x=0; x < w; x++) { | ||
| 1461 | data[x] = rgb[data[x] & pixel_mask]; | ||
| 1462 | } | ||
| 1463 | discreteRaster.setDataElements(0, y, w, 1, data); | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | return new BufferedImage(cm, discreteRaster, false, null); | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | /** | ||
| 1470 | * Returns whether or not the pixel is valid. | ||
| 1471 | * @param pixel the specified pixel value | ||
| 1472 | * @return <code>true</code> if <code>pixel</code> | ||
| 1473 | * is valid; <code>false</code> otherwise. | ||
| 1474 | * @since 1.3 | ||
| 1475 | */ | ||
| 1476 | public boolean isValid(int pixel) { | ||
| 1477 | return ((pixel >= 0 && pixel < map_size) && | ||
| 1478 | (validBits == null || validBits.testBit(pixel))); | ||
| 1479 | } | ||
| 1480 | |||
| 1481 | /** | ||
| 1482 | * Returns whether or not all of the pixels are valid. | ||
| 1483 | * @return <code>true</code> if all pixels are valid; | ||
| 1484 | * <code>false</code> otherwise. | ||
| 1485 | * @since 1.3 | ||
| 1486 | */ | ||
| 1487 | public boolean isValid() { | ||
| 1488 | return (validBits == null); | ||
| 1489 | } | ||
| 1490 | |||
| 1491 | /** | ||
| 1492 | * Returns a <code>BigInteger</code> that indicates the valid/invalid | ||
| 1493 | * pixels in the colormap. A bit is valid if the | ||
| 1494 | * <code>BigInteger</code> value at that index is set, and is invalid | ||
| 1495 | * if the <code>BigInteger</code> value at that index is not set. | ||
| 1496 | * The only valid ranges to query in the <code>BigInteger</code> are | ||
| 1497 | * between 0 and the map size. | ||
| 1498 | * @return a <code>BigInteger</code> indicating the valid/invalid pixels. | ||
| 1499 | * @since 1.3 | ||
| 1500 | */ | ||
| 1501 | public BigInteger getValidPixels() { | ||
| 1502 | if (validBits == null) { | ||
| 1503 | return getAllValid(); | ||
| 1504 | } | ||
| 1505 | else { | ||
| 1506 | return validBits; | ||
| 1507 | } | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | /** | ||
| 1511 | * Disposes of system resources associated with this | ||
| 1512 | * <code>ColorModel</code> once this <code>ColorModel</code> is no | ||
| 1513 | * longer referenced. | ||
| 1514 | */ | ||
| 1515 | public void finalize() { | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | /** | ||
| 1519 | * Returns the <code>String</code> representation of the contents of | ||
| 1520 | * this <code>ColorModel</code>object. | ||
| 1521 | * @return a <code>String</code> representing the contents of this | ||
| 1522 | * <code>ColorModel</code> object. | ||
| 1523 | */ | ||
| 1524 | public String toString() { | ||
| 1525 | return new String("IndexColorModel: #pixelBits = "+pixel_bits | ||
| 1526 | + " numComponents = "+numComponents | ||
| 1527 | + " color space = "+colorSpace | ||
| 1528 | + " transparency = "+transparency | ||
| 1529 | + " transIndex = "+transparent_index | ||
| 1530 | + " has alpha = "+supportsAlpha | ||
| 1531 | + " isAlphaPre = "+isAlphaPremultiplied | ||
| 1532 | ); | ||
| 1533 | } | ||
| 1534 | } | ||
Binary file not shown.
| @@ -0,0 +1,153 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | |||
| 29 | /** | ||
| 30 | * The <code>Kernel</code> class defines a matrix that describes how a | ||
| 31 | * specified pixel and its surrounding pixels affect the value | ||
| 32 | * computed for the pixel's position in the output image of a filtering | ||
| 33 | * operation. The X origin and Y origin indicate the kernel matrix element | ||
| 34 | * that corresponds to the pixel position for which an output value is | ||
| 35 | * being computed. | ||
| 36 | * | ||
| 37 | * @see ConvolveOp | ||
| 38 | */ | ||
| 39 | public class Kernel implements Cloneable { | ||
| 40 | private int width; | ||
| 41 | private int height; | ||
| 42 | private int xOrigin; | ||
| 43 | private int yOrigin; | ||
| 44 | private float data[]; | ||
| 45 | |||
| 46 | private static native void initIDs(); | ||
| 47 | static { | ||
| 48 | ColorModel.loadLibraries(); | ||
| 49 | initIDs(); | ||
| 50 | } | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Constructs a <code>Kernel</code> object from an array of floats. | ||
| 54 | * The first <code>width</code>*<code>height</code> elements of | ||
| 55 | * the <code>data</code> array are copied. | ||
| 56 | * If the length of the <code>data</code> array is less | ||
| 57 | * than width*height, an <code>IllegalArgumentException</code> is thrown. | ||
| 58 | * The X origin is (width-1)/2 and the Y origin is (height-1)/2. | ||
| 59 | * @param width width of the kernel | ||
| 60 | * @param height height of the kernel | ||
| 61 | * @param data kernel data in row major order | ||
| 62 | * @throws IllegalArgumentException if the length of <code>data</code> | ||
| 63 | * is less than the product of <code>width</code> and | ||
| 64 | * <code>height</code> | ||
| 65 | */ | ||
| 66 | public Kernel(int width, int height, float data[]) { | ||
| 67 | this.width = width; | ||
| 68 | this.height = height; | ||
| 69 | this.xOrigin = (width-1)>>1; | ||
| 70 | this.yOrigin = (height-1)>>1; | ||
| 71 | int len = width*height; | ||
| 72 | if (data.length < len) { | ||
| 73 | throw new IllegalArgumentException("Data array too small "+ | ||
| 74 | "(is "+data.length+ | ||
| 75 | " and should be "+len); | ||
| 76 | } | ||
| 77 | this.data = new float[len]; | ||
| 78 | System.arraycopy(data, 0, this.data, 0, len); | ||
| 79 | |||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Returns the X origin of this <code>Kernel</code>. | ||
| 84 | * @return the X origin. | ||
| 85 | */ | ||
| 86 | final public int getXOrigin(){ | ||
| 87 | return xOrigin; | ||
| 88 | } | ||
| 89 | |||
| 90 | /** | ||
| 91 | * Returns the Y origin of this <code>Kernel</code>. | ||
| 92 | * @return the Y origin. | ||
| 93 | */ | ||
| 94 | final public int getYOrigin() { | ||
| 95 | return yOrigin; | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * Returns the width of this <code>Kernel</code>. | ||
| 100 | * @return the width of this <code>Kernel</code>. | ||
| 101 | */ | ||
| 102 | final public int getWidth() { | ||
| 103 | return width; | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Returns the height of this <code>Kernel</code>. | ||
| 108 | * @return the height of this <code>Kernel</code>. | ||
| 109 | */ | ||
| 110 | final public int getHeight() { | ||
| 111 | return height; | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * Returns the kernel data in row major order. | ||
| 116 | * The <code>data</code> array is returned. If <code>data</code> | ||
| 117 | * is <code>null</code>, a new array is allocated. | ||
| 118 | * @param data if non-null, contains the returned kernel data | ||
| 119 | * @return the <code>data</code> array containing the kernel data | ||
| 120 | * in row major order or, if <code>data</code> is | ||
| 121 | * <code>null</code>, a newly allocated array containing | ||
| 122 | * the kernel data in row major order | ||
| 123 | * @throws IllegalArgumentException if <code>data</code> is less | ||
| 124 | * than the size of this <code>Kernel</code> | ||
| 125 | */ | ||
| 126 | final public float[] getKernelData(float[] data) { | ||
| 127 | if (data == null) { | ||
| 128 | data = new float[this.data.length]; | ||
| 129 | } | ||
| 130 | else if (data.length < this.data.length) { | ||
| 131 | throw new IllegalArgumentException("Data array too small "+ | ||
| 132 | "(should be "+this.data.length+ | ||
| 133 | " but is "+ | ||
| 134 | data.length+" )"); | ||
| 135 | } | ||
| 136 | System.arraycopy(this.data, 0, data, 0, this.data.length); | ||
| 137 | |||
| 138 | return data; | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * Clones this object. | ||
| 143 | * @return a clone of this object. | ||
| 144 | */ | ||
| 145 | public Object clone() { | ||
| 146 | try { | ||
| 147 | return super.clone(); | ||
| 148 | } catch (CloneNotSupportedException e) { | ||
| 149 | // this shouldn't happen, since we are Cloneable | ||
| 150 | throw new InternalError(); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | } | ||
Binary file not shown.
| @@ -0,0 +1,567 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 | |||
| 27 | package java.awt.image; | ||
| 28 | |||
| 29 | import java.awt.color.ColorSpace; | ||
| 30 | import java.awt.geom.Rectangle2D; | ||
| 31 | import java.awt.Rectangle; | ||
| 32 | import java.awt.RenderingHints; | ||
| 33 | import java.awt.geom.Point2D; | ||
| 34 | import sun.awt.image.ImagingLib; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * This class implements a lookup operation from the source | ||
| 38 | * to the destination. The LookupTable object may contain a single array | ||
| 39 | * or multiple arrays, subject to the restrictions below. | ||
| 40 | * <p> | ||
| 41 | * For Rasters, the lookup operates on bands. The number of | ||
| 42 | * lookup arrays may be one, in which case the same array is | ||
| 43 | * applied to all bands, or it must equal the number of Source | ||
| 44 | * Raster bands. | ||
| 45 | * <p> | ||
| 46 | * For BufferedImages, the lookup operates on color and alpha components. | ||
| 47 | * The number of lookup arrays may be one, in which case the | ||
| 48 | * same array is applied to all color (but not alpha) components. | ||
| 49 | * Otherwise, the number of lookup arrays may | ||
| 50 | * equal the number of Source color components, in which case no | ||
| 51 | * lookup of the alpha component (if present) is performed. | ||
| 52 | * If neither of these cases apply, the number of lookup arrays | ||
| 53 | * must equal the number of Source color components plus alpha components, | ||
| 54 | * in which case lookup is performed for all color and alpha components. | ||
| 55 | * This allows non-uniform rescaling of multi-band BufferedImages. | ||
| 56 | * <p> | ||
| 57 | * BufferedImage sources with premultiplied alpha data are treated in the same | ||
| 58 | * manner as non-premultiplied images for purposes of the lookup. That is, | ||
| 59 | * the lookup is done per band on the raw data of the BufferedImage source | ||
| 60 | * without regard to whether the data is premultiplied. If a color conversion | ||
| 61 | * is required to the destination ColorModel, the premultiplied state of | ||
| 62 | * both source and destination will be taken into account for this step. | ||
| 63 | * <p> | ||
| 64 | * Images with an IndexColorModel cannot be used. | ||
| 65 | * <p> | ||
| 66 | * If a RenderingHints object is specified in the constructor, the | ||
| 67 | * color rendering hint and the dithering hint may be used when color | ||
| 68 | * conversion is required. | ||
| 69 | * <p> | ||
| 70 | * This class allows the Source to be the same as the Destination. | ||
| 71 | * | ||
| 72 | * @see LookupTable | ||
| 73 | * @see java.awt.RenderingHints#KEY_COLOR_RENDERING | ||
| 74 | * @see java.awt.RenderingHints#KEY_DITHERING | ||
| 75 | */ | ||
| 76 | |||
| 77 | public class LookupOp implements BufferedImageOp, RasterOp { | ||
| 78 | private LookupTable ltable; | ||
| 79 | private int numComponents; | ||
| 80 | RenderingHints hints; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Constructs a <code>LookupOp</code> object given the lookup | ||
| 84 | * table and a <code>RenderingHints</code> object, which might | ||
| 85 | * be <code>null</code>. | ||
| 86 | * @param lookup the specified <code>LookupTable</code> | ||
| 87 | * @param hints the specified <code>RenderingHints</code>, | ||
| 88 | * or <code>null</code> | ||
| 89 | */ | ||
| 90 | public LookupOp(LookupTable lookup, RenderingHints hints) { | ||
| 91 | this.ltable = lookup; | ||
| 92 | this.hints = hints; | ||
| 93 | numComponents = ltable.getNumComponents(); | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Returns the <code>LookupTable</code>. | ||
| 98 | * @return the <code>LookupTable</code> of this | ||
| 99 | * <code>LookupOp</code>. | ||
| 100 | */ | ||
| 101 | public final LookupTable getTable() { | ||
| 102 | return ltable; | ||
| 103 | } | ||
| 104 | |||
| 105 | /** | ||
| 106 | * Performs a lookup operation on a <code>BufferedImage</code>. | ||
| 107 | * If the color model in the source image is not the same as that | ||
| 108 | * in the destination image, the pixels will be converted | ||
| 109 | * in the destination. If the destination image is <code>null</code>, | ||
| 110 | * a <code>BufferedImage</code> will be created with an appropriate | ||
| 111 | * <code>ColorModel</code>. An <code>IllegalArgumentException</code> | ||
| 112 | * might be thrown if the number of arrays in the | ||
| 113 | * <code>LookupTable</code> does not meet the restrictions | ||
| 114 | * stated in the class comment above, or if the source image | ||
| 115 | * has an <code>IndexColorModel</code>. | ||
| 116 | * @param src the <code>BufferedImage</code> to be filtered | ||
| 117 | * @param dst the <code>BufferedImage</code> in which to | ||
| 118 | * store the results of the filter operation | ||
| 119 | * @return the filtered <code>BufferedImage</code>. | ||
| 120 | * @throws IllegalArgumentException if the number of arrays in the | ||
| 121 | * <code>LookupTable</code> does not meet the restrictions | ||
| 122 | * described in the class comments, or if the source image | ||
| 123 | * has an <code>IndexColorModel</code>. | ||
| 124 | */ | ||
| 125 | public final BufferedImage filter(BufferedImage src, BufferedImage dst) { | ||
| 126 | ColorModel srcCM = src.getColorModel(); | ||
| 127 | int numBands = srcCM.getNumColorComponents(); | ||
| 128 | ColorModel dstCM; | ||
| 129 | if (srcCM instanceof IndexColorModel) { | ||
| 130 | throw new | ||
| 131 | IllegalArgumentException("LookupOp cannot be "+ | ||
| 132 | "performed on an indexed image"); | ||
| 133 | } | ||
| 134 | int numComponents = ltable.getNumComponents(); | ||
| 135 | if (numComponents != 1 && | ||
| 136 | numComponents != srcCM.getNumComponents() && | ||
| 137 | numComponents != srcCM.getNumColorComponents()) | ||
| 138 | { | ||
| 139 | throw new IllegalArgumentException("Number of arrays in the "+ | ||
| 140 | " lookup table ("+ | ||
| 141 | numComponents+ | ||
| 142 | " is not compatible with the "+ | ||
| 143 | " src image: "+src); | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | boolean needToConvert = false; | ||
| 148 | |||
| 149 | int width = src.getWidth(); | ||
| 150 | int height = src.getHeight(); | ||
| 151 | |||
| 152 | if (dst == null) { | ||
| 153 | dst = createCompatibleDestImage(src, null); | ||
| 154 | dstCM = srcCM; | ||
| 155 | } | ||
| 156 | else { | ||
| 157 | if (width != dst.getWidth()) { | ||
| 158 | throw new | ||
| 159 | IllegalArgumentException("Src width ("+width+ | ||
| 160 | ") not equal to dst width ("+ | ||
| 161 | dst.getWidth()+")"); | ||
| 162 | } | ||
| 163 | if (height != dst.getHeight()) { | ||
| 164 | throw new | ||
| 165 | IllegalArgumentException("Src height ("+height+ | ||
| 166 | ") not equal to dst height ("+ | ||
| 167 | dst.getHeight()+")"); | ||
| 168 | } | ||
| 169 | |||
| 170 | dstCM = dst.getColorModel(); | ||
| 171 | if (srcCM.getColorSpace().getType() != | ||
| 172 | dstCM.getColorSpace().getType()) | ||
| 173 | { | ||
| 174 | needToConvert = true; | ||
| 175 | dst = createCompatibleDestImage(src, null); | ||
| 176 | } | ||
| 177 | |||
| 178 | } | ||
| 179 | |||
| 180 | BufferedImage origDst = dst; | ||
| 181 | |||
| 182 | if (ImagingLib.filter(this, src, dst) == null) { | ||
| 183 | // Do it the slow way | ||
| 184 | WritableRaster srcRaster = src.getRaster(); | ||
| 185 | WritableRaster dstRaster = dst.getRaster(); | ||
| 186 | |||
| 187 | if (srcCM.hasAlpha()) { | ||
| 188 | if (numBands-1 == numComponents || numComponents == 1) { | ||
| 189 | int minx = srcRaster.getMinX(); | ||
| 190 | int miny = srcRaster.getMinY(); | ||
| 191 | int[] bands = new int[numBands-1]; | ||
| 192 | for (int i=0; i < numBands-1; i++) { | ||
| 193 | bands[i] = i; | ||
| 194 | } | ||
| 195 | srcRaster = | ||
| 196 | srcRaster.createWritableChild(minx, miny, | ||
| 197 | srcRaster.getWidth(), | ||
| 198 | srcRaster.getHeight(), | ||
| 199 | minx, miny, | ||
| 200 | bands); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | if (dstCM.hasAlpha()) { | ||
| 204 | int dstNumBands = dstRaster.getNumBands(); | ||
| 205 | if (dstNumBands-1 == numComponents || numComponents == 1) { | ||
| 206 | int minx = dstRaster.getMinX(); | ||
| 207 | int miny = dstRaster.getMinY(); | ||
| 208 | int[] bands = new int[numBands-1]; | ||
| 209 | for (int i=0; i < numBands-1; i++) { | ||
| 210 | bands[i] = i; | ||
| 211 | } | ||
| 212 | dstRaster = | ||
| 213 | dstRaster.createWritableChild(minx, miny, | ||
| 214 | dstRaster.getWidth(), | ||
| 215 | dstRaster.getHeight(), | ||
| 216 | minx, miny, | ||
| 217 | bands); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | filter(srcRaster, dstRaster); | ||
| 222 | } | ||
| 223 | |||
| 224 | if (needToConvert) { | ||
| 225 | // ColorModels are not the same | ||
| 226 | ColorConvertOp ccop = new ColorConvertOp(hints); | ||
| 227 | ccop.filter(dst, origDst); | ||
| 228 | } | ||
| 229 | |||
| 230 | return origDst; | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * Performs a lookup operation on a <code>Raster</code>. | ||
| 235 | * If the destination <code>Raster</code> is <code>null</code>, | ||
| 236 | * a new <code>Raster</code> will be created. | ||
| 237 | * The <code>IllegalArgumentException</code> might be thrown | ||
| 238 | * if the source <code>Raster</code> and the destination | ||
| 239 | * <code>Raster</code> do not have the same | ||
| 240 | * number of bands or if the number of arrays in the | ||
| 241 | * <code>LookupTable</code> does not meet the | ||
| 242 | * restrictions stated in the class comment above. | ||
| 243 | * @param src the source <code>Raster</code> to filter | ||
| 244 | * @param dst the destination <code>WritableRaster</code> for the | ||
| 245 | * filtered <code>src</code> | ||
| 246 | * @return the filtered <code>WritableRaster</code>. | ||
| 247 | * @throws IllegalArgumentException if the source and destinations | ||
| 248 | * rasters do not have the same number of bands, or the | ||
| 249 | * number of arrays in the <code>LookupTable</code> does | ||
| 250 | * not meet the restrictions described in the class comments. | ||
| 251 | * | ||
| 252 | */ | ||
| 253 | public final WritableRaster filter (Raster src, WritableRaster dst) { | ||
| 254 | int numBands = src.getNumBands(); | ||
| 255 | int dstLength = dst.getNumBands(); | ||
| 256 | int height = src.getHeight(); | ||
| 257 | int width = src.getWidth(); | ||
| 258 | int srcPix[] = new int[numBands]; | ||
| 259 | |||
| 260 | // Create a new destination Raster, if needed | ||
| 261 | |||
| 262 | if (dst == null) { | ||
| 263 | dst = createCompatibleDestRaster(src); | ||
| 264 | } | ||
| 265 | else if (height != dst.getHeight() || width != dst.getWidth()) { | ||
| 266 | throw new | ||
| 267 | IllegalArgumentException ("Width or height of Rasters do not "+ | ||
| 268 | "match"); | ||
| 269 | } | ||
| 270 | dstLength = dst.getNumBands(); | ||
| 271 | |||
| 272 | if (numBands != dstLength) { | ||
| 273 | throw new | ||
| 274 | IllegalArgumentException ("Number of channels in the src (" | ||
| 275 | + numBands + | ||
| 276 | ") does not match number of channels" | ||
| 277 | + " in the destination (" | ||
| 278 | + dstLength + ")"); | ||
| 279 | } | ||
| 280 | int numComponents = ltable.getNumComponents(); | ||
| 281 | if (numComponents != 1 && numComponents != src.getNumBands()) { | ||
| 282 | throw new IllegalArgumentException("Number of arrays in the "+ | ||
| 283 | " lookup table ("+ | ||
| 284 | numComponents+ | ||
| 285 | " is not compatible with the "+ | ||
| 286 | " src Raster: "+src); | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 290 | if (ImagingLib.filter(this, src, dst) != null) { | ||
| 291 | return dst; | ||
| 292 | } | ||
| 293 | |||
| 294 | // Optimize for cases we know about | ||
| 295 | if (ltable instanceof ByteLookupTable) { | ||
| 296 | byteFilter ((ByteLookupTable) ltable, src, dst, | ||
| 297 | width, height, numBands); | ||
| 298 | } | ||
| 299 | else if (ltable instanceof ShortLookupTable) { | ||
| 300 | shortFilter ((ShortLookupTable) ltable, src, dst, width, | ||
| 301 | height, numBands); | ||
| 302 | } | ||
| 303 | else { | ||
| 304 | // Not one we recognize so do it slowly | ||
| 305 | int sminX = src.getMinX(); | ||
| 306 | int sY = src.getMinY(); | ||
| 307 | int dminX = dst.getMinX(); | ||
| 308 | int dY = dst.getMinY(); | ||
| 309 | for (int y=0; y < height; y++, sY++, dY++) { | ||
| 310 | int sX = sminX; | ||
| 311 | int dX = dminX; | ||
| 312 | for (int x=0; x < width; x++, sX++, dX++) { | ||
| 313 | // Find data for all bands at this x,y position | ||
| 314 | src.getPixel(sX, sY, srcPix); | ||
| 315 | |||
| 316 | // Lookup the data for all bands at this x,y position | ||
| 317 | ltable.lookupPixel(srcPix, srcPix); | ||
| 318 | |||
| 319 | // Put it back for all bands | ||
| 320 | dst.setPixel(dX, dY, srcPix); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | return dst; | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 329 | * Returns the bounding box of the filtered destination image. Since | ||
| 330 | * this is not a geometric operation, the bounding box does not | ||
| 331 | * change. | ||
| 332 | * @param src the <code>BufferedImage</code> to be filtered | ||
| 333 | * @return the bounds of the filtered definition image. | ||
| 334 | */ | ||
| 335 | public final Rectangle2D getBounds2D (BufferedImage src) { | ||
| 336 | return getBounds2D(src.getRaster()); | ||
| 337 | } | ||
| 338 | |||
| 339 | /** | ||
| 340 | * Returns the bounding box of the filtered destination Raster. Since | ||
| 341 | * this is not a geometric operation, the bounding box does not | ||
| 342 | * change. | ||
| 343 | * @param src the <code>Raster</code> to be filtered | ||
| 344 | * @return the bounds of the filtered definition <code>Raster</code>. | ||
| 345 | */ | ||
| 346 | public final Rectangle2D getBounds2D (Raster src) { | ||
| 347 | return src.getBounds(); | ||
| 348 | |||
| 349 | } | ||
| 350 | |||
| 351 | /** | ||
| 352 | * Creates a zeroed destination image with the correct size and number of | ||
| 353 | * bands. If destCM is <code>null</code>, an appropriate | ||
| 354 | * <code>ColorModel</code> will be used. | ||
| 355 | * @param src Source image for the filter operation. | ||
| 356 | * @param destCM the destination's <code>ColorModel</code>, which | ||
| 357 | * can be <code>null</code>. | ||
| 358 | * @return a filtered destination <code>BufferedImage</code>. | ||
| 359 | */ | ||
| 360 | public BufferedImage createCompatibleDestImage (BufferedImage src, | ||
| 361 | ColorModel destCM) { | ||
| 362 | BufferedImage image; | ||
| 363 | int w = src.getWidth(); | ||
| 364 | int h = src.getHeight(); | ||
| 365 | int transferType = DataBuffer.TYPE_BYTE; | ||
| 366 | if (destCM == null) { | ||
| 367 | ColorModel cm = src.getColorModel(); | ||
| 368 | Raster raster = src.getRaster(); | ||
| 369 | if (cm instanceof ComponentColorModel) { | ||
| 370 | DataBuffer db = raster.getDataBuffer(); | ||
| 371 | boolean hasAlpha = cm.hasAlpha(); | ||
| 372 | boolean isPre = cm.isAlphaPremultiplied(); | ||
| 373 | int trans = cm.getTransparency(); | ||
| 374 | int[] nbits = null; | ||
| 375 | if (ltable instanceof ByteLookupTable) { | ||
| 376 | if (db.getDataType() == db.TYPE_USHORT) { | ||
| 377 | // Dst raster should be of type byte | ||
| 378 | if (hasAlpha) { | ||
| 379 | nbits = new int[2]; | ||
| 380 | if (trans == cm.BITMASK) { | ||
| 381 | nbits[1] = 1; | ||
| 382 | } | ||
| 383 | else { | ||
| 384 | nbits[1] = 8; | ||
| 385 | } | ||
| 386 | } | ||
| 387 | else { | ||
| 388 | nbits = new int[1]; | ||
| 389 | } | ||
| 390 | nbits[0] = 8; | ||
| 391 | } | ||
| 392 | // For byte, no need to change the cm | ||
| 393 | } | ||
| 394 | else if (ltable instanceof ShortLookupTable) { | ||
| 395 | transferType = DataBuffer.TYPE_USHORT; | ||
| 396 | if (db.getDataType() == db.TYPE_BYTE) { | ||
| 397 | if (hasAlpha) { | ||
| 398 | nbits = new int[2]; | ||
| 399 | if (trans == cm.BITMASK) { | ||
| 400 | nbits[1] = 1; | ||
| 401 | } | ||
| 402 | else { | ||
| 403 | nbits[1] = 16; | ||
| 404 | } | ||
| 405 | } | ||
| 406 | else { | ||
| 407 | nbits = new int[1]; | ||
| 408 | } | ||
| 409 | nbits[0] = 16; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | if (nbits != null) { | ||
| 413 | cm = new ComponentColorModel(cm.getColorSpace(), | ||
| 414 | nbits, hasAlpha, isPre, | ||
| 415 | trans, transferType); | ||
| 416 | } | ||
| 417 | } | ||
| 418 | image = new BufferedImage(cm, | ||
| 419 | cm.createCompatibleWritableRaster(w, h), | ||
| 420 | cm.isAlphaPremultiplied(), | ||
| 421 | null); | ||
| 422 | } | ||
| 423 | else { | ||
| 424 | image = new BufferedImage(destCM, | ||
| 425 | destCM.createCompatibleWritableRaster(w, | ||
| 426 | h), | ||
| 427 | destCM.isAlphaPremultiplied(), | ||
| 428 | null); | ||
| 429 | } | ||
| 430 | |||
| 431 | return image; | ||
| 432 | } | ||
| 433 | |||
| 434 | /** | ||
| 435 | * Creates a zeroed-destination <code>Raster</code> with the | ||
| 436 | * correct size and number of bands, given this source. | ||
| 437 | * @param src the <code>Raster</code> to be transformed | ||
| 438 | * @return the zeroed-destination <code>Raster</code>. | ||
| 439 | */ | ||
| 440 | public WritableRaster createCompatibleDestRaster (Raster src) { | ||
| 441 | return src.createCompatibleWritableRaster(); | ||
| 442 | } | ||
| 443 | |||
| 444 | /** | ||
| 445 | * Returns the location of the destination point given a | ||
| 446 | * point in the source. If <code>dstPt</code> is not | ||
| 447 | * <code>null</code>, it will be used to hold the return value. | ||
| 448 | * Since this is not a geometric operation, the <code>srcPt</code> | ||
| 449 | * will equal the <code>dstPt</code>. | ||
| 450 | * @param srcPt a <code>Point2D</code> that represents a point | ||
| 451 | * in the source image | ||
| 452 | * @param dstPt a <code>Point2D</code>that represents the location | ||
| 453 | * in the destination | ||
| 454 | * @return the <code>Point2D</code> in the destination that | ||
| 455 | * corresponds to the specified point in the source. | ||
| 456 | */ | ||
| 457 | public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) { | ||
| 458 | if (dstPt == null) { | ||
| 459 | dstPt = new Point2D.Float(); | ||
| 460 | } | ||
| 461 | dstPt.setLocation(srcPt.getX(), srcPt.getY()); | ||
| 462 | |||
| 463 | return dstPt; | ||
| 464 | } | ||
| 465 | |||
| 466 | /** | ||
| 467 | * Returns the rendering hints for this op. | ||
| 468 | * @return the <code>RenderingHints</code> object associated | ||
| 469 | * with this op. | ||
| 470 | */ | ||
| 471 | public final RenderingHints getRenderingHints() { | ||
| 472 | return hints; | ||
| 473 | } | ||
| 474 | |||
| 475 | private final void byteFilter(ByteLookupTable lookup, Raster src, | ||
| 476 | WritableRaster dst, | ||
| 477 | int width, int height, int numBands) { | ||
| 478 | int[] srcPix = null; | ||
| 479 | |||
| 480 | // Find the ref to the table and the offset | ||
| 481 | byte[][] table = lookup.getTable(); | ||
| 482 | int offset = lookup.getOffset(); | ||
| 483 | int tidx; | ||
| 484 | int step=1; | ||
| 485 | |||
| 486 | // Check if it is one lookup applied to all bands | ||
| 487 | if (table.length == 1) { | ||
| 488 | step=0; | ||
| 489 | } | ||
| 490 | |||
| 491 | int x; | ||
| 492 | int y; | ||
| 493 | int band; | ||
| 494 | int len = table[0].length; | ||
| 495 | |||
| 496 | // Loop through the data | ||
| 497 | for ( y=0; y < height; y++) { | ||
| 498 | tidx = 0; | ||
| 499 | for ( band=0; band < numBands; band++, tidx+=step) { | ||
| 500 | // Find data for this band, scanline | ||
| 501 | srcPix = src.getSamples(0, y, width, 1, band, srcPix); | ||
| 502 | |||
| 503 | for ( x=0; x < width; x++) { | ||
| 504 | int index = srcPix[x]-offset; | ||
| 505 | if (index < 0 || index > len) { | ||
| 506 | throw new | ||
| 507 | IllegalArgumentException("index ("+index+ | ||
| 508 | "(out of range: "+ | ||
| 509 | " srcPix["+x+ | ||
| 510 | "]="+ srcPix[x]+ | ||
| 511 | " offset="+ offset); | ||
| 512 | } | ||
| 513 | // Do the lookup | ||
| 514 | srcPix[x] = table[tidx][index]; | ||
| 515 | } | ||
| 516 | // Put it back | ||
| 517 | dst.setSamples(0, y, width, 1, band, srcPix); | ||
| 518 | } | ||
| 519 | } | ||
| 520 | } | ||
| 521 | |||
| 522 | private final void shortFilter(ShortLookupTable lookup, Raster src, | ||
| 523 | WritableRaster dst, | ||
| 524 | int width, int height, int numBands) { | ||
| 525 | int band; | ||
| 526 | int[] srcPix = null; | ||
| 527 | |||
| 528 | // Find the ref to the table and the offset | ||
| 529 | short[][] table = lookup.getTable(); | ||
| 530 | int offset = lookup.getOffset(); | ||
| 531 | int tidx; | ||
| 532 | int step=1; | ||
| 533 | |||
| 534 | // Check if it is one lookup applied to all bands | ||
| 535 | if (table.length == 1) { | ||
| 536 | step=0; | ||
| 537 | } | ||
| 538 | |||
| 539 | int x = 0; | ||
| 540 | int y = 0; | ||
| 541 | int index; | ||
| 542 | int maxShort = (1<<16)-1; | ||
| 543 | // Loop through the data | ||
| 544 | for (y=0; y < height; y++) { | ||
| 545 | tidx = 0; | ||
| 546 | for ( band=0; band < numBands; band++, tidx+=step) { | ||
| 547 | // Find data for this band, scanline | ||
| 548 | srcPix = src.getSamples(0, y, width, 1, band, srcPix); | ||
| 549 | |||
| 550 | for ( x=0; x < width; x++) { | ||
| 551 | index = srcPix[x]-offset; | ||
| 552 | if (index < 0 || index > maxShort) { | ||
| 553 | throw new | ||
| 554 | IllegalArgumentException("index out of range "+ | ||
| 555 | index+" x is "+x+ | ||
| 556 | "srcPix[x]="+srcPix[x] | ||
| 557 | +" offset="+ offset); | ||
| 558 | } | ||
| 559 | // Do the lookup | ||
| 560 | srcPix[x] = table[tidx][index]; | ||
| 561 | } | ||
| 562 | // Put it back | ||
| 563 | dst.setSamples(0, y, width, 1, band, srcPix); | ||
| 564 | } | ||
| 565 | } | ||
| 566 | } | ||
| 567 | } | ||
Binary file not shown.
| @@ -0,0 +1,109 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | |||
| 29 | /** | ||
| 30 | * This abstract class defines a lookup table object. ByteLookupTable | ||
| 31 | * and ShortLookupTable are subclasses, which | ||
| 32 | * contain byte and short data, respectively. A lookup table | ||
| 33 | * contains data arrays for one or more bands (or components) of an image | ||
| 34 | * (for example, separate arrays for R, G, and B), | ||
| 35 | * and it contains an offset which will be subtracted from the | ||
| 36 | * input values before indexing into the arrays. This allows an array | ||
| 37 | * smaller than the native data size to be provided for a | ||
| 38 | * constrained input. If there is only one array in the lookup | ||
| 39 | * table, it will be applied to all bands. All arrays must be the | ||
| 40 | * same size. | ||
| 41 | * | ||
| 42 | * @see ByteLookupTable | ||
| 43 | * @see ShortLookupTable | ||
| 44 | * @see LookupOp | ||
| 45 | */ | ||
| 46 | public abstract class LookupTable extends Object{ | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Constants | ||
| 50 | */ | ||
| 51 | |||
| 52 | int numComponents; | ||
| 53 | int offset; | ||
| 54 | int numEntries; | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Constructs a new LookupTable from the number of components and an offset | ||
| 58 | * into the lookup table. | ||
| 59 | * @param offset the offset to subtract from input values before indexing | ||
| 60 | * into the data arrays for this <code>LookupTable</code> | ||
| 61 | * @param numComponents the number of data arrays in this | ||
| 62 | * <code>LookupTable</code> | ||
| 63 | * @throws IllegalArgumentException if <code>offset</code> is less than 0 | ||
| 64 | * or if <code>numComponents</code> is less than 1 | ||
| 65 | */ | ||
| 66 | protected LookupTable(int offset, int numComponents) { | ||
| 67 | if (offset < 0) { | ||
| 68 | throw new | ||
| 69 | IllegalArgumentException("Offset must be greater than 0"); | ||
| 70 | } | ||
| 71 | if (numComponents < 1) { | ||
| 72 | throw new IllegalArgumentException("Number of components must "+ | ||
| 73 | " be at least 1"); | ||
| 74 | } | ||
| 75 | this.numComponents = numComponents; | ||
| 76 | this.offset = offset; | ||
| 77 | } | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Returns the number of components in the lookup table. | ||
| 81 | * @return the number of components in this <code>LookupTable</code>. | ||
| 82 | */ | ||
| 83 | public int getNumComponents() { | ||
| 84 | return numComponents; | ||
| 85 | } | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Returns the offset. | ||
| 89 | * @return the offset of this <code>LookupTable</code>. | ||
| 90 | */ | ||
| 91 | public int getOffset() { | ||
| 92 | return offset; | ||
| 93 | } | ||
| 94 | |||
| 95 | /** | ||
| 96 | * Returns an <code>int</code> array of components for | ||
| 97 | * one pixel. The <code>dest</code> array contains the | ||
| 98 | * result of the lookup and is returned. If dest is | ||
| 99 | * <code>null</code>, a new array is allocated. The | ||
| 100 | * source and destination can be equal. | ||
| 101 | * @param src the source array of components of one pixel | ||
| 102 | * @param dest the destination array of components for one pixel, | ||
| 103 | * translated with this <code>LookupTable</code> | ||
| 104 | * @return an <code>int</code> array of components for one | ||
| 105 | * pixel. | ||
| 106 | */ | ||
| 107 | public abstract int[] lookupPixel(int[] src, int[] dest); | ||
| 108 | |||
| 109 | } | ||
Binary file not shown.
| @@ -0,0 +1,571 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 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 java.awt.image; | ||
| 27 | |||
| 28 | import java.awt.image.ImageConsumer; | ||
| 29 | import java.awt.image.ImageProducer; | ||
| 30 | import java.awt.image.ColorModel; | ||
| 31 | import java.util.Hashtable; | ||
| 32 | import java.util.Vector; | ||
| 33 | import java.util.Enumeration; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * This class is an implementation of the ImageProducer interface which | ||
| 37 | * uses an array to produce pixel values for an Image. Here is an example | ||
| 38 | * which calculates a 100x100 image representing a fade from black to blue | ||
| 39 | * along the X axis and a fade from black to red along the Y axis: | ||
| 40 | * <pre> | ||
| 41 | * | ||
| 42 | * int w = 100; | ||
| 43 | * int h = 100; | ||
| 44 | * int pix[] = new int[w * h]; | ||
| 45 | * int index = 0; | ||
| 46 | * for (int y = 0; y < h; y++) { | ||
| 47 | * int red = (y * 255) / (h - 1); | ||
| 48 | * for (int x = 0; x < w; x++) { | ||
| 49 | * int blue = (x * 255) / (w - 1); | ||
| 50 | * pix[index++] = (255 << 24) | (red << 16) | blue; | ||
| 51 | * } | ||
| 52 | * } | ||
| 53 | * Image img = createImage(new MemoryImageSource(w, h, pix, 0, w)); | ||
| 54 | * | ||
| 55 | * </pre> | ||
| 56 | * The MemoryImageSource is also capable of managing a memory image which | ||
| 57 | * varies over time to allow animation or custom rendering. Here is an | ||
| 58 | * example showing how to set up the animation source and signal changes | ||
| 59 | * in the data (adapted from the MemoryAnimationSourceDemo by Garth Dickie): | ||
| 60 | * <pre> | ||
| 61 | * | ||
| 62 | * int pixels[]; | ||
| 63 | * MemoryImageSource source; | ||
| 64 | * | ||
| 65 | * public void init() { | ||
| 66 | * int width = 50; | ||
| 67 | * int height = 50; | ||
| 68 | * int size = width * height; | ||
| 69 | * pixels = new int[size]; | ||
| 70 | * | ||
| 71 | * int value = getBackground().getRGB(); | ||
| 72 | * for (int i = 0; i < size; i++) { | ||
| 73 | * pixels[i] = value; | ||
| 74 | * } | ||
| 75 | * | ||
| 76 | * source = new MemoryImageSource(width, height, pixels, 0, width); | ||
| 77 | * source.setAnimated(true); | ||
| 78 | * image = createImage(source); | ||
| 79 | * } | ||
| 80 | * | ||
| 81 | * public void run() { | ||
| 82 | * Thread me = Thread.currentThread( ); | ||
| 83 | * me.setPriority(Thread.MIN_PRIORITY); | ||
| 84 | * | ||
| 85 | * while (true) { | ||
| 86 | * try { | ||
| 87 | * Thread.sleep(10); | ||
| 88 | * } catch( InterruptedException e ) { | ||
| 89 | * return; | ||
| 90 | * } | ||
| 91 | * | ||
| 92 | * // Modify the values in the pixels array at (x, y, w, h) | ||
| 93 | * | ||
| 94 | * // Send the new data to the interested ImageConsumers | ||
| 95 | * source.newPixels(x, y, w, h); | ||
| 96 | * } | ||
| 97 | * } | ||
| 98 | * | ||
| 99 | * </pre> | ||
| 100 | * | ||
| 101 | * @see ImageProducer | ||
| 102 | * | ||
| 103 | * @author Jim Graham | ||
| 104 | * @author Animation capabilities inspired by the | ||
| 105 | * MemoryAnimationSource class written by Garth Dickie | ||
| 106 | */ | ||
| 107 | public class MemoryImageSource implements ImageProducer { | ||
| 108 | int width; | ||
| 109 | int height; | ||
| 110 | ColorModel model; | ||
| 111 | Object pixels; | ||
| 112 | int pixeloffset; | ||
| 113 | int pixelscan; | ||
| 114 | Hashtable properties; | ||
| 115 | Vector theConsumers = new Vector(); | ||
| 116 | boolean animating; | ||
| 117 | boolean fullbuffers; | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Constructs an ImageProducer object which uses an array of bytes | ||
| 121 | * to produce data for an Image object. | ||
| 122 | * @param w the width of the rectangle of pixels | ||
| 123 | * @param h the height of the rectangle of pixels | ||
| 124 | * @param cm the specified <code>ColorModel</code> | ||
| 125 | * @param pix an array of pixels | ||
| 126 | * @param off the offset into the array of where to store the | ||
| 127 | * first pixel | ||
| 128 | * @param scan the distance from one row of pixels to the next in | ||
| 129 | * the array | ||
| 130 | * @see java.awt.Component#createImage | ||
| 131 | */ | ||
| 132 | public MemoryImageSource(int w, int h, ColorModel cm, | ||
| 133 | byte[] pix, int off, int scan) { | ||
| 134 | initialize(w, h, cm, (Object) pix, off, scan, null); | ||
| 135 | } | ||
| 136 | |||
| 137 | /** | ||
| 138 | * Constructs an ImageProducer object which uses an array of bytes | ||
| 139 | * to produce data for an Image object. | ||
| 140 | * @param w the width of the rectangle of pixels | ||
| 141 | * @param h the height of the rectangle of pixels | ||
| 142 | * @param cm the specified <code>ColorModel</code> | ||
| 143 | * @param pix an array of pixels | ||
| 144 | * @param off the offset into the array of where to store the | ||
| 145 | * first pixel | ||
| 146 | * @param scan the distance from one row of pixels to the next in | ||
| 147 | * the array | ||
| 148 | * @param props a list of properties that the <code>ImageProducer</code> | ||
| 149 | * uses to process an image | ||
| 150 | * @see java.awt.Component#createImage | ||
| 151 | */ | ||
| 152 | public MemoryImageSource(int w, int h, ColorModel cm, | ||
| 153 | byte[] pix, int off, int scan, | ||
| 154 | Hashtable<?,?> props) | ||
| 155 | { | ||
| 156 | initialize(w, h, cm, (Object) pix, off, scan, props); | ||
| 157 | } | ||
| 158 | |||
| 159 | /** | ||
| 160 | * Constructs an ImageProducer object which uses an array of integers | ||
| 161 | * to produce data for an Image object. | ||
| 162 | * @param w the width of the rectangle of pixels | ||
| 163 | * @param h the height of the rectangle of pixels | ||
| 164 | * @param cm the specified <code>ColorModel</code> | ||
| 165 | * @param pix an array of pixels | ||
| 166 | * @param off the offset into the array of where to store the | ||
| 167 | * first pixel | ||
| 168 | * @param scan the distance from one row of pixels to the next in | ||
| 169 | * the array | ||
| 170 | * @see java.awt.Component#createImage | ||
| 171 | */ | ||
| 172 | public MemoryImageSource(int w, int h, ColorModel cm, | ||
| 173 | int[] pix, int off, int scan) { | ||
| 174 | initialize(w, h, cm, (Object) pix, off, scan, null); | ||
| 175 | } | ||
| 176 | |||
| 177 | /** | ||
| 178 | * Constructs an ImageProducer object which uses an array of integers | ||
| 179 | * to produce data for an Image object. | ||
| 180 | * @param w the width of the rectangle of pixels | ||
| 181 | * @param h the height of the rectangle of pixels | ||
| 182 | * @param cm the specified <code>ColorModel</code> | ||
| 183 | * @param pix an array of pixels | ||
| 184 | * @param off the offset into the array of where to store the | ||
| 185 | * first pixel | ||
| 186 | * @param scan the distance from one row of pixels to the next in | ||
| 187 | * the array | ||
| 188 | * @param props a list of properties that the <code>ImageProducer</code> | ||
| 189 | * uses to process an image | ||
| 190 | * @see java.awt.Component#createImage | ||
| 191 | */ | ||
| 192 | public MemoryImageSource(int w, int h, ColorModel cm, | ||
| 193 | int[] pix, int off, int scan, | ||
| 194 | Hashtable<?,?> props) | ||
| 195 | { | ||
| 196 | initialize(w, h, cm, (Object) pix, off, scan, props); | ||
| 197 | } | ||
| 198 | |||
| 199 | private void initialize(int w, int h, ColorModel cm, | ||
| 200 | Object pix, int off, int scan, Hashtable props) { | ||
| 201 | width = w; | ||
| 202 | height = h; | ||
| 203 | model = cm; | ||
| 204 | pixels = pix; | ||
| 205 | pixeloffset = off; | ||
| 206 | pixelscan = scan; | ||
| 207 | if (props == null) { | ||
| 208 | props = new Hashtable(); | ||
| 209 | } | ||
| 210 | properties = props; | ||
| 211 | } | ||
| 212 | |||
| 213 | /** | ||
| 214 | * Constructs an ImageProducer object which uses an array of integers | ||
| 215 | * in the default RGB ColorModel to produce data for an Image object. | ||
| 216 | * @param w the width of the rectangle of pixels | ||
| 217 | * @param h the height of the rectangle of pixels | ||
| 218 | * @param pix an array of pixels | ||
| 219 | * @param off the offset into the array of where to store the | ||
| 220 | * first pixel | ||
| 221 | * @param scan the distance from one row of pixels to the next in | ||
| 222 | * the array | ||
| 223 | * @see java.awt.Component#createImage | ||
| 224 | * @see ColorModel#getRGBdefault | ||
| 225 | */ | ||
| 226 | public MemoryImageSource(int w, int h, int pix[], int off, int scan) { | ||
| 227 | initialize(w, h, ColorModel.getRGBdefault(), | ||
| 228 | (Object) pix, off, scan, null); | ||
| 229 | } | ||
| 230 | |||
| 231 | /** | ||
| 232 | * Constructs an ImageProducer object which uses an array of integers | ||
| 233 | * in the default RGB ColorModel to produce data for an Image object. | ||
| 234 | * @param w the width of the rectangle of pixels | ||
| 235 | * @param h the height of the rectangle of pixels | ||
| 236 | * @param pix an array of pixels | ||
| 237 | * @param off the offset into the array of where to store the | ||
| 238 | * first pixel | ||
| 239 | * @param scan the distance from one row of pixels to the next in | ||
| 240 | * the array | ||
| 241 | * @param props a list of properties that the <code>ImageProducer</code> | ||
| 242 | * uses to process an image | ||
| 243 | * @see java.awt.Component#createImage | ||
| 244 | * @see ColorModel#getRGBdefault | ||
| 245 | */ | ||
| 246 | public MemoryImageSource(int w, int h, int pix[], int off, int scan, | ||
| 247 | Hashtable<?,?> props) | ||
| 248 | { | ||
| 249 | initialize(w, h, ColorModel.getRGBdefault(), | ||
| 250 | (Object) pix, off, scan, props); | ||
| 251 | } | ||
| 252 | |||
| 253 | /** | ||
| 254 | * Adds an ImageConsumer to the list of consumers interested in | ||
| 255 | * data for this image. | ||
| 256 | * @param ic the specified <code>ImageConsumer</code> | ||
| 257 | * @throws NullPointerException if the specified | ||
| 258 | * <code>ImageConsumer</code> is null | ||
| 259 | * @see ImageConsumer | ||
| 260 | */ | ||
| 261 | public synchronized void addConsumer(ImageConsumer ic) { | ||
| 262 | if (theConsumers.contains(ic)) { | ||
| 263 | return; | ||
| 264 | } | ||
| 265 | theConsumers.addElement(ic); | ||
| 266 | try { | ||
| 267 | initConsumer(ic); | ||
| 268 | sendPixels(ic, 0, 0, width, height); | ||
| 269 | if (isConsumer(ic)) { | ||
| 270 | ic.imageComplete(animating | ||
| 271 | ? ImageConsumer.SINGLEFRAMEDONE | ||
| 272 | : ImageConsumer.STATICIMAGEDONE); | ||
| 273 | if (!animating && isConsumer(ic)) { | ||
| 274 | ic.imageComplete(ImageConsumer.IMAGEERROR); | ||
| 275 | removeConsumer(ic); | ||
| 276 | } | ||
| 277 | } | ||
| 278 | } catch (Exception e) { | ||
| 279 | if (isConsumer(ic)) { | ||
| 280 | ic.imageComplete(ImageConsumer.IMAGEERROR); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | /** | ||
| 286 | * Determines if an ImageConsumer is on the list of consumers currently | ||
| 287 | * interested in data for this image. | ||
| 288 | * @param ic the specified <code>ImageConsumer</code> | ||
| 289 | * @return <code>true</code> if the <code>ImageConsumer</code> | ||
| 290 | * is on the list; <code>false</code> otherwise. | ||
| 291 | * @see ImageConsumer | ||
| 292 | */ | ||
| 293 | public synchronized boolean isConsumer(ImageConsumer ic) { | ||
| 294 | return theConsumers.contains(ic); | ||
| 295 | } | ||
| 296 | |||
| 297 | /** | ||
| 298 | * Removes an ImageConsumer from the list of consumers interested in | ||
| 299 | * data for this image. | ||
| 300 | * @param ic the specified <code>ImageConsumer</code> | ||
| 301 | * @see ImageConsumer | ||
| 302 | */ | ||
| 303 | public synchronized void removeConsumer(ImageConsumer ic) { | ||
| 304 | theConsumers.removeElement(ic); | ||
| 305 | } | ||
| 306 | |||
| 307 | /** | ||
| 308 | * Adds an ImageConsumer to the list of consumers interested in | ||
| 309 | * data for this image and immediately starts delivery of the | ||
| 310 | * image data through the ImageConsumer interface. | ||
| 311 | * @param ic the specified <code>ImageConsumer</code> | ||
| 312 | * image data through the ImageConsumer interface. | ||
| 313 | * @see ImageConsumer | ||
| 314 | */ | ||
| 315 | public void startProduction(ImageConsumer ic) { | ||
| 316 | addConsumer(ic); | ||
| 317 | } | ||
| 318 | |||
| 319 | /** | ||
| 320 | * Requests that a given ImageConsumer have the image data delivered | ||
| 321 | * one more time in top-down, left-right order. | ||
| 322 | * @param ic the specified <code>ImageConsumer</code> | ||
249 more lines aren’t shown here.
Binary file not shown.
This diff is large: its 700 lines aren’t shown here.
Binary file not shown.
This diff is large: its 487 lines aren’t shown here.
Binary file not shown.
This diff is large: its 673 lines aren’t shown here.
Binary file not shown.
This diff is large: its 172 lines aren’t shown here.
Binary file not shown.
This diff is large: its 293 lines aren’t shown here.
Binary file not shown.
This diff is large: its 1778 lines aren’t shown here.
Binary file not shown.
This diff is large: its 45 lines aren’t shown here.
Binary file not shown.
This diff is large: its 108 lines aren’t shown here.
Binary file not shown.
This diff is large: its 218 lines aren’t shown here.
Binary file not shown.
This diff is large: its 256 lines aren’t shown here.
Binary file not shown.
This diff is large: its 667 lines aren’t shown here.
Binary file not shown.
This diff is large: its 1508 lines aren’t shown here.
Binary file not shown.
This diff is large: its 205 lines aren’t shown here.
Binary file not shown.
This diff is large: its 802 lines aren’t shown here.
Binary file not shown.
This diff is large: its 56 lines aren’t shown here.
Binary file not shown.
This diff is large: its 343 lines aren’t shown here.
Binary file not shown.
This diff is large: its 742 lines aren’t shown here.
Binary file not shown.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
Binary file not shown.
This diff is large: its 144 lines aren’t shown here.
Binary file not shown.
This diff is large: its 726 lines aren’t shown here.
Binary file not shown.
This diff is large: its 273 lines aren’t shown here.
Binary file not shown.
This diff is large: its 199 lines aren’t shown here.
Binary file not shown.
This diff is large: its 351 lines aren’t shown here.
Binary file not shown.
This diff is large: its 220 lines aren’t shown here.
Binary file not shown.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.