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.