From 7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 21 Oct 2008 07:00:00 -0700 Subject: Initial Contribution --- awt/java/awt/image/AffineTransformOp.java | 617 ++++++++ awt/java/awt/image/AreaAveragingScaleFilter.java | 253 ++++ .../awt/image/AwtImageBackdoorAccessorImpl.java | 153 ++ awt/java/awt/image/BandCombineOp.java | 610 ++++++++ awt/java/awt/image/BandedSampleModel.java | 426 ++++++ awt/java/awt/image/BufferStrategy.java | 72 + awt/java/awt/image/BufferedImage.java | 931 +++++++++++++ awt/java/awt/image/BufferedImageFilter.java | 375 +++++ awt/java/awt/image/BufferedImageOp.java | 86 ++ awt/java/awt/image/ByteLookupTable.java | 134 ++ awt/java/awt/image/ColorConvertOp.java | 711 ++++++++++ awt/java/awt/image/ColorModel.java | 911 ++++++++++++ awt/java/awt/image/ComponentColorModel.java | 1471 ++++++++++++++++++++ awt/java/awt/image/ComponentSampleModel.java | 690 +++++++++ awt/java/awt/image/ConvolveOp.java | 545 ++++++++ awt/java/awt/image/CropImageFilter.java | 193 +++ awt/java/awt/image/DataBuffer.java | 442 ++++++ awt/java/awt/image/DataBufferByte.java | 171 +++ awt/java/awt/image/DataBufferDouble.java | 214 +++ awt/java/awt/image/DataBufferFloat.java | 214 +++ awt/java/awt/image/DataBufferInt.java | 170 +++ awt/java/awt/image/DataBufferShort.java | 172 +++ awt/java/awt/image/DataBufferUShort.java | 182 +++ awt/java/awt/image/DirectColorModel.java | 862 ++++++++++++ awt/java/awt/image/FilteredImageSource.java | 88 ++ awt/java/awt/image/ImageConsumer.java | 165 +++ awt/java/awt/image/ImageFilter.java | 129 ++ awt/java/awt/image/ImageObserver.java | 99 ++ awt/java/awt/image/ImageProducer.java | 74 + awt/java/awt/image/ImagingOpException.java | 44 + awt/java/awt/image/IndexColorModel.java | 1020 ++++++++++++++ awt/java/awt/image/Kernel.java | 138 ++ awt/java/awt/image/LookupOp.java | 647 +++++++++ awt/java/awt/image/LookupTable.java | 93 ++ awt/java/awt/image/MemoryImageSource.java | 512 +++++++ .../awt/image/MultiPixelPackedSampleModel.java | 454 ++++++ awt/java/awt/image/PackedColorModel.java | 383 +++++ awt/java/awt/image/PixelGrabber.java | 408 ++++++ .../awt/image/PixelInterleavedSampleModel.java | 124 ++ awt/java/awt/image/RGBImageFilter.java | 190 +++ awt/java/awt/image/Raster.java | 1412 +++++++++++++++++++ awt/java/awt/image/RasterFormatException.java | 45 + awt/java/awt/image/RasterOp.java | 83 ++ awt/java/awt/image/RenderedImage.java | 198 +++ awt/java/awt/image/ReplicateScaleFilter.java | 213 +++ awt/java/awt/image/RescaleOp.java | 659 +++++++++ awt/java/awt/image/SampleModel.java | 1053 ++++++++++++++ awt/java/awt/image/ShortLookupTable.java | 132 ++ .../awt/image/SinglePixelPackedSampleModel.java | 508 +++++++ awt/java/awt/image/TileObserver.java | 44 + awt/java/awt/image/VolatileImage.java | 144 ++ awt/java/awt/image/WritableRaster.java | 516 +++++++ awt/java/awt/image/WritableRenderedImage.java | 101 ++ .../renderable/ContextualRenderedImageFactory.java | 89 ++ awt/java/awt/image/renderable/ParameterBlock.java | 548 ++++++++ awt/java/awt/image/renderable/RenderContext.java | 196 +++ awt/java/awt/image/renderable/RenderableImage.java | 132 ++ .../awt/image/renderable/RenderableImageOp.java | 182 +++ .../image/renderable/RenderableImageProducer.java | 141 ++ .../awt/image/renderable/RenderedImageFactory.java | 43 + 60 files changed, 21612 insertions(+) create mode 100644 awt/java/awt/image/AffineTransformOp.java create mode 100644 awt/java/awt/image/AreaAveragingScaleFilter.java create mode 100644 awt/java/awt/image/AwtImageBackdoorAccessorImpl.java create mode 100644 awt/java/awt/image/BandCombineOp.java create mode 100644 awt/java/awt/image/BandedSampleModel.java create mode 100644 awt/java/awt/image/BufferStrategy.java create mode 100644 awt/java/awt/image/BufferedImage.java create mode 100644 awt/java/awt/image/BufferedImageFilter.java create mode 100644 awt/java/awt/image/BufferedImageOp.java create mode 100644 awt/java/awt/image/ByteLookupTable.java create mode 100644 awt/java/awt/image/ColorConvertOp.java create mode 100644 awt/java/awt/image/ColorModel.java create mode 100644 awt/java/awt/image/ComponentColorModel.java create mode 100644 awt/java/awt/image/ComponentSampleModel.java create mode 100644 awt/java/awt/image/ConvolveOp.java create mode 100644 awt/java/awt/image/CropImageFilter.java create mode 100644 awt/java/awt/image/DataBuffer.java create mode 100644 awt/java/awt/image/DataBufferByte.java create mode 100644 awt/java/awt/image/DataBufferDouble.java create mode 100644 awt/java/awt/image/DataBufferFloat.java create mode 100644 awt/java/awt/image/DataBufferInt.java create mode 100644 awt/java/awt/image/DataBufferShort.java create mode 100644 awt/java/awt/image/DataBufferUShort.java create mode 100644 awt/java/awt/image/DirectColorModel.java create mode 100644 awt/java/awt/image/FilteredImageSource.java create mode 100644 awt/java/awt/image/ImageConsumer.java create mode 100644 awt/java/awt/image/ImageFilter.java create mode 100644 awt/java/awt/image/ImageObserver.java create mode 100644 awt/java/awt/image/ImageProducer.java create mode 100644 awt/java/awt/image/ImagingOpException.java create mode 100644 awt/java/awt/image/IndexColorModel.java create mode 100644 awt/java/awt/image/Kernel.java create mode 100644 awt/java/awt/image/LookupOp.java create mode 100644 awt/java/awt/image/LookupTable.java create mode 100644 awt/java/awt/image/MemoryImageSource.java create mode 100644 awt/java/awt/image/MultiPixelPackedSampleModel.java create mode 100644 awt/java/awt/image/PackedColorModel.java create mode 100644 awt/java/awt/image/PixelGrabber.java create mode 100644 awt/java/awt/image/PixelInterleavedSampleModel.java create mode 100644 awt/java/awt/image/RGBImageFilter.java create mode 100644 awt/java/awt/image/Raster.java create mode 100644 awt/java/awt/image/RasterFormatException.java create mode 100644 awt/java/awt/image/RasterOp.java create mode 100644 awt/java/awt/image/RenderedImage.java create mode 100644 awt/java/awt/image/ReplicateScaleFilter.java create mode 100644 awt/java/awt/image/RescaleOp.java create mode 100644 awt/java/awt/image/SampleModel.java create mode 100644 awt/java/awt/image/ShortLookupTable.java create mode 100644 awt/java/awt/image/SinglePixelPackedSampleModel.java create mode 100644 awt/java/awt/image/TileObserver.java create mode 100644 awt/java/awt/image/VolatileImage.java create mode 100644 awt/java/awt/image/WritableRaster.java create mode 100644 awt/java/awt/image/WritableRenderedImage.java create mode 100644 awt/java/awt/image/renderable/ContextualRenderedImageFactory.java create mode 100644 awt/java/awt/image/renderable/ParameterBlock.java create mode 100644 awt/java/awt/image/renderable/RenderContext.java create mode 100644 awt/java/awt/image/renderable/RenderableImage.java create mode 100644 awt/java/awt/image/renderable/RenderableImageOp.java create mode 100644 awt/java/awt/image/renderable/RenderableImageProducer.java create mode 100644 awt/java/awt/image/renderable/RenderedImageFactory.java (limited to 'awt/java/awt/image') diff --git a/awt/java/awt/image/AffineTransformOp.java b/awt/java/awt/image/AffineTransformOp.java new file mode 100644 index 0000000..546837a --- /dev/null +++ b/awt/java/awt/image/AffineTransformOp.java @@ -0,0 +1,617 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky, Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Point2D; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.*; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The AffineTransform class translates coordinates from 2D coordinates + * in the source image or Raster to 2D coordinates in the destination + * image or Raster using Affine transformation. The number of bands in + * the source Raster should equal to the number of bands in the destination + * Raster. + */ +public class AffineTransformOp implements BufferedImageOp, RasterOp { + + /** + * The Constant TYPE_NEAREST_NEIGHBOR indicates nearest-neighbor + * interpolation type. + */ + public static final int TYPE_NEAREST_NEIGHBOR = 1; + + /** + * The Constant TYPE_BILINEAR indicates bilinear interpolation type. + */ + public static final int TYPE_BILINEAR = 2; + + /** The Constant TYPE_BICUBIC indicates bicubic interpolation type. */ + public static final int TYPE_BICUBIC = 3; + + /** The i type. */ + private int iType; // interpolation type + + /** The at. */ + private AffineTransform at; + + /** The hints. */ + private RenderingHints hints; + + static { + // TODO - uncomment + //System.loadLibrary("imageops"); + } + + /** + * Instantiates a new AffineTransformOp with the specified + * AffineTransform and RenderingHints object which defines + * the interpolation type. + * + * @param xform the AffineTransform. + * @param hints the RenderingHints object which defines + * the interpolation type. + */ + public AffineTransformOp(AffineTransform xform, RenderingHints hints) { + this(xform, TYPE_NEAREST_NEIGHBOR); + this.hints = hints; + + if (hints != null) { + Object hint = hints.get(RenderingHints.KEY_INTERPOLATION); + if (hint != null) { + // Nearest neighbor is default + if (hint == RenderingHints.VALUE_INTERPOLATION_BILINEAR) { + this.iType = TYPE_BILINEAR; + } else if (hint == RenderingHints.VALUE_INTERPOLATION_BICUBIC) { + this.iType = TYPE_BICUBIC; + } + } else { + hint = hints.get(RenderingHints.KEY_RENDERING); + // Determine from rendering quality + if (hint == RenderingHints.VALUE_RENDER_QUALITY) { + this.iType = TYPE_BILINEAR; + // For speed use nearest neighbor + } + } + } + } + + /** + * Instantiates a new AffineTransformOp with the specified + * AffineTransform and a specified interpolation type from the + * list of predefined interpolation types. + * + * @param xform the AffineTransform. + * @param interp the one of predefined interpolation types: + * TYPE_NEAREST_NEIGHBOR, TYPE_BILINEAR, or TYPE_BICUBIC. + */ + public AffineTransformOp(AffineTransform xform, int interp) { + if (Math.abs(xform.getDeterminant()) <= Double.MIN_VALUE) { + // awt.24F=Unable to invert transform {0} + throw new ImagingOpException(Messages.getString("awt.24F", xform)); //$NON-NLS-1$ + } + + this.at = (AffineTransform) xform.clone(); + + if (interp != TYPE_NEAREST_NEIGHBOR && interp != TYPE_BILINEAR && interp != TYPE_BICUBIC) { + // awt.250=Unknown interpolation type: {0} + throw new IllegalArgumentException(Messages.getString("awt.250", interp)); //$NON-NLS-1$ + } + + this.iType = interp; + } + + /** + * Gets the interpolation type. + * + * @return the interpolation type + */ + public final int getInterpolationType() { + return iType; + } + + public final RenderingHints getRenderingHints() { + if (hints == null) { + Object value = null; + + switch (iType) { + case TYPE_NEAREST_NEIGHBOR: + value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; + break; + case TYPE_BILINEAR: + value = RenderingHints.VALUE_INTERPOLATION_BILINEAR; + break; + case TYPE_BICUBIC: + value = RenderingHints.VALUE_INTERPOLATION_BICUBIC; + break; + default: + value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; + } + + hints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, value); + } + + return hints; + } + + /** + * Gets the affine transform associated with this AffineTransformOp. + * + * @return the AffineTransform. + */ + public final AffineTransform getTransform() { + return (AffineTransform) at.clone(); + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + return at.transform(srcPt, dstPt); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public final Rectangle2D getBounds2D(Raster src) { + // We position source raster to (0,0) even if it is translated child raster. + // This means that we need only width and height of the src + int width = src.getWidth(); + int height = src.getHeight(); + + float[] corners = { + 0, 0, + width, 0, + width, height, + 0, height + }; + + at.transform(corners, 0, corners, 0, 4); + + Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0); + bounds.add(corners[2], corners[3]); + bounds.add(corners[4], corners[5]); + bounds.add(corners[6], corners[7]); + + return bounds; + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { + Rectangle2D newBounds = getBounds2D(src); + + // Destination image should include (0,0) + positive part + // of the area bounded by newBounds (in source coordinate system). + double dstWidth = newBounds.getX() + newBounds.getWidth(); + double dstHeight = newBounds.getY() + newBounds.getHeight(); + + if (dstWidth <= 0 || dstHeight <= 0) { + // awt.251=Transformed width ({0}) and height ({1}) should be greater than 0 + throw new RasterFormatException( + Messages.getString("awt.251", dstWidth, dstHeight)); //$NON-NLS-1$ + } + + if (destCM != null) { + return new BufferedImage(destCM, + destCM.createCompatibleWritableRaster((int)dstWidth, (int)dstHeight), + destCM.isAlphaPremultiplied(), + null + ); + } + + ColorModel cm = src.getColorModel(); + + // Interpolation other than NN doesn't make any sense for index color + if (iType != TYPE_NEAREST_NEIGHBOR && cm instanceof IndexColorModel) { + return new BufferedImage((int)dstWidth, (int)dstHeight, BufferedImage.TYPE_INT_ARGB); + } + + // OK, we can get source color model + return new BufferedImage(cm, + src.getRaster().createCompatibleWritableRaster((int)dstWidth, (int)dstHeight), + cm.isAlphaPremultiplied(), + null + ); + } + + public WritableRaster createCompatibleDestRaster (Raster src) { + // Here approach is other then in createCompatibleDestImage - + // destination should include only + // transformed image, but not (0,0) in source coordinate system + + Rectangle2D newBounds = getBounds2D(src); + return src.createCompatibleWritableRaster( + (int) newBounds.getX(), (int) newBounds.getY(), + (int) newBounds.getWidth(), (int)newBounds.getHeight() + ); + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + if (src == dst) { + // awt.252=Source can't be same as the destination + throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$ + } + + ColorModel srcCM = src.getColorModel(); + BufferedImage finalDst = null; + + if ( + srcCM instanceof IndexColorModel && + (iType != TYPE_NEAREST_NEIGHBOR || srcCM.getPixelSize() % 8 != 0) + ) { + src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true); + srcCM = src.getColorModel(); + } + + if (dst == null) { + dst = createCompatibleDestImage(src, srcCM); + } else { + if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same + if ( + !( + (src.getType() == BufferedImage.TYPE_INT_RGB || + src.getType() == BufferedImage.TYPE_INT_ARGB) && + (dst.getType() == BufferedImage.TYPE_INT_RGB || + dst.getType() == BufferedImage.TYPE_INT_ARGB) + ) + ) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } + } + } + + // Skip alpha channel for TYPE_INT_RGB images + if (slowFilter(src.getRaster(), dst.getRaster()) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ + // TODO - uncomment + //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0) + //throw new ImagingOpException ("Unable to transform source"); + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return finalDst; + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (src == dst) { + // awt.252=Source can't be same as the destination + throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$ + } + + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else if (src.getNumBands() != dst.getNumBands()) { + // awt.253=Different number of bands in source and destination + throw new IllegalArgumentException(Messages.getString("awt.253")); //$NON-NLS-1$ + } + + if (slowFilter(src, dst) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + // TODO - uncomment + //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) + // throw new ImagingOpException("Unable to transform source"); + } + + return dst; + } + + // TODO remove when method is used + /** + * Ipp filter. + * + * @param src the src + * @param dst the dst + * @param imageType the image type + * + * @return the int + */ + @SuppressWarnings("unused") + private int ippFilter(Raster src, WritableRaster dst, int imageType) { + int srcStride, dstStride; + boolean skipChannel = false; + int channels; + int offsets[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_RGB: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth()*4; + dstStride = dst.getWidth()*4; + skipChannel = true; + break; + } + + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: { + channels = 4; + srcStride = src.getWidth()*4; + dstStride = dst.getWidth()*4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: + case BufferedImage.TYPE_BYTE_INDEXED: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth()*3; + dstStride = dst.getWidth()*3; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in native code? + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if ( + srcSM instanceof PixelInterleavedSampleModel && + dstSM instanceof PixelInterleavedSampleModel + ) { + // Check PixelInterleavedSampleModel + if ( + srcSM.getDataType() != DataBuffer.TYPE_BYTE || + dstSM.getDataType() != DataBuffer.TYPE_BYTE + ) { + return slowFilter(src, dst); + } + + channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels + if (channels != 1 && channels != 3 && channels != 4) { + return slowFilter(src, dst); + } + + int dataTypeSize = DataBuffer.getDataTypeSize(srcSM.getDataType()) / 8; + + srcStride = ((ComponentSampleModel) srcSM).getScanlineStride() * dataTypeSize; + dstStride = ((ComponentSampleModel) dstSM).getScanlineStride() * dataTypeSize; + } else if ( + srcSM instanceof SinglePixelPackedSampleModel && + dstSM instanceof SinglePixelPackedSampleModel + ) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM; + + // No IPP function for this type + if (sppsm1.getDataType() == DataBuffer.TYPE_USHORT) { + return slowFilter(src, dst); + } + + channels = sppsm1.getNumBands(); + // Have IPP functions for 1, 3 and 4 channels + if (channels != 1 && channels != 3 && channels != 4) { + return slowFilter(src, dst); + } + + // Check compatibility of sample models + if ( + sppsm1.getDataType() != sppsm2.getDataType() || + !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) || + !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks()) + ) { + return slowFilter(src, dst); + } + + for (int i=0; i> 8; + int py = sy >> 8; + if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { + Object val = src.getDataElements(px , py , null); + dst.setDataElements(x, y, val); + } + sx += hx; + sy += hy; + } + sx += vx; + sy += vy; + } + } else { + float pixel[] = null; + for (int y = minY; y < maxY; y++) { + for (int x = minX; x < maxX; x++) { + int px = sx >> 8; + int py = sy >> 8; + if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { + pixel = src.getPixel(px, py, pixel); + dst.setPixel(x, y, pixel); + } + sx += hx; + sy += hy; + } + sx += vx; + sy += vy; + } + } + + return 0; + } + + /** + * Ipp affine transform. + * + * @param m00 the m00 + * @param m01 the m01 + * @param m02 the m02 + * @param m10 the m10 + * @param m11 the m11 + * @param m12 the m12 + * @param src the src + * @param srcWidth the src width + * @param srcHeight the src height + * @param srcStride the src stride + * @param dst the dst + * @param dstWidth the dst width + * @param dstHeight the dst height + * @param dstStride the dst stride + * @param iType the i type + * @param channels the channels + * @param skipChannel the skip channel + * @param offsets the offsets + * + * @return the int + */ + private native int ippAffineTransform( + double m00, double m01, + double m02, double m10, + double m11, double m12, + Object src, int srcWidth, int srcHeight, int srcStride, + Object dst, int dstWidth, int dstHeight, int dstStride, + int iType, int channels, boolean skipChannel, + int offsets[]); +} \ No newline at end of file diff --git a/awt/java/awt/image/AreaAveragingScaleFilter.java b/awt/java/awt/image/AreaAveragingScaleFilter.java new file mode 100644 index 0000000..f4933db --- /dev/null +++ b/awt/java/awt/image/AreaAveragingScaleFilter.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.util.Arrays; + + +/** + * The AreaAveragingScaleFilter class scales the source image using + * area averaging algorithm. This algorithm provides a source image + * with a new image containing the resampled image. + */ +public class AreaAveragingScaleFilter extends ReplicateScaleFilter { + + /** The Constant rgbCM. */ + private static final ColorModel rgbCM = ColorModel.getRGBdefault(); + + /** The Constant averagingFlags. */ + private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT | + ImageConsumer.COMPLETESCANLINES); + + /** The reset. */ + private boolean reset = true; // Flag for used superclass filter + + /** The inited. */ + private boolean inited = false; // All data inited + + /** The sum_r. */ + private int sum_r[]; // Array for average Red samples + + /** The sum_g. */ + private int sum_g[]; // Array for average Green samples + + /** The sum_b. */ + private int sum_b[]; // Array for average Blue samples + + /** The sum_a. */ + private int sum_a[]; // Array for average Alpha samples + + /** The buff. */ + private int buff[]; // Stride buffer + + /** The avg factor. */ + private int avgFactor; // Global averaging factor + + /** The cached dy. */ + private int cachedDY; // Cached number of the destination scanline + + /** The cached dv rest. */ + private int cachedDVRest; // Cached value of rest src scanlines for sum + // pixel samples + // Because data if transfering by whole scanlines + // we are caching only Y coordinate values + + /** + * Instantiates a new AreaAveragingScaleFilter object which scales + * a source image with the specified width and height. + * + * @param width the scaled width of the image. + * @param height the scaled height of the image. + */ + public AreaAveragingScaleFilter(int width, int height) { + super(width, height); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) { + if(reset) { + super.setPixels(x, y, w, h, model, pixels, off, scansize); + } else { + setFilteredPixels(x, y, w, h, model, pixels, off, scansize); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) { + if(reset) { + super.setPixels(x, y, w, h, model, pixels, off, scansize); + } else { + setFilteredPixels(x, y, w, h, model, pixels, off, scansize); + } + } + + @Override + public void setHints(int hints) { + super.setHints(hints); + reset = ((hints & averagingFlags) != averagingFlags); + } + + /** + * This method implements the Area Averaging Scale filter. + * The description of algorithm is presented in Java API Specification. + * + * Arrays sum_r, sum_g, sum_b, sum_a have length equals width of destination + * image. In each array's element is accumulating pixel's component values, + * proportional to the area which source pixels will occupy in destination + * image. Then that values will divide by Global averaging + * factor (area of the destination image) for receiving + * average values of destination pixels. + * + * @param x - Src pixels X coordinate + * @param y - Src pixels Y coordinate + * @param w - width of the area of Src pixels + * @param h - height of the area of Src pixels + * @param model - Color Model of Src pixels + * @param pixels - array of Src pixels + * @param off - offset into the Src pixels array + * @param scansize - length of scanline in the pixels array + */ + private void setFilteredPixels(int x, int y, int w, int h, ColorModel model, Object pixels, int off, int scansize){ + if(!inited){ + initialize(); + } + + int srcX, srcY, dx, dy; + int svRest, dvRest, shRest, dhRest, vDif, hDif; + + if(y == 0){ + dy = 0; + dvRest = srcHeight; + }else{ + dy = cachedDY; + dvRest = cachedDVRest; + } + + srcY = y; + svRest = destHeight; + + int srcOff = off; + while (srcY < y + h) { + if (svRest < dvRest) { + vDif = svRest; + } else { + vDif = dvRest; + } + + srcX = 0; + dx = 0; + shRest = destWidth; + dhRest = srcWidth; + while (srcX < w) { + if (shRest < dhRest) { + hDif = shRest; + } else { + hDif = dhRest; + } + int avg = hDif * vDif; // calculation of contribution factor + + int rgb, pix; + if (pixels instanceof int[]) { + pix = ((int[]) pixels)[srcOff + srcX]; + } else { + pix = ((byte[]) pixels)[srcOff + srcX] & 0xff; + } + + rgb = model.getRGB(pix); + int a = rgb >>> 24; + int r = (rgb >> 16) & 0xff; + int g = (rgb >> 8) & 0xff; + int b = rgb & 0xff; + + // accumulating pixel's component values + sum_a[dx] += a * avg; + sum_r[dx] += r * avg; + sum_g[dx] += g * avg; + sum_b[dx] += b * avg; + + shRest -= hDif; + dhRest -= hDif; + + if (shRest == 0) { + srcX++; + shRest = destWidth; + } + + if (dhRest == 0) { + dx++; + dhRest = srcWidth; + } + } + + svRest -= vDif; + dvRest -= vDif; + + if (svRest == 0) { + svRest = destHeight; + srcY++; + srcOff += scansize; + } + + if (dvRest == 0) { + // averaging destination pixel's values + for(int i = 0; i < destWidth; i++){ + int a = (sum_a[i] / avgFactor) & 0xff; + int r = (sum_r[i] / avgFactor) & 0xff; + int g = (sum_g[i] / avgFactor) & 0xff; + int b = (sum_b[i] / avgFactor) & 0xff; + int frgb = (a << 24) | (r << 16) | (g << 8) | b; + buff[i] = frgb; + } + consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0, + destWidth); + dy++; + dvRest = srcHeight; + Arrays.fill(sum_a, 0); + Arrays.fill(sum_r, 0); + Arrays.fill(sum_g, 0); + Arrays.fill(sum_b, 0); + } + + } + + cachedDY = dy; + cachedDVRest = dvRest; + + } + + /** + * Initialization of the auxiliary data. + */ + private void initialize(){ + + sum_a = new int[destWidth]; + sum_r = new int[destWidth]; + sum_g = new int[destWidth]; + sum_b = new int[destWidth]; + + buff = new int[destWidth]; + outpixbuf = buff; + avgFactor = srcWidth * srcHeight; + + inited = true; + } +} + diff --git a/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java new file mode 100644 index 0000000..ce85ddd --- /dev/null +++ b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 23.11.2005 + * + */ +package java.awt.image; + +import java.awt.Image; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferDouble; +import java.awt.image.DataBufferFloat; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.DataBufferUShort; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.gl.GLVolatileImage; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.image.DataBufferListener; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class not part of public API. It useful for receiving package private + * data from other packages. + */ +class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { + + static void init(){ + inst = new AwtImageBackdoorAccessorImpl(); + } + + @Override + public Surface getImageSurface(Image image) { + if (image instanceof BufferedImage){ + return ((BufferedImage)image).getImageSurface(); + } else if (image instanceof GLVolatileImage){ + return ((GLVolatileImage)image).getImageSurface(); + } + return null; + } + + @Override + public boolean isGrayPallete(IndexColorModel icm){ + return icm.isGrayPallete(); + } + + @Override + public Object getData(DataBuffer db) { + if (db instanceof DataBufferByte){ + return ((DataBufferByte)db).getData(); + } else if (db instanceof DataBufferUShort){ + return ((DataBufferUShort)db).getData(); + } else if (db instanceof DataBufferShort){ + return ((DataBufferShort)db).getData(); + } else if (db instanceof DataBufferInt){ + return ((DataBufferInt)db).getData(); + } else if (db instanceof DataBufferFloat){ + return ((DataBufferFloat)db).getData(); + } else if (db instanceof DataBufferDouble){ + return ((DataBufferDouble)db).getData(); + } else { + // awt.235=Wrong Data Buffer type : {0} + throw new IllegalArgumentException(Messages.getString("awt.235", //$NON-NLS-1$ + db.getClass())); + } + } + + @Override + public int[] getDataInt(DataBuffer db) { + if (db instanceof DataBufferInt){ + return ((DataBufferInt)db).getData(); + } + return null; + } + + @Override + public byte[] getDataByte(DataBuffer db) { + if (db instanceof DataBufferByte){ + return ((DataBufferByte)db).getData(); + } + return null; + } + + @Override + public short[] getDataShort(DataBuffer db) { + if (db instanceof DataBufferShort){ + return ((DataBufferShort)db).getData(); + } + return null; + } + + @Override + public short[] getDataUShort(DataBuffer db) { + if (db instanceof DataBufferUShort){ + return ((DataBufferUShort)db).getData(); + } + return null; + } + + @Override + public double[] getDataDouble(DataBuffer db) { + if (db instanceof DataBufferDouble){ + return ((DataBufferDouble)db).getData(); + } + return null; + } + + @Override + public float[] getDataFloat(DataBuffer db) { + if (db instanceof DataBufferFloat){ + return ((DataBufferFloat)db).getData(); + } + return null; + } + + @Override + public void addDataBufferListener(DataBuffer db, DataBufferListener listener) { + db.addDataBufferListener(listener); + } + + @Override + public void removeDataBufferListener(DataBuffer db) { + db.removeDataBufferListener(); + } + + @Override + public void validate(DataBuffer db) { + db.validate(); + } + + @Override + public void releaseData(DataBuffer db) { + db.releaseData(); + } +} diff --git a/awt/java/awt/image/BandCombineOp.java b/awt/java/awt/image/BandCombineOp.java new file mode 100644 index 0000000..cd77a21 --- /dev/null +++ b/awt/java/awt/image/BandCombineOp.java @@ -0,0 +1,610 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Sep 20, 2005 + */ + +package java.awt.image; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BandCombineOp class translates coordinates from + * coordinates in the source Raster to coordinates in + * the destination Raster by an arbitrary linear combination + * of the bands in a source Raster, using a specified matrix. + * The number of bands in the matrix should equal to + * the number of bands in the source Raster plus 1. + */ +public class BandCombineOp implements RasterOp { + + /** The Constant offsets3c. */ + static final int offsets3c[] = {16, 8, 0}; + + /** The Constant offsets4ac. */ + static final int offsets4ac[] = {16, 8, 0, 24}; + + /** The Constant masks3c. */ + static final int masks3c[] = {0xFF0000, 0xFF00, 0xFF}; + + /** The Constant masks4ac. */ + static final int masks4ac[] = {0xFF0000, 0xFF00, 0xFF, 0xFF000000}; + + /** The Constant piOffsets. */ + private static final int piOffsets[] = {0, 1, 2}; + + /** The Constant piInvOffsets. */ + private static final int piInvOffsets[] = {2, 1, 0}; + + /** The Constant TYPE_BYTE3C. */ + private static final int TYPE_BYTE3C = 0; + + /** The Constant TYPE_BYTE4AC. */ + private static final int TYPE_BYTE4AC = 1; + + /** The Constant TYPE_USHORT3C. */ + private static final int TYPE_USHORT3C = 2; + + /** The Constant TYPE_SHORT3C. */ + private static final int TYPE_SHORT3C = 3; + + /** The mx width. */ + private int mxWidth; + + /** The mx height. */ + private int mxHeight; + + /** The matrix. */ + private float matrix[][]; + + /** The r hints. */ + private RenderingHints rHints; + + static { + // XXX - todo + //System.loadLibrary("imageops"); + } + + /** + * Instantiates a new BandCombineOp object with the specified + * matrix. + * + * @param matrix the specified matrix for band combining. + * @param hints the RenderingHints. + */ + public BandCombineOp(float matrix[][], RenderingHints hints) { + this.mxHeight = matrix.length; + this.mxWidth = matrix[0].length; + this.matrix = new float[mxHeight][mxWidth]; + + for (int i=0; i= dstInfo.channelsOrder.length) { + continue; + } + + for (int i=0; i= srcInfo.channelsOrder.length) { + break; + } + + reorderedMatrix[dstInfo.channelsOrder[j]*rmxWidth + srcInfo.channelsOrder[i]] = + matrix[j][i]; + } + if (mxWidth == rmxWidth) { + reorderedMatrix[(dstInfo.channelsOrder[j]+1)*rmxWidth - 1] = matrix[j][mxWidth-1]; + } + } + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + simpleCombineBands( + srcData, src.getWidth(), src.getHeight(), srcInfo.stride, srcInfo.channels, + dstData, dstInfo.stride, dstInfo.channels, + reorderedMatrix, offsets + ); + + return res; + } + + /** + * Very slow filter. + * + * @param src the src + * @param dst the dst + * + * @return the int + */ + private int verySlowFilter(Raster src, WritableRaster dst) { + int numBands = src.getNumBands(); + + int srcMinX = src.getMinX(); + int srcY = src.getMinY(); + + int dstMinX = dst.getMinX(); + int dstY = dst.getMinY(); + + int dX = src.getWidth();//< dst.getWidth() ? src.getWidth() : dst.getWidth(); + int dY = src.getHeight();//< dst.getHeight() ? src.getHeight() : dst.getHeight(); + + float sample; + int srcPixels[] = new int[numBands*dX*dY]; + int dstPixels[] = new int[mxHeight*dX*dY]; + + srcPixels = src.getPixels(srcMinX, srcY, dX, dY, srcPixels); + + if (numBands == mxWidth) { + for (int i=0, j=0; i numBands) { + // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model + throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ + } + + int indices[] = new int[bands.length]; + int offsets[] = new int[bands.length]; + + for (int i = 0; i < bands.length; i++) { + indices[i] = bankIndices[bands[i]]; + offsets[i] = bandOffsets[bands[i]]; + } + + return new BandedSampleModel(dataType, width, height, scanlineStride, + indices, offsets); + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + switch (dataType) { + case DataBuffer.TYPE_BYTE: { + byte bdata[]; + + if (obj == null) { + bdata = new byte[numBands]; + } else { + bdata = (byte[]) obj; + } + + for (int i = 0; i < numBands; i++) { + bdata[i] = (byte) getSample(x, y, i, data); + } + + obj = bdata; + break; + } + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: { + short sdata[]; + + if (obj == null) { + sdata = new short[numBands]; + } else { + sdata = (short[]) obj; + } + + for (int i = 0; i < numBands; i++) { + sdata[i] = (short) getSample(x, y, i, data); + } + + obj = sdata; + break; + } + case DataBuffer.TYPE_INT: { + int idata[]; + + if (obj == null) { + idata = new int[numBands]; + } else { + idata = (int[]) obj; + } + + for (int i = 0; i < numBands; i++) { + idata[i] = getSample(x, y, i, data); + } + + obj = idata; + break; + } + case DataBuffer.TYPE_FLOAT: { + float fdata[]; + + if (obj == null) { + fdata = new float[numBands]; + } else { + fdata = (float[]) obj; + } + + for (int i = 0; i < numBands; i++) { + fdata[i] = getSampleFloat(x, y, i, data); + } + + obj = fdata; + break; + } + case DataBuffer.TYPE_DOUBLE: { + double ddata[]; + + if (obj == null) { + ddata = new double[numBands]; + } else { + ddata = (double[]) obj; + } + + for (int i = 0; i < numBands; i++) { + ddata[i] = getSampleDouble(x, y, i, data); + } + + obj = ddata; + break; + } + } + + return obj; + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + int pixel[]; + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElem(bankIndices[b], y * scanlineStride + x + + bandOffsets[b]); + } + + @Override + public double getSampleDouble(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemDouble(bankIndices[b], y * scanlineStride + x + + bandOffsets[b]); + } + + @Override + public float getSampleFloat(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemFloat(bankIndices[b], y * scanlineStride + x + + bandOffsets[b]); + } + + @Override + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], + DataBuffer data) { + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + int tmp = hash >>> 8; + hash <<= 8; + hash |= tmp; + + return hash ^ 0x55; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + switch (dataType) { + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, bdata[i] & 0xff, data); + } + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, sdata[i] & 0xffff, data); + } + break; + + case DataBuffer.TYPE_INT: + int idata[] = (int[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, idata[i], data); + } + break; + + case DataBuffer.TYPE_FLOAT: + float fdata[] = (float[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, fdata[i], data); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double ddata[] = (double[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, ddata[i], data); + } + break; + } + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, int iArray[], + DataBuffer data) { + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + @Override + public void setSample(int x, int y, int b, double s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemDouble(bankIndices[b], y * scanlineStride + x + + bandOffsets[b], s); + } + + @Override + public void setSample(int x, int y, int b, float s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemFloat(bankIndices[b], y * scanlineStride + x + + bandOffsets[b], s); + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElem(bankIndices[b], y * scanlineStride + x + + bandOffsets[b], s); + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int iArray[], + DataBuffer data) { + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, iArray[idx++], data); + } + } + + } + +} + diff --git a/awt/java/awt/image/BufferStrategy.java b/awt/java/awt/image/BufferStrategy.java new file mode 100644 index 0000000..e0508f0 --- /dev/null +++ b/awt/java/awt/image/BufferStrategy.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.BufferCapabilities; +import java.awt.Graphics; + +/** + * The BufferStrategy abstract class provides an opportunity + * to organize the buffers for a Canvas or Window. The BufferStrategy + * implementation depends on hardware and software limitations. + * These limitations are detectible through the capabilities + * object which can be obtained by the GraphicsConfiguration of the Canvas + * or Window. + */ +public abstract class BufferStrategy { + + /** + * Returns true if the drawing buffer was lost since the last call + * of getDrawGraphics. + * + * @return true if the drawing buffer was lost since the last call + * of getDrawGraphics, false otherwise. + */ + public abstract boolean contentsLost(); + + /** + * Returns true if the drawing buffer is restored from a lost state. + * + * @return true if the drawing buffer is restored from a lost state, + * false otherwise. + */ + public abstract boolean contentsRestored(); + + /** + * Gets the BufferCapabilities of BufferStrategy. + * + * @return the BufferCapabilities of BufferStrategy. + */ + public abstract BufferCapabilities getCapabilities(); + + /** + * Gets the Graphics object to use to draw to the buffer. + * + * @return the Graphics object to use to draw to the buffer. + */ + public abstract Graphics getDrawGraphics(); + + /** + * Shows the next available buffer. + */ + public abstract void show(); + +} diff --git a/awt/java/awt/image/BufferedImage.java b/awt/java/awt/image/BufferedImage.java new file mode 100644 index 0000000..d305d66 --- /dev/null +++ b/awt/java/awt/image/BufferedImage.java @@ -0,0 +1,931 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import com.android.internal.awt.AndroidGraphics2D; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.apache.harmony.awt.gl.ImageSurface; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.image.BufferedImageSource; +import org.apache.harmony.awt.internal.nls.Messages; + + +/** + * The BufferedImage class describes an Image which contains a buffer + * of image data and includes a ColorModel and a Raster for this data. + * This class provides methods for obtaining and setting the Raster + * and for manipulating the ColorModel parameters. + */ +public class BufferedImage extends +Image implements WritableRenderedImage, Transparency{ + + /** + * The Constant TYPE_CUSTOM indicates that Image type + * is unknown. + */ + public static final int TYPE_CUSTOM = 0; + + /** + * The Constant TYPE_INT_RGB indicates an image with + * 8 bit RGB color components, it has a DirectColorModel + * without alpha. + */ + public static final int TYPE_INT_RGB = 1; + + /** + * The Constant TYPE_INT_ARGB indicates an image with + * 8 bit RGBA color components, it has a DirectColorModel + * with alpha. + */ + public static final int TYPE_INT_ARGB = 2; + + /** + * The Constant TYPE_INT_ARGB_PRE indicates an image with + * 8 bit RGBA color components, it has a DirectColorModel + * with alpha, and image data is premultiplied by alpha. + */ + public static final int TYPE_INT_ARGB_PRE = 3; + + /** + * The Constant TYPE_INT_BGR indicates an image with + * 8 bit RGB color components, BGR color model + * (with the colors Blue, Green, and Red). There is no + * alpha. The image has a DirectColorModel. + */ + public static final int TYPE_INT_BGR = 4; + + /** + * The Constant TYPE_3BYTE_BGR indicates an image with + * 8 bit RGB color components, BGR color model + * (with the colors Blue, Green, and Red stored in 3 bytes). + * There is no alpha. The image has a ComponentColorModel. + */ + public static final int TYPE_3BYTE_BGR = 5; + + /** + * The Constant TYPE_4BYTE_ABGR indicates an image with + * 8 bit RGBA color components stored in 3 bytes and 1 byte of alpha. + * It has a ComponentColorModel with alpha. + */ + public static final int TYPE_4BYTE_ABGR = 6; + + /** + * The Constant TYPE_4BYTE_ABGR_PRE indicates an image with + * 8 bit RGBA color components stored in 3 bytes and 1 byte + * for alpha. The image has a ComponentColorModel with alpha. + * The color data is premultiplied with alpha. + */ + public static final int TYPE_4BYTE_ABGR_PRE = 7; + + /** + * The Constant TYPE_USHORT_565_RGB indicates an image with + * 565 RGB color components (5-bits red, 6-bits green, 5-bits blue) + * with no alpha. This image has a DirectColorModel. + */ + public static final int TYPE_USHORT_565_RGB = 8; + + /** + * The Constant TYPE_USHORT_555_RGB indicates an image with + * 555 RGB color components (5-bits red, 5-bits green, 5-bits blue) + * with no alpha. This image has a DirectColorModel. + */ + public static final int TYPE_USHORT_555_RGB = 9; + + /** + * The Constant TYPE_BYTE_GRAY indicates a unsigned byte + * image. This image has a ComponentColorModel with + * a CS_GRAY ColorSpace. + */ + public static final int TYPE_BYTE_GRAY = 10; + + /** + * The Constant TYPE_USHORT_GRAY indicates an unsigned short + * image. This image has a ComponentColorModel with a CS_GRAY + * ColorSpace. + */ + public static final int TYPE_USHORT_GRAY = 11; + + /** + * The Constant TYPE_BYTE_BINARY indicates an opaque byte-packed + * 1, 2 or 4 bit image. The image has an IndexColorModel without + * alpha. + */ + public static final int TYPE_BYTE_BINARY = 12; + + /** + * The Constant TYPE_BYTE_INDEXED indicates an indexed byte image. + */ + public static final int TYPE_BYTE_INDEXED = 13; + + /** The Constant ALPHA_MASK. */ + private static final int ALPHA_MASK = 0xff000000; + + /** The Constant RED_MASK. */ + private static final int RED_MASK = 0x00ff0000; + + /** The Constant GREEN_MASK. */ + private static final int GREEN_MASK = 0x0000ff00; + + /** The Constant BLUE_MASK. */ + private static final int BLUE_MASK = 0x000000ff; + + /** The Constant RED_BGR_MASK. */ + private static final int RED_BGR_MASK = 0x000000ff; + + /** The Constant GREEN_BGR_MASK. */ + private static final int GREEN_BGR_MASK = 0x0000ff00; + + /** The Constant BLUE_BGR_MASK. */ + private static final int BLUE_BGR_MASK = 0x00ff0000; + + /** The Constant RED_565_MASK. */ + private static final int RED_565_MASK = 0xf800; + + /** The Constant GREEN_565_MASK. */ + private static final int GREEN_565_MASK = 0x07e0; + + /** The Constant BLUE_565_MASK. */ + private static final int BLUE_565_MASK = 0x001f; + + /** The Constant RED_555_MASK. */ + private static final int RED_555_MASK = 0x7c00; + + /** The Constant GREEN_555_MASK. */ + private static final int GREEN_555_MASK = 0x03e0; + + /** The Constant BLUE_555_MASK. */ + private static final int BLUE_555_MASK = 0x001f; + + /** The cm. */ + private ColorModel cm; + + /** The raster. */ + private final WritableRaster raster; + + /** The image type. */ + private final int imageType; + + /** The properties. */ + private Hashtable properties; + + // Surface of the Buffered Image - used for blitting one Buffered Image + // on the other one or on the Component + /** The image surf. */ + private final ImageSurface imageSurf; + + /** + * Instantiates a new BufferedImage with the specified ColorModel, + * and WritableRaster objects. The Raster data can be + * be divided or multiplied by alpha. It depends on the + * alphaPremultiplied state in the ColorModel. + * + * @param cm the ColorModel of the new image. + * @param raster the WritableRaster of the new image. + * @param isRasterPremultiplied if true the data of the specified + * Raster is premultiplied by alpha. + * @param properties the properties of new Image. + */ + public BufferedImage(ColorModel cm, WritableRaster raster, + boolean isRasterPremultiplied, Hashtable properties) { + if (!cm.isCompatibleRaster(raster)) { + // awt.4D=The raster is incompatible with this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$ + } + + if (raster.getMinX() != 0 || raster.getMinY() != 0) { + // awt.228=minX or minY of this raster not equal to zero + throw new IllegalArgumentException(Messages.getString("awt.228")); //$NON-NLS-1$ + } + + this.cm = cm; + this.raster = raster; + this.properties = properties; + + coerceData(isRasterPremultiplied); + + imageType = Surface.getType(cm, raster); + + imageSurf = createImageSurface(imageType); + } + + /** + * Instantiates a new BufferedImage with the specified width, height + * predefined image type (TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED) + * and the specified IndexColorModel. + * + * @param width the width of new image. + * @param height the height of new image. + * @param imageType the predefined image type. + * @param cm the specified IndexColorModel. + */ + public BufferedImage(int width, int height, int imageType, + IndexColorModel cm) { + switch (imageType) { + case TYPE_BYTE_BINARY: + if (cm.hasAlpha()) { + // awt.227=This image type can't have alpha + throw new IllegalArgumentException(Messages.getString("awt.227")); //$NON-NLS-1$ + } + int pixel_bits = 0; + int mapSize = cm.getMapSize(); + if (mapSize <= 2) { + pixel_bits = 1; + } else if (mapSize <= 4) { + pixel_bits = 2; + } else if (mapSize <= 16) { + pixel_bits = 4; + } else { + // awt.221=The imageType is TYPE_BYTE_BINARY and the color map has more than 16 entries + throw new IllegalArgumentException(Messages.getString("awt.221")); //$NON-NLS-1$ + } + + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, + height, 1, pixel_bits, null); + break; + + case TYPE_BYTE_INDEXED: + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + width, height, 1, null); + break; + + default: + // awt.222=The imageType is not TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED + throw new IllegalArgumentException(Messages.getString("awt.222")); //$NON-NLS-1$ + + } + + if (!cm.isCompatibleRaster(raster)) { + // awt.223=The imageType is not compatible with ColorModel + throw new IllegalArgumentException(Messages.getString("awt.223")); //$NON-NLS-1$ + } + + this.cm = cm; + this.imageType = imageType; + imageSurf = createImageSurface(imageType); + + } + + /** + * Instantiates a new BufferedImage with the specified width, height + * and predefined image type. + * + * @param width the width of new image. + * @param height the height of new image. + * @param imageType the predefined image type. + */ + public BufferedImage(int width, int height, int imageType) { + + switch (imageType) { + case TYPE_INT_RGB: + cm = new DirectColorModel(24, RED_MASK, GREEN_MASK, BLUE_MASK); + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_ARGB: + cm = ColorModel.getRGBdefault(); + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_ARGB_PRE: + cm = new DirectColorModel( + ColorSpace.getInstance(ColorSpace.CS_sRGB), + 32, + RED_MASK, + GREEN_MASK, + BLUE_MASK, + ALPHA_MASK, + true, + DataBuffer.TYPE_INT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_BGR: + cm = new DirectColorModel(24, + RED_BGR_MASK, + GREEN_BGR_MASK, + BLUE_BGR_MASK); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_3BYTE_BGR: { + int bits[] = { 8, 8, 8 }; + int bandOffsets[] = { 2, 1, 0 }; + cm = new ComponentColorModel( + ColorSpace.getInstance(ColorSpace.CS_sRGB), + bits, + false, + false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + width, height, width * 3, 3, bandOffsets, null); + } + break; + + case TYPE_4BYTE_ABGR: { + int bits[] = { 8, 8, 8, 8 }; + int bandOffsets[] = { 3, 2, 1, 0 }; + cm = new ComponentColorModel( + ColorSpace.getInstance(ColorSpace.CS_sRGB), + bits, + true, + false, + Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + width, height, width * 4, 4, bandOffsets, null); + } + break; + + case TYPE_4BYTE_ABGR_PRE: { + int bits[] = { 8, 8, 8, 8 }; + int bandOffsets[] = { 3, 2, 1, 0 }; + cm = new ComponentColorModel( + ColorSpace.getInstance(ColorSpace.CS_sRGB), + bits, + true, + true, + Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + width, height, width * 4, 4, bandOffsets, null); + } + break; + + case TYPE_USHORT_565_RGB: + cm = new DirectColorModel( + ColorSpace.getInstance(ColorSpace.CS_sRGB), + 16, + RED_565_MASK, + GREEN_565_MASK, + BLUE_565_MASK, + 0, + false, + DataBuffer.TYPE_USHORT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_USHORT_555_RGB: + cm = new DirectColorModel( + ColorSpace.getInstance(ColorSpace.CS_sRGB), + 15, + RED_555_MASK, + GREEN_555_MASK, + BLUE_555_MASK, + 0, + false, + DataBuffer.TYPE_USHORT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_BYTE_GRAY: { + int bits[] = { 8 }; + cm = new ComponentColorModel( + ColorSpace.getInstance(ColorSpace.CS_GRAY), + bits, + false, + false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + + raster = cm.createCompatibleWritableRaster(width, height); + } + break; + + case TYPE_USHORT_GRAY: { + int bits[] = { 16 }; + cm = new ComponentColorModel( + ColorSpace.getInstance(ColorSpace.CS_GRAY), + bits, + false, + false, + Transparency.OPAQUE, + DataBuffer.TYPE_USHORT); + raster = cm.createCompatibleWritableRaster(width, height); + } + break; + + case TYPE_BYTE_BINARY: { + int colorMap[] = { 0, 0xffffff }; + cm = new IndexColorModel(1, 2, colorMap, 0, false, -1, + DataBuffer.TYPE_BYTE); + + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, + height, 1, 1, null); + } + break; + + case TYPE_BYTE_INDEXED: { + int colorMap[] = new int[256]; + int i = 0; + for (int r = 0; r < 256; r += 51) { + for (int g = 0; g < 256; g += 51) { + for (int b = 0; b < 256; b += 51) { + colorMap[i] = (r << 16) | (g << 8) | b; + i++; + } + } + } + + int gray = 0x12; + for (; i < 256; i++, gray += 6) { + colorMap[i] = (gray << 16) | (gray << 8) | gray; + } + cm = new IndexColorModel(8, 256, colorMap, 0, false, -1, + DataBuffer.TYPE_BYTE); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + width, height, 1, null); + + } + break; + default: + // awt.224=Unknown image type + throw new IllegalArgumentException(Messages.getString("awt.224")); //$NON-NLS-1$ + } + this.imageType = imageType; + imageSurf = createImageSurface(imageType); + } + + @Override + public Object getProperty(String name, ImageObserver observer) { + return getProperty(name); + } + + public Object getProperty(String name) { + if(name == null) { + // awt.225=Property name is null + throw new NullPointerException(Messages.getString("awt.225")); //$NON-NLS-1$ + } + if (properties == null) { + return Image.UndefinedProperty; + } + Object property = properties.get(name); + if (property == null) { + property = Image.UndefinedProperty; + } + return property; + } + + public WritableRaster copyData(WritableRaster outRaster) { + if (outRaster == null) { + outRaster = Raster.createWritableRaster(raster.getSampleModel(), + new Point(raster.getSampleModelTranslateX(), + raster.getSampleModelTranslateY())); + } + + int w = outRaster.getWidth(); + int h = outRaster.getHeight(); + int minX = outRaster.getMinX(); + int minY = outRaster.getMinY(); + + Object data = null; + + data = raster.getDataElements(minX, minY, w, h, data); + outRaster.setDataElements(minX, minY, w, h, data); + + return outRaster; + } + + public Raster getData(Rectangle rect) { + int minX = rect.x; + int minY = rect.y; + int w = rect.width; + int h = rect.height; + + SampleModel sm = raster.getSampleModel(); + SampleModel nsm = sm.createCompatibleSampleModel(w, h); + WritableRaster outr = Raster.createWritableRaster(nsm, + rect.getLocation()); + Object data = null; + + data = raster.getDataElements(minX, minY, w, h, data); + outr.setDataElements(minX, minY, w, h, data); + return outr; + } + + public Vector getSources() { + return null; + } + + public String[] getPropertyNames() { + if (properties == null) { + return null; + } + Vector v = new Vector(); + for (Enumeration e = properties.keys(); e.hasMoreElements();) { + try { + v.add((String) e.nextElement()); + } catch (ClassCastException ex) { + } + } + int size = v.size(); + if (size > 0) { + String names[] = new String[size]; + for (int i = 0; i < size; i++) { + names[i] = v.elementAt(i); + } + return names; + } + return null; + } + + /** + * Returns the string representation of this BufferedImage object. + * + * @return the string representation of this BufferedImage object. + */ + @Override + public String toString() { + return "BufferedImage@" + Integer.toHexString(hashCode()) + //$NON-NLS-1$ + ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + public WritableRaster getWritableTile(int tileX, int tileY) { + return raster; + } + + /** + * Gets the WritableRaster of this BufferedImage. + * + * @return the WritableRaster of this BufferedImage. + */ + public WritableRaster getRaster() { + return raster; + } + + /** + * Gets a WritableRaster object which contains the alpha channel of + * BufferedImage object with ColorModel objects that supports + * a separate alpha channel such as ComponentColorModel + * or DirectColorModel. + * + * @return the WritableRaster object which contains the alpha + * channel of this BufferedImage. + */ + public WritableRaster getAlphaRaster() { + return cm.getAlphaRaster(raster); + } + + public void removeTileObserver(TileObserver to) { + } + + public void addTileObserver(TileObserver to) { + } + + public SampleModel getSampleModel() { + return raster.getSampleModel(); + } + + public void setData(Raster r) { + + Rectangle from = r.getBounds(); + Rectangle to = raster.getBounds(); + Rectangle intersection = to.intersection(from); + + int minX = intersection.x; + int minY = intersection.y; + int w = intersection.width; + int h = intersection.height; + + Object data = null; + + data = r.getDataElements(minX, minY, w, h, data); + raster.setDataElements(minX, minY, w, h, data); + } + + public Raster getTile(int tileX, int tileY) { + if (tileX == 0 && tileY == 0) { + return raster; + } + // awt.226=Both tileX and tileY are not equal to 0 + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$ + } + + public Raster getData() { + int w = raster.getWidth(); + int h = raster.getHeight(); + int minX = raster.getMinX(); + int minY = raster.getMinY(); + + WritableRaster outr = Raster.createWritableRaster( + raster.getSampleModel(), + new Point(raster.getSampleModelTranslateX(), + raster.getSampleModelTranslateY())); + + Object data = null; + + data = raster.getDataElements(minX, minY, w, h, data); + outr.setDataElements(minX, minY, w, h, data); + + return outr; + } + + @Override + public ImageProducer getSource() { + return new BufferedImageSource(this, properties); + } + + @Override + public int getWidth(ImageObserver observer) { + return raster.getWidth(); + } + + @Override + public int getHeight(ImageObserver observer) { + return raster.getHeight(); + } + + public ColorModel getColorModel() { + return cm; + } + + /** + * Gets the rectangular area of this BufferedImage as a subimage. + * + * @param x the x coordinate. + * @param y the y coordinate. + * @param w the width of the subimage. + * @param h the height of the subimage. + * + * @return the BufferedImage. + */ + public BufferedImage getSubimage(int x, int y, int w, int h) { + WritableRaster wr = raster.createWritableChild(x, y, w, h, 0, 0, null); + return new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), properties); + } + + public Point[] getWritableTileIndices() { + Point points[] = new Point[1]; + points[0] = new Point(0, 0); + return points; + } + + /** + * Creates the Graphics2D object which allows to draw into + * this BufferedImage. + * + * @return the graphics2D object. + */ + public Graphics2D createGraphics() { + GraphicsEnvironment ge = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + //return ge.createGraphics(this); + //???AWT hack, FIXME + //return AndroidGraphics2D.getInstance(); + //throw new RuntimeException("Not implemented!"); + return null; + } + + @Override + public Graphics getGraphics() { + return createGraphics(); + } + + /** + * Coerces the data to achieve the state which is specified by + * the isAlphaPremultiplied variable. + * + * @param isAlphaPremultiplied the is alpha premultiplied state. + */ + public void coerceData(boolean isAlphaPremultiplied) { + if (cm.hasAlpha() && + cm.isAlphaPremultiplied() != isAlphaPremultiplied) { + cm = cm.coerceData(raster, isAlphaPremultiplied); + } + } + + /** + * Gets an array of colors in the TYPE_INT_ARGB color model and + * default sRGB colorspace of the specified area of this + * BufferedImage. The result array is composed by the following + * algirithm: + *

+ * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)] + * + * @param startX the start X area coordinate. + * @param startY the start Y area coordinate. + * @param w the width of the area. + * @param h the height of the area. + * @param rgbArray the result array will be stored to this array. + * @param offset the offset of the rgbArray array. + * @param scansize the scanline stride for the rgbArray. + * + * @return an array of colors for the specified area. + */ + public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, + int offset, int scansize) { + if (rgbArray == null) { + rgbArray = new int[offset + h * scansize]; + } + + int off = offset; + for (int y = startY; y < startY + h; y++, off += scansize) { + int i = off; + for (int x = startX; x < startX + w; x++, i++) { + rgbArray[i] = cm.getRGB(raster.getDataElements(x, y, null)); + } + } + return rgbArray; + } + + /** + * Sets RGB values from the specified array to the specified + * BufferedImage area. The pixels are in the default RGB color model + * (TYPE_INT_ARGB) and default sRGB color space. + * + * @param startX the start X coordinate. + * @param startY the start Y coordinate. + * @param w the width of the BufferedImage area. + * @param h the height of the BufferedImage area. + * @param rgbArray the array of RGB values. + * @param offset the offset of the rgbArray array. + * @param scansize the scanline stride for the rgbArray. + */ + public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, + int offset, int scansize) { + int off = offset; + for (int y = startY; y < startY + h; y++, off += scansize) { + int i = off; + for (int x = startX; x < startX + w; x++, i++) { + raster.setDataElements(x, y, + cm.getDataElements(rgbArray[i], null)); + } + } + } + + /** + * Sets a the specified RGB value to the specified pixel of + * this BufferedImage. The pixel should be in the default + * RGB color model (TYPE_INT_ARGB) and default sRGB color space. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param rgb the RGB value to be set. + */ + public synchronized void setRGB(int x, int y, int rgb) { + raster.setDataElements(x, y, cm.getDataElements(rgb, null)); + } + + public boolean isTileWritable(int tileX, int tileY) { + if (tileX == 0 && tileY == 0) { + return true; + } + // awt.226=Both tileX and tileY are not equal to 0 + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$ + } + + public void releaseWritableTile(int tileX, int tileY) { + } + + /** + * Gets a color in the TYPE_INT_ARGB color model and default + * sRGB colorspace of the specified pixel. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * + * @return the color of the specified pixel in the TYPE_INT_ARGB + * color model and default sRGB colorspace. + */ + public int getRGB(int x, int y) { + return cm.getRGB(raster.getDataElements(x, y, null)); + } + + /** + * Returnes true if alpha is premultiplied, + * false if alpha is not premultiplied or there is no alpha. + * + * @return true if alpha is premultiplied, + * false if alpha is not premultiplied or there is no alpha. + */ + public boolean isAlphaPremultiplied() { + return cm.isAlphaPremultiplied(); + } + + public boolean hasTileWriters() { + return true; + } + + @Override + public void flush() { + imageSurf.dispose(); + } + + public int getWidth() { + return raster.getWidth(); + } + + /** + * Gets the image type. + * + * @return the image type. + */ + public int getType() { + return imageType; + } + + public int getTileWidth() { + return raster.getWidth(); + } + + public int getTileHeight() { + return raster.getHeight(); + } + + public int getTileGridYOffset() { + return raster.getSampleModelTranslateY(); + } + + public int getTileGridXOffset() { + return raster.getSampleModelTranslateX(); + } + + public int getNumYTiles() { + return 1; + } + + public int getNumXTiles() { + return 1; + } + + public int getMinY() { + return raster.getMinY(); + } + + public int getMinX() { + return raster.getMinX(); + } + + public int getMinTileY() { + return 0; + } + + public int getMinTileX() { + return 0; + } + + public int getHeight() { + return raster.getHeight(); + } + + /** + * Creates the image surface. + * + * @param type the type + * + * @return the image surface + */ + private ImageSurface createImageSurface(int type) { + return new ImageSurface(getColorModel(), getRaster(), type); + } + + /** + * Gets the image surface. + * + * @return the image surface + */ + ImageSurface getImageSurface() { + return imageSurf; + } + + public int getTransparency() { + return cm.getTransparency(); + } +} + diff --git a/awt/java/awt/image/BufferedImageFilter.java b/awt/java/awt/image/BufferedImageFilter.java new file mode 100644 index 0000000..44b3c2e --- /dev/null +++ b/awt/java/awt/image/BufferedImageFilter.java @@ -0,0 +1,375 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BufferedImageFilter class provides filtering operations to + * the BufferedImage objects using operators which implement + * BufferedImageOp interface. + */ +public class BufferedImageFilter extends ImageFilter implements Cloneable { + + /** The Constant accessor. */ + private static final AwtImageBackdoorAccessor accessor = AwtImageBackdoorAccessor.getInstance(); + + /** The op. */ + private BufferedImageOp op; + + /** The raster. */ + private WritableRaster raster; + + /** The i data. */ + private int iData[]; + + /** The b data. */ + private byte bData[]; + + /** The width. */ + private int width; + + /** The height. */ + private int height; + + /** The cm. */ + private ColorModel cm; + + /** The forced rgb. */ + private boolean forcedRGB = false; + + /** The transfer type. */ + private int transferType = DataBuffer.TYPE_UNDEFINED; + + /** + * Instantiates a new BufferedImageFilter with the specified + * BufferedImageOp operator. + * + * @param op the specified BufferedImageOp operator. + * + * @throws NullPointerException if BufferedImageOp is null. + */ + public BufferedImageFilter(BufferedImageOp op) { + if (op == null) { + throw new NullPointerException(Messages.getString("awt.05")); //$NON-NLS-1$ + } + this.op = op; + } + + /** + * Gets the BufferedImageOp operator associated with this + * BufferedImageFilter object. + * + * @return the BufferedImageOp associated with this + * BufferedImageFilter object. + */ + public BufferedImageOp getBufferedImageOp() { + return op; + } + + @Override + public void setDimensions(int width, int height) { + this.width = width; + this.height = height; + // Stop image consuming if no pixels expected. + if (width <= 0 || height <= 0) { + consumer.imageComplete(ImageConsumer.STATICIMAGEDONE); + reset(); + } + } + + @Override + public void setColorModel(ColorModel model) { + if (this.cm != null && this.cm != model && raster != null) { + forceRGB(); + } else { + this.cm = model; + } + } + + @Override + public void setPixels( + int x, int y, int + w, int h, + ColorModel model, byte[] pixels, + int off, int scansize + ) { + setPixels(x, y, w, h, model, pixels, off, scansize, true); + } + + @Override + public void setPixels( + int x, int y, + int w, int h, + ColorModel model, int[] pixels, + int off, int scansize + ) { + setPixels(x, y, w, h, model, pixels, off, scansize, false); + } + + @Override + public void imageComplete(int status) { + if (status == STATICIMAGEDONE || status == SINGLEFRAMEDONE) { + BufferedImage bim = new BufferedImage(cm, raster, cm.isAlphaPremultiplied, null); + bim = op.filter(bim, null); + DataBuffer dstDb = bim.getRaster().getDataBuffer(); + ColorModel dstCm = bim.getColorModel(); + int dstW = bim.getWidth(); + int dstH = bim.getHeight(); + + consumer.setDimensions(dstW, dstH); + + if (dstDb.getDataType() == DataBuffer.TYPE_INT) { + consumer.setColorModel(dstCm); + consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataInt(dstDb), 0, dstW); + } else if (dstDb.getDataType() == DataBuffer.TYPE_BYTE) { + consumer.setColorModel(dstCm); + consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataByte(dstDb), 0, dstW); + } else { + int dstData[] = bim.getRGB(0, 0, dstW, dstH, null, 0, dstW); + dstCm = ColorModel.getRGBdefault(); + consumer.setColorModel(dstCm); + consumer.setPixels(0, 0, dstW, dstH, dstCm, dstData, 0, dstW); + } + } else if (status == IMAGEERROR || status == IMAGEABORTED) { + reset(); + } + + consumer.imageComplete(status); + } + + /** + * Sets the pixels. + * + * @param x the x + * @param y the y + * @param w the w + * @param h the h + * @param model the model + * @param pixels the pixels + * @param off the off + * @param scansize the scansize + * @param isByteData the is byte data + */ + private void setPixels( + int x, int y, + int w, int h, + ColorModel model, Object pixels, + int off, int scansize, boolean isByteData + ) { + // Check bounds + // Need to copy only the pixels that will fit into the destination area + if (x < 0) { + w -= x; + off += x; + x = 0; + } + + if (y < 0) { + h -= y; + off += y * scansize; + y = 0; + } + + if (x + w > width) { + w = width - x; + } + + if (y + h > height) { + h = height - y; + } + + if (w <= 0 || h <= 0) { + return; + } + + // Check model + if (this.cm == null) { + setColorModel(model); + } else if (model == null) { + model = this.cm; + } else if (!model.equals(this.cm)) { + forceRGB(); + } + + boolean canArraycopy; + // Process pixels + switch(transferType) { + case DataBuffer.TYPE_UNDEFINED: { + if (isByteData) { + transferType = DataBuffer.TYPE_BYTE; + createRaster(transferType); + //bData = new byte[width*height]; + canArraycopy = !forcedRGB; + break; + } + transferType = DataBuffer.TYPE_INT; + createRaster(transferType); + //iData = new int[width*height]; + canArraycopy = !forcedRGB || model.equals(ColorModel.getRGBdefault()); + break; + } // And proceed to copy the pixels + case DataBuffer.TYPE_INT: { + if (isByteData) { // There are int data already but the new data are bytes + forceRGB(); + canArraycopy = false; + break; + } else if (!forcedRGB || model.equals(ColorModel.getRGBdefault())) { + canArraycopy = true; + break; + } // Else fallback to the RGB conversion + } + case DataBuffer.TYPE_BYTE: { + if (isByteData && !forcedRGB) { + canArraycopy = true; + break; + } + + // RGB conversion + canArraycopy = false; + break; + } default: { + throw new IllegalStateException(Messages.getString("awt.06")); //$NON-NLS-1$ + } + } + + off += x; + int maxOffset = off + h * scansize; + int dstOffset = x + y * width; + + if (canArraycopy) { + Object dstArray = isByteData ? (Object) bData : (Object) iData; + for (; off < maxOffset; off += scansize, dstOffset += width) { + System.arraycopy(pixels, off, dstArray, dstOffset, w); + } + } else { + // RGB conversion + for (; off < maxOffset; off += scansize, dstOffset += width) { + int srcPos = off; + int dstPos = dstOffset; + int maxDstPos = dstOffset + w; + for (; dstPos < maxDstPos; dstPos++, srcPos++) { + iData[dstPos] = model.getRGB( + isByteData ? + ((byte[])pixels)[srcPos] : + ((int[])pixels)[srcPos] + ); + } + } + } + } + + /** + * Force rgb. + */ + private void forceRGB() { + if (!forcedRGB) { + forcedRGB = true; + int size = width*height; + int rgbData[] = new int[size]; + + if (bData != null) { + for (int i=0; i profiles = new ArrayList(10); + ArrayList sequence = new ArrayList(10); + + // We need this profile anyway + ICC_Profile xyzProfile = ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ); + + Object conversionFirst = null, conversionLast = null; + int conversionLength = conversionSequence.length; + if (conversionLength > 0) { + conversionFirst = conversionSequence[0]; + conversionLast = conversionSequence[conversionLength-1]; + } + + boolean iccSequenceStarted = false; + + if (src != conversionFirst && src != null) { + if (src instanceof ICC_Profile) { + profiles.add(src); + iccSequenceStarted = true; + } else { + profiles.add(xyzProfile); + sequence.add(src); // Add non-ICC color space to the sequence + } + } else { + profiles.add(xyzProfile); + } + + for (int i=0; i 1) { + sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0]))); + + // Add non-ICC color space to the sequence + sequence.add(conversionSequence[i]); + } + + profiles.clear(); + profiles.add(xyzProfile); + iccSequenceStarted = false; // Sequence of ICC profiles is processed + } else { // Add non-ICC color space to the sequence + sequence.add(conversionSequence[i]); + } + } + + if (dst != conversionLast && dst != null) { // Add last profile if needed + if (dst instanceof ICC_Profile) { + profiles.add(dst); + iccSequenceStarted = true; + } else if (iccSequenceStarted) { + profiles.add(xyzProfile); + } else { + sequence.add(dst); // Add last non-ICC color space to the sequence + } + } + + if (iccSequenceStarted) { // Make last transform if needed + sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0]))); + if (dst != null && !(dst instanceof ICC_Profile)) { + sequence.add(dst); // Add last non-ICC color space to the + // sequence + } + } + + // Calculate max number of components + // This number will be used for memory allocation + maxComponents = 0; + Object o; + for (int i=0, size = sequence.size(); i t.getNumInputChannels() + 1) ? + maxComponents : + t.getNumInputChannels() + 1; + maxComponents = + (maxComponents > t.getNumOutputChannels() + 1) ? + maxComponents : + t.getNumOutputChannels() + 1; + } else { + ColorSpace cs = (ColorSpace) o; + maxComponents = + (maxComponents > cs.getNumComponents() + 1) ? + maxComponents : + cs.getNumComponents() + 1; + } + } + + return sequence.toArray(); + } + } + + /** + * Instantiates a new ColorConvertOp object using two specified + * ColorSpace objects. + * + * @param srcCS the source ColorSpace. + * @param dstCS the destination ColorSpace. + * @param hints the RenderingHints object used for + * the color conversion, or null. + */ + public ColorConvertOp(ColorSpace srcCS, ColorSpace dstCS, RenderingHints hints) { + if (srcCS == null || dstCS == null) { + throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$ + } + + renderingHints = hints; + + boolean srcICC = srcCS instanceof ICC_ColorSpace; + boolean dstICC = dstCS instanceof ICC_ColorSpace; + + if (srcICC && dstICC) { + conversionSequence = new ICC_Profile[2]; + } else { + conversionSequence = new Object[2]; + isICC = false; + } + + if (srcICC) { + conversionSequence[0] = ((ICC_ColorSpace) srcCS).getProfile(); + } else { + conversionSequence[0] = srcCS; + } + + if (dstICC) { + conversionSequence[1] = ((ICC_ColorSpace) dstCS).getProfile(); + } else { + conversionSequence[1] = dstCS; + } + } + + /** + * Instantiates a new ColorConvertOp object from the specified + * ICC_Profile objects. + * + * @param profiles the array of ICC_Profile objects. + * @param hints the RenderingHints object used for + * the color conversion, or null. + */ + public ColorConvertOp(ICC_Profile profiles[], RenderingHints hints) { + if (profiles == null) { + throw new NullPointerException(Messages.getString("awt.25C")); //$NON-NLS-1$ + } + + renderingHints = hints; + + // This array is not used in the program logic, so don't need to copy it + // Store it only to return back + midProfiles = profiles; + + conversionSequence = new ICC_Profile[midProfiles.length]; + + // Add profiles to the conversion sequence + for (int i=0, length=midProfiles.length; i Transparency.TRANSLUCENT) { + // awt.270=The transparency is not a valid value + throw new IllegalArgumentException(Messages.getString("awt.270")); //$NON-NLS-1$ + } + + this.pixel_bits = pixel_bits; + this.bits = bits.clone(); + + maxValues = new int[bits.length]; + maxBitLength = 0; + for (int i = 0; i < maxValues.length; i++) { + maxValues[i] = (1 << bits[i]) - 1; + if (bits[i] > maxBitLength) { + maxBitLength = bits[i]; + } + } + + cs = cspace; + this.hasAlpha = hasAlpha; + this.isAlphaPremultiplied = isAlphaPremultiplied; + numColorComponents = cs.getNumComponents(); + + if (hasAlpha) { + numComponents = numColorComponents + 1; + } else { + numComponents = numColorComponents; + } + + this.transparency = transparency; + this.transferType = transferType; + + } + + /** + * Instantiates a new color model with the specified pixel bit depth. + * The transferType is chosen based on the pixel bits, and the other + * data fields are given default values. + * + * @param bits the array of component masks + */ + public ColorModel(int bits) { + + if (bits < 1) { + // awt.271=The number of bits in bits is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.271")); //$NON-NLS-1$ + } + + pixel_bits = bits; + transferType = getTransferType(bits); + cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + hasAlpha = true; + isAlphaPremultiplied = false; + transparency = Transparency.TRANSLUCENT; + + numColorComponents = 3; + numComponents = 4; + + this.bits = null; + } + + /** + * Gets the data elements from the specified component array, transforming + * them according to rules of the color model. + * + * @param components the components + * @param offset the offset in the normComponents array + * @param obj the array that the result is written to: an array of values + * whose length must be the number of components used by the color model and + * whose type depends on the transfer type (based on the pixel bit depth), + * or null to have the appropriate array created + * + * @return the array of data elements + */ + public Object getDataElements(int[] components, int offset, Object obj) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the data elements from the specified array of normalized components. + * + * @param normComponents the array normalized components + * @param normOffset the offset in the normComponents array + * @param obj the array that the result is written to: an array of values + * whose length must be the number of components used by the color model and + * whose type depends on the transfer type (based on the pixel bit depth), + * or null to have the appropriate array created + * + * @return the array of data elements + */ + public Object getDataElements(float[] normComponents, int normOffset, + Object obj) { + int unnormComponents[] = getUnnormalizedComponents(normComponents, + normOffset, null, 0); + return getDataElements(unnormComponents, 0, obj); + } + + /** + * Gets the data elements corresponding to the pixel determined by the + * RGB data. + * + * @param rgb the rgb int that defines the pixel + * @param pixel the array that the result is written to: an array of values + * whose length must be the number of components used by the color model and + * whose type depends on the transfer type (based on the pixel bit depth), + * or null to have the appropriate array created + * + * @return the array of data elements + */ + public Object getDataElements(int rgb, Object pixel) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the child raster corresponding to the alpha channel of the + * specified writable raster, or null if alpha is not supported. + * + * @param raster the raster + * + * @return the alpha raster + */ + public WritableRaster getAlphaRaster(WritableRaster raster) { + return null; + } + + /** + * Creates a new color model by coercing the data in the writable raster + * in accordance with the alpha strategy of this color model. + * + * @param raster the raster + * @param isAlphaPremultiplied whether the alpha is premultiplied in this + * color model + * + * @return the new color model + */ + public ColorModel coerceData(WritableRaster raster, + boolean isAlphaPremultiplied) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + @Override + public String toString() { + // The output format based on 1.5 release behaviour. + // It could be reveled such way: + // ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB, + // false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + // System.out.println(cm.toString()); + return "ColorModel: Color Space = " + cs.toString() + "; has alpha = " //$NON-NLS-1$ //$NON-NLS-2$ + + hasAlpha + "; is alpha premultipied = " //$NON-NLS-1$ + + isAlphaPremultiplied + "; transparency = " + transparency //$NON-NLS-1$ + + "; number color components = " + numColorComponents //$NON-NLS-1$ + + "; pixel bits = " + pixel_bits + "; transfer type = " //$NON-NLS-1$ //$NON-NLS-2$ + + transferType; + } + + /** + * Gets the components of the pixel determined by the data array. + * + * @param pixel the data array that defines the pixel (whose + * primitive type corresponds to the pixel length in bits, + * @see ColorModel#getTransferType() + * @param components the the array where the resulting components + * are written (or null to prompt the method to create the return array) + * @param offset the offset that tells where the results should be written + * in the return array + * + * @return the array of components + */ + public int[] getComponents(Object pixel, int[] components, int offset) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the normalized components of the pixel determined by the data array. + * + * @param pixel the data array that defines the pixel (whose + * primitive type corresponds to the pixel length in bits, + * @see ColorModel#getTransferType() + * @param normComponents the array where the resulting normalised components + * are written (or null to prompt the method to create the return array) + * @param normOffset the offset that tells where the results should be written + * in the return array + * + * @return the array of normalized components + */ + public float[] getNormalizedComponents(Object pixel, + float[] normComponents, int normOffset) { + + if (pixel == null) { + // awt.294=pixel is null + throw new NullPointerException(Messages.getString("awt.294")); //$NON-NLS-1$ + } + + int unnormComponents[] = getComponents(pixel, null, 0); + return getNormalizedComponents(unnormComponents, 0, normComponents, + normOffset); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ColorModel)) { + return false; + } + ColorModel cm = (ColorModel) obj; + + return (pixel_bits == cm.getPixelSize() && + transferType == cm.getTransferType() && + cs.getType() == cm.getColorSpace().getType() && + hasAlpha == cm.hasAlpha() && + isAlphaPremultiplied == cm.isAlphaPremultiplied() && + transparency == cm.getTransparency() && + numColorComponents == cm.getNumColorComponents() && + numComponents == cm.getNumComponents() && + Arrays.equals(bits, cm.getComponentSize())); + } + + /** + * Gets the red component of the pixel determined by the data array. + * + * @param inData the data array that defines the pixel (whose + * primitive type corresponds to the pixel length in bits, + * @see ColorModel#getTransferType() + * + * @return the red + */ + public int getRed(Object inData) { + return getRed(constructPixel(inData)); + } + + /** + * Gets the RGB int corresponding to the pixel defined by the data array. + * + * @param inData the data array that defines the pixel (whose + * primitive type corresponds to the pixel length in bits, + * @see ColorModel#getTransferType() + * + * @return the int that gives the pixel's colors in RGB format + */ + public int getRGB(Object inData) { + return (getAlpha(inData) << 24 | getRed(inData) << 16 | + getGreen(inData) << 8 | getBlue(inData)); + } + + /** + * Gets the green component of the pixel defined by the data array. + * + * @param inData the data array that defines the pixel (whose + * primitive type corresponds to the pixel length in bits, + * @see ColorModel#getTransferType() + * + * @return the green + */ + public int getGreen(Object inData) { + return getGreen(constructPixel(inData)); + } + + /** + * Gets the blue component of the pixel defined by the data array. + * + * @param inData the data array that defines the pixel (whose + * primitive type corresponds to the pixel length in bits, + * @see ColorModel#getTransferType() + * + * @return the blue + */ + public int getBlue(Object inData) { + return getBlue(constructPixel(inData)); + } + + /** + * Gets the alpha component of the pixel defined by the data array. + * + * @param inData the data array that defines the pixel (whose + * primitive type corresponds to the pixel length in bits, + * @see ColorModel#getTransferType() + * + * @return the alpha + */ + public int getAlpha(Object inData) { + return getAlpha(constructPixel(inData)); + } + + /** + * Creates a compatible writable raster. + * + * @param w the width of the desired writable raster + * @param h the height of the desired writable raster + * + * @return the writable raster + */ + public WritableRaster createCompatibleWritableRaster(int w, int h) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Checks if the sample model is compatible with this color model. + * + * @param sm the sample model + * + * @return true, if the sample model is compatible with this color model + */ + public boolean isCompatibleSampleModel(SampleModel sm) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Creates the compatible sample model. + * + * @param w the width of the desired sample model + * @param h the height of the desired sample model + * + * @return the sample model + */ + public SampleModel createCompatibleSampleModel(int w, int h) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Checks if the specified raster is compatible with this color model. + * + * @param raster the raster to inspect + * + * @return true, if the raster is compatible with this color model + */ + public boolean isCompatibleRaster(Raster raster) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the color space of this color model. + * + * @return the color space + */ + public final ColorSpace getColorSpace() { + return cs; + } + + /** + * Gets the normalized components corresponding to the specified + * unnormalized components. + * + * @param components the array of unnormalized components + * @param offset the offset where the components should be read + * from the array of unnormalized components + * @param normComponents the array where the resulting normalised components + * are written (or null to prompt the method to create the return array) + * @param normOffset the offset that tells where the results should be written + * in the return array + * + * @return the normalized components + */ + public float[] getNormalizedComponents(int[] components, int offset, + float normComponents[], int normOffset) { + if (bits == null) { + // awt.26C=bits is null + throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + if (normComponents == null) { + normComponents = new float[numComponents + normOffset]; + } + + if (hasAlpha && isAlphaPremultiplied) { + float normAlpha = + (float) components[offset + numColorComponents] / + maxValues[numColorComponents]; + if (normAlpha != 0.0f) { + for (int i = 0; i < numColorComponents; i++) { + normComponents[normOffset + i] = + components[offset + i] / + (normAlpha * maxValues[i]); + } + normComponents[normOffset + numColorComponents] = normAlpha; + } else { + for (int i = 0; i < numComponents; i++) { + normComponents[normOffset + i] = 0.0f; + } + } + } else { + for (int i = 0; i < numComponents; i++) { + normComponents[normOffset + i] = + (float) components[offset + i] / + maxValues[i]; + } + } + + return normComponents; + } + + /** + * Gets the data element corresponding to the unnormalized components. + * + * @param components the components + * @param offset the offset to start reading the components from the + * array of components + * + * @return the data element + */ + public int getDataElement(int[] components, int offset) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the unnormalized components corresponding to the specified + * normalized components. + * + * @param normComponents the array of normalized components + * @param normOffset the offset where the components should be read + * from the array of normalized components + * @param components the array where the resulting unnormalised components + * are written (or null to prompt the method to create the return array) + * @param offset the offset that tells where the results should be written + * in the return array + * + * @return the unnormalized components + */ + public int[] getUnnormalizedComponents(float normComponents[], + int normOffset, int components[], int offset) { + + if (bits == null) { + // awt.26C=bits is null + throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + if (normComponents.length - normOffset < numComponents) { + // awt.273=The length of normComponents minus normOffset is less than numComponents + throw new IllegalArgumentException(Messages.getString("awt.273")); //$NON-NLS-1$ + } + + if (components == null) { + components = new int[numComponents + offset]; + } else { + if (components.length - offset < numComponents) { + // awt.272=The length of components minus offset is less than numComponents + throw new IllegalArgumentException(Messages.getString("awt.272")); //$NON-NLS-1$ + } + } + + if (hasAlpha && isAlphaPremultiplied) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0; i < numColorComponents; i++) { + components[offset + i] = (int) (normComponents[normOffset + i] + * maxValues[i] * alpha + 0.5f); + } + components[offset + numColorComponents] = + (int) (normComponents[normOffset + numColorComponents] * + maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0; i < numComponents; i++) { + components[offset + i] = + (int) (normComponents[normOffset + i] * + maxValues[i] + 0.5f); + } + } + + return components; + } + + /** + * Gets the data element corresponding to the normalized components. + * + * @param normComponents the normalized components + * @param normOffset the offset where the normalized components should + * be read from the normalized component array + * + * @return the data element + */ + public int getDataElement(float normComponents[], int normOffset) { + int unnormComponents[] = getUnnormalizedComponents(normComponents, + normOffset, null, 0); + return getDataElement(unnormComponents, 0); + } + + /** + * Takes a pixel whose data is defined by an int, and writes the + * corresponding components into the components array, starting + * from the index offset. + * + * @param pixel the pixel data + * @param components the data array to write the components to (or + * null to have the method create the return array) + * @param offset the offset that determines where the results are + * written in the components array + * + * @return the array of components corresponding to the pixel + */ + public int[] getComponents(int pixel, int components[], int offset) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the red component of the pixel determined by the pixel data. + * + * @param pixel the pixel data + * + * @return the red component of the pixel + */ + public abstract int getRed(int pixel); + + /** + * Takes the pixel data and returns the int corresponding + * to the pixel's color in RGB format. + * + * @param pixel the pixel data + * + * @return the corresponding RGB int + */ + public int getRGB(int pixel) { + return (getAlpha(pixel) << 24 | getRed(pixel) << 16 + | getGreen(pixel) << 8 | getBlue(pixel)); + } + + /** + * Gets the green component of the pixel determined by the pixel data. + * + * @param pixel the pixel data + * + * @return the green component of the pixel + */ + public abstract int getGreen(int pixel); + + /** + * Gets the size of the desired component of this color model. + * + * @param componentIdx the index that determines which component size to get + * + * @return the component size corresponding to the index + * + * @throws NullPointerException if this color model doesn't support + * an array of separate components. + * @throws ArrayIndexOutOfBoundsException if the index is negative or + * greater than or equal to the number of components + */ + public int getComponentSize(int componentIdx) { + if (bits == null) { + // awt.26C=bits is null + throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + if (componentIdx < 0 || componentIdx >= bits.length) { + // awt.274=componentIdx is greater than the number of components or less than zero + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.274")); //$NON-NLS-1$ + } + + return bits[componentIdx]; + } + + /** + * Gets the blue component of the pixel determined by the pixel data. + * + * @param pixel the pixel + * + * @return the blue component of the pixel + */ + public abstract int getBlue(int pixel); + + /** + * Gets the alpha component of the pixel determined by the pixel data. + * + * @param pixel the pixel + * + * @return the alpha component of the pixel + */ + public abstract int getAlpha(int pixel); + + /** + * Gets the array of sizes of the different components. + * + * @return the array of sizes of the different components + */ + public int[] getComponentSize() { + if (bits != null) { + return bits.clone(); + } + return null; + } + + /** + * Checks if the alpha component is premultiplied. + * + * @return true, if the alpha component is premultiplied + */ + public final boolean isAlphaPremultiplied() { + return isAlphaPremultiplied; + } + + /** + * Checks whether this color model supports alpha. + * + * @return true, if this color model has alpha + */ + public final boolean hasAlpha() { + return hasAlpha; + } + + @Override + public int hashCode() { + int hash = 0; + int tmp; + + if (hasAlpha) { + hash ^= 1; + hash <<= 8; + } + if (isAlphaPremultiplied) { + hash ^= 1; + hash <<= 8; + } + + tmp = hash >>> 24; + hash ^= numColorComponents; + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= transparency; + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= cs.getType(); + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= pixel_bits; + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= transferType; + hash <<= 8; + hash |= tmp; + + if (bits != null) { + + for (int element : bits) { + tmp = hash >>> 24; + hash ^= element; + hash <<= 8; + hash |= tmp; + } + + } + + return hash; + } + + public int getTransparency() { + return transparency; + } + + /** + * Gets the transfer type, which is the type of Java primitive + * value that corresponds to the bit length per pixel: either + * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, + * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}. + * + * @return the transfer type + */ + public final int getTransferType() { + return transferType; + } + + /** + * Gets the pixel size in bits. + * + * @return the pixel size + */ + public int getPixelSize() { + return pixel_bits; + } + + /** + * Gets the number of components of this color model. + * + * @return the number of components + */ + public int getNumComponents() { + return numComponents; + } + + /** + * Gets the number of color components of this color model. + * + * @return the number color components + */ + public int getNumColorComponents() { + return numColorComponents; + } + + /** + * Gets the default RGB color model. + * + * @return the default RGB color model + */ + public static ColorModel getRGBdefault() { + if (RGBdefault == null) { + RGBdefault = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, + 0x000000ff, 0xff000000); + } + return RGBdefault; + } + + /* + * Construct INT pixel representation from Object + * @param obj + * + * @return + */ + /** + * Construct pixel. + * + * @param obj the obj + * + * @return the int + */ + private int constructPixel(Object obj) { + int pixel = 0; + + switch (getTransferType()) { + + case DataBuffer.TYPE_BYTE: + byte[] bPixel = (byte[]) obj; + if(bPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = bPixel[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short[] sPixel = (short[]) obj; + if(sPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = sPixel[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int[] iPixel = (int[]) obj; + if(iPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = iPixel[0]; + break; + + default: + // awt.22D=This transferType ( {0} ) is not supported by this color model + throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ + transferType)); + + } + return pixel; + } + + /** + * Gets the transfer type, which is the type of Java primitive + * value that corresponds to the bit length per pixel: either + * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, + * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}. + * + * @param bits the array of component masks + * + * @return the transfer type + */ + static int getTransferType(int bits) { + if (bits <= 8) { + return DataBuffer.TYPE_BYTE; + } else if (bits <= 16) { + return DataBuffer.TYPE_USHORT; + } else if (bits <= 32) { + return DataBuffer.TYPE_INT; + } else { + return DataBuffer.TYPE_UNDEFINED; + } + } + + @Override + public void finalize() { + // This method is added for the API compatibility + // Don't need to call super since Object's finalize is always empty + } +} diff --git a/awt/java/awt/image/ComponentColorModel.java b/awt/java/awt/image/ComponentColorModel.java new file mode 100644 index 0000000..a152f55 --- /dev/null +++ b/awt/java/awt/image/ComponentColorModel.java @@ -0,0 +1,1471 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.color.ColorSpace; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class ComponentColorModel represents a color model that is defined + * in terms of its components. + */ +public class ComponentColorModel extends ColorModel { + + /** The signed. */ + private boolean signed; // Pixel samples are signed. + // Samples with TransferType DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT - + // unsigned. Samples with others TransferType - + // signed. + + /** The integral. */ + private boolean integral; // Pixel samples are integral. + // Samples with TransferType DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.Short and + // DataBuffer.TYPE_INT - integral. + + /** The scale factors. */ + private float scaleFactors[]; // Array of factors for reduction components + // values into the form scaled from 0 to 255 + + /** The donot support unnormalized. */ + private boolean donotSupportUnnormalized; // This Color Model don't support + // unnormolized form + + /** The need alpha divide. */ + private boolean needAlphaDivide; // hasAlpha && isAlphaPremultiplied + + /** The calc value. */ + private boolean calcValue; // Value was culculated + + /** The need scale. */ + private boolean needScale; // Normalized value need to scale + + /** The min vals. */ + private float minVals[]; // Array of Min normalized values + + /** The ranges. */ + private float ranges[]; // Array of range normalized values + + /** The alpha lut. */ + private byte alphaLUT[]; // Lookup table for scale alpha value + + /** The color lu ts. */ + private byte colorLUTs[][]; // Lookup tables for scale color values + + /** The from_ linea r_ rg b_ lut. */ + private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from + // Linear RGB Color Space into sRGB + + /** The to_ linea r_8 rg b_ lut. */ + private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from + // sRGB Color Space into Linear RGB + // 8 bit + + /** The to_ linea r_16 rg b_ lut. */ + private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from + // sRGB Color Space into Linear RGB + // 16 bit + + /** The LINEA r_ rg b_ length. */ + private int LINEAR_RGB_Length; // Linear RGB bit length + + /** The factor. */ + private float fFactor; // Scale factor + + /** The is_s rgb. */ + private boolean is_sRGB; // ColorModel has sRGB ColorSpace + + /** The is_ linea r_ rgb. */ + private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color + // Space + + /** + * Instantiates a new component color model. + * + * @param colorSpace the color space + * @param bits the array of component masks + * @param hasAlpha whether the color model has alpha + * @param isAlphaPremultiplied whether the alpha is premultiplied + * @param transparency the transparency strategy, @see java.awt.Transparency + * @param transferType the transfer type (primitive java type + * to use for the components) + */ + public ComponentColorModel(ColorSpace colorSpace, int bits[], + boolean hasAlpha, boolean isAlphaPremultiplied, int transparency, + int transferType) { + super(createPixelBits(colorSpace, hasAlpha, transferType), + validateBits(bits, colorSpace, hasAlpha, transferType), + colorSpace, hasAlpha, isAlphaPremultiplied, transparency, + transferType); + + needScale = false; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + signed = false; + integral = true; + donotSupportUnnormalized = false; + scaleFactors = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + scaleFactors[i] = 1.0f / maxValues[i]; + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + donotSupportUnnormalized = true; + } + } + if (hasAlpha) { + maxValues[numColorComponents] = + (1 << bits[numColorComponents]) - 1; + scaleFactors[numColorComponents] = + 1.0f / maxValues[numColorComponents]; + } + break; + case DataBuffer.TYPE_SHORT: + signed = true; + integral = true; + donotSupportUnnormalized = true; + scaleFactors = new float[numComponents]; + for (int i = 0; i < numComponents; i++) { + maxValues[i] = Short.MAX_VALUE; + scaleFactors[i] = 1.0f / maxValues[i]; + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + needScale = true; + } + } + if (needScale) { + minVals = new float[numColorComponents]; + ranges = new float[numColorComponents]; + for (int i = 0; i < numColorComponents; i++) { + minVals[i] = cs.getMinValue(i); + ranges[i] = cs.getMaxValue(i) - minVals[i]; + } + } + break; + case DataBuffer.TYPE_FLOAT: + case DataBuffer.TYPE_DOUBLE: + signed = true; + integral = false; + donotSupportUnnormalized = true; + break; + default: + // awt.215=transferType is not one of DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + // DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + // DataBuffer.TYPE_DOUBLE + throw new IllegalArgumentException(Messages.getString("awt.215")); //$NON-NLS-1$ + } + + needAlphaDivide = hasAlpha && isAlphaPremultiplied; + initLUTs(); + } + + /** + * Instantiates a new component color model. + * + * @param colorSpace the color space + * @param hasAlpha whether the color model has alpha + * @param isAlphaPremultiplied whether the alpha is premultiplied + * @param transparency the transparency strategy, @see java.awt.Transparency + * @param transferType the transfer type (primitive java type + * to use for the components) + */ + public ComponentColorModel(ColorSpace colorSpace, boolean hasAlpha, + boolean isAlphaPremultiplied, int transparency, int transferType) { + + this(colorSpace, + createPixelBitsArray(colorSpace, hasAlpha, transferType), + hasAlpha, + isAlphaPremultiplied, + transparency, + transferType); + } + + /** + * Validate bits. + * + * @param bits the bits + * @param colorSpace the color space + * @param hasAlpha the has alpha + * @param transferType the transfer type + * + * @return the int[] + */ + private static int[] validateBits(int bits[], ColorSpace colorSpace, + boolean hasAlpha, int transferType) { + if (bits != null) { + return bits; + } + + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + numComponents++; + } + bits = new int[numComponents]; + + int componentLength = DataBuffer.getDataTypeSize(transferType); + + for (int i = 0; i < numComponents; i++) { + bits[i] = componentLength; + } + + return bits; + } + + /** + * Creates the pixel bits. + * + * @param colorSpace the color space + * @param hasAlpha the has alpha + * @param transferType the transfer type + * + * @return the int + */ + private static int createPixelBits(ColorSpace colorSpace, boolean hasAlpha, + int transferType) { + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + numComponents++; + } + int componentLength = DataBuffer.getDataTypeSize(transferType); + return numComponents * componentLength; + } + + /** + * Creates the pixel bits array. + * + * @param colorSpace the color space + * @param hasAlpha the has alpha + * @param transferType the transfer type + * + * @return the int[] + */ + private static int[] createPixelBitsArray(ColorSpace colorSpace, + boolean hasAlpha, int transferType) { + + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + numComponents++; + } + + int bits[] = new int[numComponents]; + for(int i = 0; i < numComponents; i++){ + bits[i] = DataBuffer.getDataTypeSize(transferType); + } + return bits; + } + + @Override + public Object getDataElements(int components[], int offset, Object obj) { + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (offset + numComponents > components.length) { + // awt.216=The components array is not large enough to hold all the color and alpha components + throw new IllegalArgumentException(Messages.getString("awt.216")); //$NON-NLS-1$ + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[numComponents]; + } else { + ba = (byte[]) obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + ba[i] = (byte) components[idx]; + } + return ba; + case DataBuffer.TYPE_USHORT: + short sa[]; + if (obj == null) { + sa = new short[numComponents]; + } else { + sa = (short[]) obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + sa[i] = (short) components[idx]; + } + return sa; + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[numComponents]; + } else { + ia = (int[]) obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + ia[i] = components[idx]; + } + return ia; + default: + // awt.217=The transfer type of this ComponentColorModel is not one + // of the following transfer types: DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + throw new UnsupportedOperationException(Messages + .getString("awt.217")); //$NON-NLS-1$ + } + } + + @Override + public Object getDataElements(float normComponents[], int normOffset, + Object obj) { + if (needScale) { + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + normComponents[idx] = + (normComponents[idx] - minVals[i]) / ranges[i]; + } + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[numComponents]; + } else { + ba = (byte[]) obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = normOffset; i < numColorComponents; + i++, idx++) { + ba[i] = (byte) (normComponents[idx] * alpha * + maxValues[i] + 0.5f); + } + ba[numColorComponents] = + (byte) (normComponents[normOffset + numColorComponents] * + maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; + i++, idx++) { + ba[idx] = + (byte) (normComponents[idx] * maxValues[i] + 0.5f); + } + } + return ba; + + case DataBuffer.TYPE_USHORT: + short usa[]; + if (obj == null) { + usa = new short[numComponents]; + } else { + usa = (short[]) obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + usa[i] = (short) (normComponents[idx] * alpha * + maxValues[i] + 0.5f); + } + usa[numColorComponents] = (short) (alpha * + maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; + i++, idx++) { + usa[i] = (short) (normComponents[idx] * + maxValues[i] + 0.5f); + } + } + return usa; + + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[numComponents]; + } else { + ia = (int[]) obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + ia[i] = (int) (normComponents[idx] * alpha * + maxValues[i] + 0.5f); + } + ia[numColorComponents] = (int) (alpha * + maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; + i++, idx++) { + ia[i] = (int) (normComponents[idx] * maxValues[i] + 0.5f); + } + } + return ia; + + case DataBuffer.TYPE_SHORT: + short sa[]; + if (obj == null) { + sa = new short[numComponents]; + } else { + sa = (short[]) obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + sa[i] = (short) (normComponents[idx] * alpha * + maxValues[i] + 0.5f); + } + sa[numColorComponents] = (short) (alpha * + maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; + i++, idx++) { + sa[i] = (short) (normComponents[idx] * + maxValues[i] + 0.5f); + } + } + return sa; + + case DataBuffer.TYPE_FLOAT: + float fa[]; + if (obj == null) { + fa = new float[numComponents]; + } else { + fa = (float[]) obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + fa[i] = normComponents[idx] * alpha; + } + fa[numColorComponents] = alpha; + } else { + for (int i = 0, idx = normOffset; i < numComponents; + i++, idx++) { + fa[i] = normComponents[idx]; + } + } + return fa; + + case DataBuffer.TYPE_DOUBLE: + double da[]; + if (obj == null) { + da = new double[numComponents]; + } else { + da = (double[]) obj; + } + + if (needAlphaDivide) { + double alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + da[i] = normComponents[idx] * alpha; + } + da[numColorComponents] = alpha; + } else { + for (int i = 0, idx = normOffset; i < numComponents; + i++, idx++) { + da[i] = normComponents[idx]; + } + } + return da; + + default: + // awt.213=This ComponentColorModel does not support the unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + } + + @Override + public Object getDataElements(int rgb, Object pixel) { + float normComp[]; + float comp[]; + + int red = (rgb >> 16) & 0xff; + int green = (rgb >> 8) & 0xff; + int blue = rgb & 0xff; + int alpha = (rgb >> 24) & 0xff; + + comp = new float[3]; + if (is_sRGB || is_LINEAR_RGB) { + if (is_LINEAR_RGB) { + if (LINEAR_RGB_Length == 8) { + red = to_LINEAR_8RGB_LUT[red] & 0xff; + green = to_LINEAR_8RGB_LUT[green] & 0xff; + blue = to_LINEAR_8RGB_LUT[blue] & 0xff; + } else { + red = to_LINEAR_16RGB_LUT[red] & 0xffff; + green = to_LINEAR_16RGB_LUT[green] & 0xffff; + blue = to_LINEAR_16RGB_LUT[blue] & 0xffff; + } + } + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + if (!hasAlpha) { + normComp = comp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = comp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } else { + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + float[] defComp = cs.fromRGB(comp); + if (!hasAlpha) { + normComp = defComp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = defComp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } + if(hasAlpha && isAlphaPremultiplied){ + normComp[0] *= normComp[numColorComponents]; + normComp[1] *= normComp[numColorComponents]; + normComp[2] *= normComp[numColorComponents]; + } + + return getDataElements(normComp, 0, pixel); + } + + @Override + public WritableRaster getAlphaRaster(WritableRaster raster) { + if(!hasAlpha) { + return null; + } + + int x = raster.getMinX(); + int y = raster.getMinY(); + int bandList[] = new int[1]; + bandList[0] = raster.getNumBands() - 1; + + return raster.createWritableChild(x, y, raster.getWidth(), + raster.getHeight(), x, y, bandList); + } + + @Override + public ColorModel coerceData(WritableRaster raster, + boolean isAlphaPremultiplied) { + if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) { + return this; + } + + int minX = raster.getMinX(); + int minY = raster.getMinY(); + int w = raster.getWidth(); + int h = raster.getHeight(); + + if (isAlphaPremultiplied) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + float alphaFactor = maxValues[numColorComponents]; + int iComponents[] = null; + int iTransparentComponents[] = new int[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + iComponents = raster.getPixel(x, minY, + iComponents); + if (iComponents[numColorComponents] == 0) { + raster.setPixel(x, minY, iTransparentComponents); + } else { + float alpha = + iComponents[numColorComponents] / + alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + iComponents[n] = + (int) (alpha * iComponents[n] + 0.5f); + } + raster.setPixel(x, minY, iComponents); + } + } + + } + break; + + case DataBuffer.TYPE_SHORT: + float sAlphaFactor = maxValues[numColorComponents]; + short sComponents[] = null; + short sTransparentComponents[] = new short[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + sComponents = (short[]) raster.getDataElements(x, minY, + sComponents); + if (sComponents[numColorComponents] == 0) { + raster.setDataElements(x, minY, + sTransparentComponents); + } else { + float alpha = + sComponents[numColorComponents] / + sAlphaFactor; + for (int n = 0; n < numColorComponents; n++) { + sComponents[n] = + (byte) (alpha * sComponents[n] + 0.5f); + } + raster.setDataElements(x, minY, sComponents); + } + } + + } + break; + + case DataBuffer.TYPE_FLOAT: + float fComponents[] = null; + float fTransparentComponents[] = new float[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + fComponents = raster.getPixel(x, minY, fComponents); + if (fComponents[numColorComponents] == 0.0f) { + raster.setDataElements(x, minY, + fTransparentComponents); + } else { + float alpha = fComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + fComponents[n] = fComponents[n] * alpha; + } + raster.setPixel(x, minY, fComponents); + } + } + + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dComponents[] = null; + double dTransparentComponents[] = new double[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + dComponents = raster.getPixel(x, minY, dComponents); + if (dComponents[numColorComponents] == 0.0) { + raster.setPixel(x, minY, dTransparentComponents); + } else { + double alpha = dComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + dComponents[n] = dComponents[n] * alpha; + } + raster.setPixel(x, minY, dComponents); + } + } + + } + break; + + default: + // awt.219=This transferType is not supported by this color model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + } else { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + float alphaFactor = maxValues[numColorComponents]; + int iComponents[] = null; + int iTransparentComponents[] = new int[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + iComponents = raster.getPixel(x, minY, + iComponents); + if (iComponents[numColorComponents] == 0) { + raster.setPixel(x, minY, iTransparentComponents); + } else { + float alpha = + iComponents[numColorComponents] / + alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + iComponents[n] = + (int) (iComponents[n] / + alpha + 0.5f); + } + raster.setPixel(x, minY, iComponents); + } + } + + } + break; + + case DataBuffer.TYPE_SHORT: + float sAlphaFactor = maxValues[numColorComponents]; + short sComponents[] = null; + short sTransparentComponents[] = new short[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + sComponents = (short[]) raster.getDataElements(x, minY, + sComponents); + if (sComponents[numColorComponents] == 0) { + raster.setDataElements(x, minY, + sTransparentComponents); + } else { + float alpha = + sComponents[numColorComponents] / + sAlphaFactor; + for (int n = 0; n < numColorComponents; n++) { + sComponents[n] = + (byte) (sComponents[n] / + alpha + 0.5f); + } + raster.setDataElements(x, minY, sComponents); + } + } + + } + break; + + case DataBuffer.TYPE_FLOAT: + float fComponents[] = null; + float fTransparentComponents[] = new float[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + fComponents = raster.getPixel(x, minY, fComponents); + if (fComponents[numColorComponents] == 0.0f) { + raster.setDataElements(x, minY, + fTransparentComponents); + } else { + float alpha = fComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + fComponents[n] = fComponents[n] / alpha; + } + raster.setPixel(x, minY, fComponents); + } + } + + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dComponents[] = null; + double dTransparentComponents[] = new double[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + dComponents = raster.getPixel(x, minY, dComponents); + if (dComponents[numColorComponents] == 0.0) { + raster.setPixel(x, minY, dTransparentComponents); + } else { + double alpha = dComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + dComponents[n] = dComponents[n] / alpha; + } + raster.setPixel(x, minY, dComponents); + } + } + + } + break; + default: + // awt.219=This transferType is not supported by this color model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + } + + if (!signed) { + return new ComponentColorModel(cs, bits, hasAlpha, + isAlphaPremultiplied, transparency, transferType); + } + + return new ComponentColorModel(cs, null, hasAlpha, + isAlphaPremultiplied, transparency, transferType); + } + + @Override + public int[] getComponents(Object pixel, int[] components, int offset) { + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (components == null) { + components = new int[offset + numComponents]; + } else if (offset + numComponents > components.length) { + // awt.218=The components array is not large enough to hold all the color and alpha components + throw new IllegalArgumentException(Messages.getString("awt.218")); //$NON-NLS-1$ + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) pixel; + + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = ba[i] & 0xff; + } + return components; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[]) pixel; + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = sa[i] & 0xffff; + } + return components; + + case DataBuffer.TYPE_INT: + int ia[] = (int[]) pixel; + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = ia[i]; + } + return components; + + default: + // awt.217=The transfer type of this ComponentColorModel is not one + // of the following transfer types: DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + throw new UnsupportedOperationException(Messages + .getString("awt.217")); //$NON-NLS-1$ + } + + } + + @Override + public float[] getNormalizedComponents(Object pixel, + float normComponents[], int normOffset) { + + if (normComponents == null) { + normComponents = new float[numComponents + normOffset]; + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (ba[i] & 0xff) * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_USHORT: + short usa[] = (short[]) pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (usa[i] & 0xffff) + * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[]) pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = ia[i] * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_SHORT: + short sa[] = (short[]) pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = sa[i] * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_FLOAT: + float fa[] = (float[]) pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = fa[i]; + } + break; + + case DataBuffer.TYPE_DOUBLE: + double da[] = (double[]) pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (float) da[i]; + } + break; + + default: + // awt.21A=This ComponentColorModel does not support this transferType + throw new IllegalArgumentException(Messages.getString("awt.21A")); //$NON-NLS-1$ + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = normOffset; i < numColorComponents; + i++, idx++) { + normComponents[idx] /= alpha; + } + } + + if (needScale) { + for (int i = 0, idx = normOffset; i < numColorComponents; + i++, idx++) { + normComponents[idx] = minVals[i] + + ranges[i] * normComponents[idx]; + } + } + return normComponents; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ComponentColorModel)) { + return false; + } + return super.equals(obj); + } + + @Override + public int getRed(Object inData) { + return getRGBComponent(inData, 0); + } + + @Override + public int getRGB(Object inData) { + int alpha = getAlpha(inData); + if (cs.getType() == ColorSpace.TYPE_GRAY) { + int gray = getRed(inData); + return (alpha << 24 | gray << 16 | gray << 8 | gray); + } + return (alpha << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | + getBlue(inData)); + } + + @Override + public int getGreen(Object inData) { + return getRGBComponent(inData, 1); + } + + @Override + public int getBlue(Object inData) { + return getRGBComponent(inData, 2); + } + + @Override + public int getAlpha(Object inData) { + if (!hasAlpha) { + return 255; + } + int alpha = 0; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: { + byte ba[] = (byte[]) inData; + alpha = ba[numColorComponents] & 0xff; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_USHORT: { + short usa[] = (short[]) inData; + alpha = usa[numColorComponents] & 0xffff; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_INT: { + int ia[] = (int[]) inData; + alpha = ia[numColorComponents]; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_SHORT: { + short sa[] = (short[]) inData; + alpha = sa[numColorComponents]; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_FLOAT: { + float fa[] = (float[]) inData; + return (int) (fa[numColorComponents] * 255.0f + 0.5f); + } + case DataBuffer.TYPE_DOUBLE: { + double da[] = (double[]) inData; + return (int) (da[numColorComponents] * 255.0 + 0.5); + } + default: { + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } + } + + @Override + public WritableRaster createCompatibleWritableRaster(int w, int h) { + SampleModel sm = createCompatibleSampleModel(w, h); + DataBuffer db = sm.createDataBuffer(); + return Raster.createWritableRaster(sm, db, null); + } + + @Override + public boolean isCompatibleSampleModel(SampleModel sm) { + if (!(sm instanceof ComponentSampleModel)) { + return false; + } + if (numComponents != sm.getNumBands()) { + return false; + } + if (transferType != sm.getTransferType()) { + return false; + } + return true; + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + int bandOffsets[] = new int[numComponents]; + for (int i = 0; i < numComponents; i++) { + bandOffsets[i] = i; + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + return new PixelInterleavedSampleModel(transferType, w, h, + numComponents, w * numComponents, bandOffsets); + + default: + return new ComponentSampleModel(transferType, w, h, numComponents, + w * numComponents, bandOffsets); + } + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + SampleModel sm = raster.getSampleModel(); + if (!(sm instanceof ComponentSampleModel)) { + return false; + } + + if (sm.getNumBands() != numComponents) { + return false; + } + if (raster.getTransferType() != transferType) { + return false; + } + + int sampleSizes[] = sm.getSampleSize(); + for (int i = 0; i < numComponents; i++) { + if (bits[i] != sampleSizes[i]) { + return false; + } + } + return true; + } + + @Override + public float[] getNormalizedComponents(int components[], int offset, + float normComponents[], int normOffset) { + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + return super.getNormalizedComponents(components, offset, + normComponents, normOffset); + } + + @Override + public int getDataElement(int[] components, int offset) { + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + return components[offset]; + } + + @Override + public int[] getUnnormalizedComponents(float[] normComponents, + int normOffset, int[] components, int offset) { + + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (normComponents.length - normOffset < numComponents) { + // awt.21B=The length of normComponents minus normOffset is less than numComponents + throw new IllegalArgumentException(Messages.getString("awt.21B")); //$NON-NLS-1$ + } + + return super.getUnnormalizedComponents(normComponents, normOffset, + components, offset); + } + + @Override + public int getDataElement(float normComponents[], int normOffset) { + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + if (signed) { + // awt.210=The component value for this ColorModel is signed + throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$ + } + + Object pixel = getDataElements(normComponents, normOffset, null); + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) pixel; + return ba[0] & 0xff; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[]) pixel; + return sa[0] & 0xffff; + case DataBuffer.TYPE_INT: + int ia[] = (int[]) pixel; + return ia[0]; + default: + // awt.211=Pixel values for this ColorModel are not conveniently + // representable as a single int + throw new IllegalArgumentException(Messages.getString("awt.211")); //$NON-NLS-1$ + } + } + + @Override + public int[] getComponents(int pixel, int components[], int offset) { + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (components == null) { + components = new int[offset + 1]; + } + + components[offset] = pixel & maxValues[0]; + return components; + } + + @Override + public int getRed(int pixel) { + float rgb[] = toRGB(pixel); + return (int) (rgb[0] * 255.0f + 0.5f); + } + + @Override + public int getRGB(int pixel) { + return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | + (getGreen(pixel) << 8) | getBlue(pixel); + } + + @Override + public int getGreen(int pixel) { + float rgb[] = toRGB(pixel); + return (int) (rgb[1] * 255.0f + 0.5f); + } + + @Override + public int getBlue(int pixel) { + float rgb[] = toRGB(pixel); + return (int) (rgb[2] * 255.0f + 0.5f); + } + + @Override + public int getAlpha(int pixel) { + + // This method throw IllegalArgumentException according to + // Java API Spacification + if (signed) { + // awt.210=The component value for this ColorModel is signed + throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$ + } + + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + + return 255; + } + + /** + * Initialization of Lookup tables. + */ + private void initLUTs() { + is_sRGB = cs.isCS_sRGB(); + is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS); + + if (hasAlpha && bits[numColorComponents] != 8 && integral) { + alphaLUT = new byte[maxValues[numColorComponents] + 1]; + for (int i = 0; i <= maxValues[numColorComponents]; i++) { + alphaLUT[i] = (byte) (scaleFactors[numColorComponents] * i + + 0.5f); + } + } + + if (is_LINEAR_RGB) { + if (maxBitLength > 8) { + LINEAR_RGB_Length = 16; + from_LINEAR_RGB_LUT = + LUTColorConverter.getFrom16lRGBtosRGB_LUT(); + to_LINEAR_16RGB_LUT = + LUTColorConverter.getFromsRGBto16lRGB_LUT(); + } else { + LINEAR_RGB_Length = 8; + from_LINEAR_RGB_LUT = + LUTColorConverter.getFrom8lRGBtosRGB_LUT(); + to_LINEAR_8RGB_LUT = + LUTColorConverter.getFromsRGBto8lRGB_LUT(); + } + fFactor = ((1 << LINEAR_RGB_Length) - 1); + } else { + fFactor = 255.0f; + } + + if (!isAlphaPremultiplied && integral) { + colorLUTs = new byte[3][]; + + if (is_sRGB) { + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != 8) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[0]; j++) { + colorLUTs[i][j] = + (byte) (scaleFactors[i] * j + 0.5f); + } + } + } + } + + if (is_LINEAR_RGB) { + + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != LINEAR_RGB_Length) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[0]; j++) { + int idx; + if (LINEAR_RGB_Length == 8) { + idx = (int) (scaleFactors[i] * j + 0.5f); + } else { + idx = (int) (scaleFactors[i] * j * 257.0f + + 0.5f); + } + colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx]; + } + } + } + } + + } + } + + /** + * To rgb. + * + * @param pixel - int representation of pixel + * + * @return - array of normalized sRGB components + */ + private float[] toRGB(int pixel) { + + // This method throw IllegalArgumentException according to + // Java API Spacification + if (signed) { + // awt.210=The component value for this ColorModel is signed + throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$ + } + + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + + Object obj = null; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = new byte[1]; + ba[0] = (byte) pixel; + obj = ba; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = new short[1]; + sa[0] = (short) pixel; + obj = sa; + break; + + case DataBuffer.TYPE_INT: + int ia[] = new int[1]; + ia[0] = pixel; + obj = ia; + break; + + } + + return cs.toRGB(getNormalizedComponents(obj, null, 0)); + } + + /** + * Gets the rgb component. + * + * @param pixel - pixel + * @param idx - index of component + * + * @return - RGB value from 0 to 255 pixel's component + */ + private int getRGBComponent(Object pixel, int idx) { + if (is_sRGB) { + int comp = getDefComponent(pixel, idx); + if (calcValue || bits[idx] == 8) { + return comp; + } + return colorLUTs[idx][comp] & 0xff; + } else if (is_LINEAR_RGB) { + int comp = getDefComponent(pixel, idx); + if (calcValue || bits[idx] == LINEAR_RGB_Length) { + return from_LINEAR_RGB_LUT[comp] & 0xff; + } + return colorLUTs[idx][comp] & 0xff; + } + + float normComp[] = getNormalizedComponents(pixel, null, 0); + float rgbComp[] = cs.toRGB(normComp); + return (int) (rgbComp[idx] * 255.0f + 0.5f); + } + + /** + * Gets the def component. + * + * @param pixel - pixel + * @param idx - index of component + * + * @return - tentative value of the pixel component + */ + private int getDefComponent(Object pixel, int idx) { + int comp = 0; + calcValue = false; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) pixel; + comp = ba[idx] & 0xff; + if (needAlphaDivide) { + int alpha = ba[numColorComponents] & 0xff; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int) (comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_USHORT: + short usa[] = (short[]) pixel; + comp = usa[idx] & 0xffff; + if (needAlphaDivide) { + int alpha = usa[numColorComponents] & 0xffff; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int) (comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_INT: + int ia[] = (int[]) pixel; + comp = ia[idx]; + if (needAlphaDivide) { + int alpha = ia[numColorComponents]; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int) (comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_SHORT: + short sa[] = (short[]) pixel; + comp = sa[idx]; + if (needAlphaDivide) { + int alpha = sa[numColorComponents]; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int) (comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_FLOAT: + float fa[] = (float[]) pixel; + if (needAlphaDivide) { + float alpha = fa[numColorComponents]; + if (fa[numColorComponents] == 0.0f) { + comp = 0; + } else { + comp = (int) (fa[idx] * fFactor / alpha + 0.5f); + } + } else { + comp = (int) (fa[idx] * fFactor + 0.5f); + } + calcValue = true; + return comp; + + case DataBuffer.TYPE_DOUBLE: + double da[] = (double[]) pixel; + if (needAlphaDivide) { + if (da[numColorComponents] == 0.0) { + comp = 0; + } else { + comp = (int) (da[idx] * fFactor / da[numColorComponents] + + 0.5); + } + } else { + comp = (int) (da[idx] * fFactor + 0.5); + } + calcValue = true; + return comp; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } + +} + diff --git a/awt/java/awt/image/ComponentSampleModel.java b/awt/java/awt/image/ComponentSampleModel.java new file mode 100644 index 0000000..2ff4f1a --- /dev/null +++ b/awt/java/awt/image/ComponentSampleModel.java @@ -0,0 +1,690 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ComponentSampleModel class represents a set of image data whose + * each element - the sample of a pixel - takes one data element of + * the DataBuffer. + *

+ * The Bank indices denote the correspondence between the bank of data + * buffers and a band of image data. The Pixel stride is the number of data + * array elements between two samples for the same band on the same + * scanline. The pixel stride for a BandedSampleModel is one. The Scanline + * stride represents the number of data array elements between a + * specified sample and the corresponding sample in the same column in + * the next scanline. The array of band offsets gives the starting + * offsets within each data banks of the in the DataBuffer. The bank + * indices represents the indices within each bank of the DataBuffer + * corresponding to a band of image data. + */ +public class ComponentSampleModel extends SampleModel { + + /** The band offsets array of this ComponentSampleModel. */ + protected int bandOffsets[]; + + /** The bank indices array of this ComponentSampleModel. */ + protected int bankIndices[]; + + /** The number of bands in this ComponentSampleModel. */ + protected int numBands; + + /** The number banks of this ComponentSampleModel. */ + protected int numBanks; + + /** The scanline stride of this ComponentSampleModel. */ + protected int scanlineStride; + + /** The pixel stride of this ComponentSampleModel. */ + protected int pixelStride; + + /** + * Instantiates a new ComponentSampleModel with the specified + * properties. + * + * @param dataType the data type of samples. + * @param w the width of the image data. + * @param h the height of the image data. + * @param pixelStride the pixel stride of the image data. + * @param scanlineStride the scanline stride of the image data. + * @param bankIndices the array of the bank indices. + * @param bandOffsets the array of the band offsets. + */ + public ComponentSampleModel(int dataType, int w, int h, int pixelStride, + int scanlineStride, int bankIndices[], int bandOffsets[]) { + + super(dataType, w, h, bandOffsets.length); + + if (pixelStride < 0) { + // awt.24B=Pixel stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$ + } + + if (scanlineStride < 0) { + // awt.24C=Scanline stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$ + } + + if (bankIndices.length != bandOffsets.length) { + // awt.24D=Bank Indices length must be equal Bank Offsets length + throw new IllegalArgumentException(Messages.getString("awt.24D")); //$NON-NLS-1$ + } + + this.pixelStride = pixelStride; + this.scanlineStride = scanlineStride; + this.bandOffsets = bandOffsets.clone(); + this.bankIndices = bankIndices.clone(); + this.numBands = bandOffsets.length; + + int maxBank = 0; + for (int i = 0; i < bankIndices.length; i++) { + if (bankIndices[i] < 0) { + // awt.24E=Index of {0} bank must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24E", i)); //$NON-NLS-1$ + } + if (bankIndices[i] > maxBank) { + maxBank = bankIndices[i]; + } + } + this.numBanks = maxBank + 1; + + } + + /** + * Instantiates a new ComponentSampleModel with the specified + * properties. + * + * @param dataType the data type of the samples. + * @param w the width of the image data. + * @param h the height of the image data. + * @param pixelStride the pixel stride of the image data. + * @param scanlineStride the scanline stride of the image data. + * @param bandOffsets the band offsets. + */ + public ComponentSampleModel(int dataType, int w, int h, int pixelStride, + int scanlineStride, int bandOffsets[]) { + + super(dataType, w, h, bandOffsets.length); + if (pixelStride < 0) { + // awt.24B=Pixel stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$ + } + + if (scanlineStride < 0) { + // awt.24C=Scanline stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$ + } + + this.pixelStride = pixelStride; + this.scanlineStride = scanlineStride; + this.bandOffsets = bandOffsets.clone(); + this.numBands = bandOffsets.length; + this.numBanks = 1; + + this.bankIndices = new int[numBands]; + for (int i = 0; i < numBands; i++) { + bankIndices[i] = 0; + } + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (dataType) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[numBands]; + } else { + bdata = (byte[]) obj; + } + + for (int i = 0; i < numBands; i++) { + bdata[i] = (byte) getSample(x, y, i, data); + } + + obj = bdata; + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[numBands]; + } else { + sdata = (short[]) obj; + } + + for (int i = 0; i < numBands; i++) { + sdata[i] = (short) getSample(x, y, i, data); + } + + obj = sdata; + break; + + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[numBands]; + } else { + idata = (int[]) obj; + } + + for (int i = 0; i < numBands; i++) { + idata[i] = getSample(x, y, i, data); + } + + obj = idata; + break; + + case DataBuffer.TYPE_FLOAT: + float fdata[]; + if (obj == null) { + fdata = new float[numBands]; + } else { + fdata = (float[]) obj; + } + + for (int i = 0; i < numBands; i++) { + fdata[i] = getSampleFloat(x, y, i, data); + } + + obj = fdata; + break; + + case DataBuffer.TYPE_DOUBLE: + double ddata[]; + if (obj == null) { + ddata = new double[numBands]; + } else { + ddata = (double[]) obj; + } + + for (int i = 0; i < numBands; i++) { + ddata[i] = getSampleDouble(x, y, i, data); + } + + obj = ddata; + break; + } + + return obj; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (dataType) { + case DataBuffer.TYPE_BYTE: + byte barr[] = (byte[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, barr[i] & 0xff, data); + } + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sarr[] = (short[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, sarr[i] & 0xffff, data); + } + break; + + case DataBuffer.TYPE_INT: + int iarr[] = (int[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iarr[i], data); + } + break; + + case DataBuffer.TYPE_FLOAT: + float farr[] = (float[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, farr[i], data); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double darr[] = (double[]) obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, darr[i], data); + } + break; + } + } + + /** + * Compares this ComponentSampleModel with the specified Object. + * + * @param o the Object. + * + * @return true, if the object is a ComponentSampleModel with + * identical data values to this ComponentSampleModel, false otherwise. + */ + @Override + public boolean equals(Object o) { + if ((o == null) || !(o instanceof ComponentSampleModel)) { + return false; + } + ComponentSampleModel model = (ComponentSampleModel) o; + return this.width == model.width && this.height == model.height && + this.numBands == model.numBands && + this.dataType == model.dataType && + Arrays.equals(this.bandOffsets, model.bandOffsets) && + Arrays.equals(this.bankIndices, model.bankIndices) && + this.numBands == model.numBands && + this.numBanks == model.numBanks && + this.scanlineStride == model.scanlineStride && + this.pixelStride == model.pixelStride; + } + + /** + * @see java.awt.image.SampleModel#createSubsetSampleModel(int[]) + */ + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands.length > this.numBands) { + // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model + throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ + } + + int indices[] = new int[bands.length]; + int offsets[] = new int[bands.length]; + + for (int i = 0; i < bands.length; i++) { + indices[i] = bankIndices[bands[i]]; + offsets[i] = bandOffsets[bands[i]]; + } + + return new ComponentSampleModel(dataType, width, height, pixelStride, + scanlineStride, indices, offsets); + + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new ComponentSampleModel(dataType, w, h, pixelStride, + pixelStride * w, bankIndices, bandOffsets); + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + int pixel[]; + + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElem(bankIndices[b], y * scanlineStride + + x * pixelStride + bandOffsets[b]); + } + + @Override + public float getSampleFloat(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemFloat(bankIndices[b], y * scanlineStride + + x * pixelStride + bandOffsets[b]); + } + + @Override + public double getSampleDouble(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemDouble(bankIndices[b], y * scanlineStride + + x * pixelStride + bandOffsets[b]); + } + + @Override + public int[] getPixels(int x, int y, int w, int h, int iArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x > this.width || x + w > this.width + || y > this.height || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixels[] = null; + int idx = 0; + + if (iArray == null) { + pixels = new int[w * h * numBands]; + } else { + pixels = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSample(j, i, n, data); + } + } + } + + return pixels; + } + + @Override + public void setPixels(int x, int y, int w, int h, int iArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b], s); + } + + @Override + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + if (data == null) { + // awt.295=data is null + throw new NullPointerException(Messages.getString("awt.295")); //$NON-NLS-1$ + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int iArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, iArray[idx++], data); + } + } + } + + @Override + public void setSample(int x, int y, int b, float s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemFloat(bankIndices[b], y * scanlineStride + + x * pixelStride + bandOffsets[b], s); + } + + @Override + public void setSample(int x, int y, int b, double s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemDouble(bankIndices[b], y * scanlineStride + + x * pixelStride + bandOffsets[b], s); + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer data = null; + + int maxOffset = bandOffsets[0]; + for (int i = 1; i < bandOffsets.length; i++) { + if (bandOffsets[i] > maxOffset) { + maxOffset = bandOffsets[i]; + } + } + int size = (height - 1) * scanlineStride + + (width - 1) * pixelStride + maxOffset + 1; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size, numBanks); + break; + case DataBuffer.TYPE_SHORT: + data = new DataBufferShort(size, numBanks); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size, numBanks); + break; + case DataBuffer.TYPE_FLOAT: + data = new DataBufferFloat(size, numBanks); + break; + case DataBuffer.TYPE_DOUBLE: + data = new DataBufferDouble(size, numBanks); + break; + } + + return data; + + } + + /** + * Gets the offset of the specified band of the specified pixel. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the band. + * + * @return the offset of the specified band of the specified pixel. + */ + public int getOffset(int x, int y, int b) { + return y * scanlineStride + x * pixelStride + bandOffsets[b]; + } + + /** + * Gets the offset of the first band of the specified pixel. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * + * @return the offset of the first band of the specified pixel. + */ + public int getOffset(int x, int y) { + return y * scanlineStride + x * pixelStride + bandOffsets[0]; + } + + @Override + public final int getSampleSize(int band) { + return DataBuffer.getDataTypeSize(dataType); + } + + @Override + public final int[] getSampleSize() { + int sampleSizes[] = new int[numBands]; + int size = DataBuffer.getDataTypeSize(dataType); + + for (int i = 0; i < numBands; i++) { + sampleSizes[i] = size; + } + return sampleSizes; + } + + /** + * Gets an array of bank indices corresponding to this + * ComponentSampleModel. + * + * @return the array of bank indices. + */ + public final int[] getBankIndices() { + return bankIndices.clone(); + } + + /** + * Gets an array of the band offsets corresponding to this + * ComponentSampleModel. + * + * @return the array of band offsets. + */ + public final int[] getBandOffsets() { + return bandOffsets.clone(); + } + + /** + * Gets a hash code of this ComponentSampleModel object. + * + * @return a hash code of this ComponentSampleModel object. + */ + @Override + public int hashCode() { + int hash = 0; + int tmp = 0; + + hash = width; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= height; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= numBands; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataType; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + for (int element : bandOffsets) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + for (int element : bankIndices) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + hash ^= pixelStride; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + + hash ^= scanlineStride; + return hash; + } + + /** + * Gets the scanline stride of this ComponentSampleModel. + * + * @return the scanline stride of this ComponentSampleModel. + */ + public final int getScanlineStride() { + return scanlineStride; + } + + /** + * Gets the pixel stride. + * + * @return the pixel stride + */ + public final int getPixelStride() { + return pixelStride; + } + + @Override + public final int getNumDataElements() { + return numBands; + } + +} + + + diff --git a/awt/java/awt/image/ConvolveOp.java b/awt/java/awt/image/ConvolveOp.java new file mode 100644 index 0000000..bb588bc --- /dev/null +++ b/awt/java/awt/image/ConvolveOp.java @@ -0,0 +1,545 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Sep 29, 2005 + */ + +package java.awt.image; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ConvolveOp class convolves from the source data + * to the destination using a convolution kernel. + * Each output pixel is represented as the result of multiplying + * the kernel and the surround of the input pixel. + */ +public class ConvolveOp implements BufferedImageOp, RasterOp { + + /** + * The Constant EDGE_ZERO_FILL indicates that pixels at the edge of + * the destination image are set to zero. + */ + public static final int EDGE_ZERO_FILL = 0; + + /** + * The Constant EDGE_NO_OP indicates that pixels at the edge of + * the source image are converted to the edge pixels in the + * destination without modification. + */ + public static final int EDGE_NO_OP = 1; + + /** The kernel. */ + private Kernel kernel; + + /** The edge cond. */ + private int edgeCond; + + /** The rhs. */ + private RenderingHints rhs = null; + + static { + // TODO + //System.loadLibrary("imageops"); + } + + /** + * Instantiates a new ConvolveOp object with the specified Kernel + * and specified edges condition. + * + * @param kernel the specified Kernel. + * @param edgeCondition the specified edge condition. + * @param hints the RenderingHints object, or null. + */ + public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) { + this.kernel = kernel; + this.edgeCond = edgeCondition; + this.rhs = hints; + } + + /** + * Instantiates a new ConvolveOp object with the specified Kernel + * and EDGE_ZERO_FILL edge condition. + * + * @param kernel the specified Kernel. + */ + public ConvolveOp(Kernel kernel) { + this.kernel = kernel; + this.edgeCond = EDGE_ZERO_FILL; + } + + /** + * Gets the Kernel object of this ConvolveOp. + * + * @return the Kernel object of this ConvolveOp. + */ + public final Kernel getKernel() { + return (Kernel) kernel.clone(); + } + + public final RenderingHints getRenderingHints() { + return rhs; + } + + /** + * Gets the edge condition of this ConvolveOp. + * + * @return the edge condition: EDGE_NO_OP or EDGE_ZERO_FILL. + */ + public int getEdgeCondition() { + return edgeCond; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt == null) { + dstPt = new Point2D.Float(); + } + + dstPt.setLocation(srcPt); + return dstPt; + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { + if (dstCM == null) { + dstCM = src.getColorModel(); + } + + if (dstCM instanceof IndexColorModel) { + dstCM = ColorModel.getRGBdefault(); + } + + WritableRaster r = + dstCM.isCompatibleSampleModel(src.getSampleModel()) ? + src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : + dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage( + dstCM, + r, + dstCM.isAlphaPremultiplied(), + null + ); + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (src == null) { // Should throw according to spec + // awt.256=Source raster is null + throw new NullPointerException(Messages.getString("awt.256")); //$NON-NLS-1$ + } + + if (src == dst){ + // awt.257=Source raster is equal to destination + throw new IllegalArgumentException(Messages.getString("awt.257")); //$NON-NLS-1$ + } + + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else if (src.getNumBands() != dst.getNumBands()) { + // awt.258=Number of source bands ({0}) is not equal to number of destination bands ({1}) + throw new IllegalArgumentException( + Messages.getString("awt.258", src.getNumBands(), dst.getNumBands())); //$NON-NLS-1$ + } + + // TODO + //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) + if (slowFilter(src, dst) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + /** + * Slow filter. + * + * @param src the src + * @param dst the dst + * + * @return the int + */ + private int slowFilter(Raster src, WritableRaster dst) { + try { + SampleModel sm = src.getSampleModel(); + + int numBands = src.getNumBands(); + int srcHeight = src.getHeight(); + int srcWidth = src.getWidth(); + + int xOrigin = kernel.getXOrigin(); + int yOrigin = kernel.getYOrigin(); + int kWidth = kernel.getWidth(); + int kHeight = kernel.getHeight(); + float[] data = kernel.getKernelData(null); + + int srcMinX = src.getMinX(); + int srcMinY = src.getMinY(); + int dstMinX = dst.getMinX(); + int dstMinY = dst.getMinY(); + + int srcConvMaxX = srcWidth - (kWidth - xOrigin - 1); + int srcConvMaxY = srcHeight - (kHeight - yOrigin - 1); + + int[] maxValues = new int[numBands]; + int[] masks = new int[numBands]; + int[] sampleSizes = sm.getSampleSize(); + + for (int i=0; i < numBands; i++){ + maxValues[i] = (1 << sampleSizes[i]) - 1; + masks[i] = ~(maxValues[i]); + } + + // Processing bounds + float[] pixels = null; + pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels); + float[] newPixels = new float[pixels.length]; + int rowLength = srcWidth*numBands; + if (this.edgeCond == ConvolveOp.EDGE_NO_OP){ + // top + int start = 0; + int length = yOrigin*rowLength; + System.arraycopy(pixels, start, newPixels, start, length); + // bottom + start = (srcHeight - (kHeight - yOrigin - 1))*rowLength; + length = (kHeight - yOrigin - 1)*rowLength; + System.arraycopy(pixels, start, newPixels, start, length); + // middle + length = xOrigin*numBands; + int length1 = (kWidth - xOrigin - 1)*numBands; + start = yOrigin*rowLength; + int start1 = (yOrigin+1)*rowLength - length1; + for (int i = yOrigin; i < (srcHeight - (kHeight - yOrigin - 1)); i ++) { + System.arraycopy(pixels, start, newPixels, start, length); + System.arraycopy(pixels, start1, newPixels, start1, length1); + start +=rowLength; + start1 +=rowLength; + } + + } + + // Cycle over pixels to be calculated + for (int i = yOrigin; i < srcConvMaxY; i++){ + for (int j = xOrigin; j < srcConvMaxX; j++){ + + // Take kernel data in backward direction, convolution + int kernelIdx = data.length - 1; + + int pixelIndex = i * rowLength + j * numBands; + for (int hIdx = 0, rasterHIdx = i - yOrigin; + hIdx < kHeight; + hIdx++, rasterHIdx++ + ){ + for (int wIdx = 0, rasterWIdx = j - xOrigin; + wIdx < kWidth; + wIdx++, rasterWIdx++ + ){ + int curIndex = rasterHIdx * rowLength + rasterWIdx * numBands; + for (int idx=0; idx < numBands; idx++){ + newPixels[pixelIndex+idx] += data[kernelIdx] * pixels[curIndex+idx]; + } + kernelIdx--; + } + } + + // Check for overflow now + for (int idx=0; idx < numBands; idx++){ + if (((int)newPixels[pixelIndex+idx] & masks[idx]) != 0) { + if (newPixels[pixelIndex+idx] < 0) { + newPixels[pixelIndex+idx] = 0; + } else { + newPixels[pixelIndex+idx] = maxValues[idx]; + } + } + } + } + } + + dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, newPixels); + } catch (Exception e) { // Something goes wrong, signal error + return 1; + } + return 0; + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + if (src == null) { + // awt.259=Source image is null + throw new NullPointerException(Messages.getString("awt.259")); //$NON-NLS-1$ + } + + if (src == dst){ + // awt.25A=Source equals to destination + throw new IllegalArgumentException(Messages.getString("awt.25A")); //$NON-NLS-1$ + } + + ColorModel srcCM = src.getColorModel(); + BufferedImage finalDst = null; + + if (srcCM instanceof IndexColorModel) { + src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true); + srcCM = src.getColorModel(); + } + + if (dst == null) { + dst = createCompatibleDestImage(src, srcCM); + } else { + if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same + if ( + !((src.getType() == BufferedImage.TYPE_INT_RGB || + src.getType() == BufferedImage.TYPE_INT_ARGB) && + (dst.getType() == BufferedImage.TYPE_INT_RGB || + dst.getType() == BufferedImage.TYPE_INT_ARGB)) + ) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } + } + } + + // Skip alpha channel for TYPE_INT_RGB images + // TODO + //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0) + if (slowFilter(src.getRaster(), dst.getRaster()) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return finalDst; + } + + // TODO remove when this method is used + /** + * Ipp filter. + * + * @param src the src + * @param dst the dst + * @param imageType the image type + * + * @return the int + */ + @SuppressWarnings("unused") + private int ippFilter(Raster src, WritableRaster dst, int imageType) { + int srcStride, dstStride; + boolean skipChannel = false; + int channels; + int offsets[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_RGB: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth()*4; + dstStride = dst.getWidth()*4; + skipChannel = true; + break; + } + + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: { + channels = 4; + srcStride = src.getWidth()*4; + dstStride = dst.getWidth()*4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth()*3; + dstStride = dst.getWidth()*3; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in native code? + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if ( + srcSM instanceof PixelInterleavedSampleModel && + dstSM instanceof PixelInterleavedSampleModel + ) { + // Check PixelInterleavedSampleModel + if ( + srcSM.getDataType() != DataBuffer.TYPE_BYTE || + dstSM.getDataType() != DataBuffer.TYPE_BYTE + ) { + return slowFilter(src, dst); + } + + channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels + if (!(channels == 1 || channels == 3 || channels == 4)) { + return slowFilter(src, dst); + } + + srcStride = ((ComponentSampleModel) srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel) dstSM).getScanlineStride(); + } else if ( + srcSM instanceof SinglePixelPackedSampleModel && + dstSM instanceof SinglePixelPackedSampleModel + ) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM; + + channels = sppsm1.getNumBands(); + + // TYPE_INT_RGB, TYPE_INT_ARGB... + if ( + sppsm1.getDataType() != DataBuffer.TYPE_INT || + sppsm2.getDataType() != DataBuffer.TYPE_INT || + !(channels == 3 || channels == 4) + ) { + return slowFilter(src, dst); + } + + // Check compatibility of sample models + if ( + !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) || + !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks()) + ) { + return slowFilter(src, dst); + } + + for (int i=0; i props) { + Hashtable fprops; + if(props == null) { + fprops = new Hashtable(); + } else { + fprops = (Hashtable) props.clone(); + } + String propName = "Crop Filters"; //$NON-NLS-1$ + String prop = "x=" + X + "; y=" + Y + "; width=" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + WIDTH + "; height=" + HEIGHT; //$NON-NLS-1$ + Object o = fprops.get(propName); + if(o != null){ + if(o instanceof String){ + prop = (String)o + "; " + prop; //$NON-NLS-1$ + }else{ + prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } + } + fprops.put(propName, prop); + consumer.setProperties(fprops); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) { + + if(x + w < X || X + WIDTH < x || + y + h < Y || Y + HEIGHT < y) { + return; + } + + int destX, destY, destWidth, destHeight, endX, endY, + srcEndX, srcEndY; + + int newOffset = off; + + endX = X + WIDTH; + endY = Y + HEIGHT; + + srcEndX = x + w; + srcEndY = y + h; + + if(x <= X){ + destX = 0; + newOffset += X; + if(endX >= srcEndX){ + destWidth = srcEndX - X; + }else{ + destWidth = WIDTH; + } + }else{ + destX = x - X; + if(endX >= srcEndX){ + destWidth = w; + }else{ + destWidth = endX - x; + } + } + + + if(y <= Y){ + newOffset += scansize * (Y - y); + destY = 0; + if(endY >= srcEndY){ + destHeight = srcEndY - Y; + }else{ + destHeight = HEIGHT; + } + }else{ + destY = y - Y; + if(endY >= srcEndY){ + destHeight = h; + }else{ + destHeight = endY - y; + } + } + consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) { + + if(x + w < X || X + WIDTH < x || + y + h < Y || Y + HEIGHT < y) { + return; + } + + int destX, destY, destWidth, destHeight, endX, endY, + srcEndX, srcEndY; + + int newOffset = off; + + endX = X + WIDTH; + endY = Y + HEIGHT; + + srcEndX = x + w; + srcEndY = y + h; + + if(x <= X){ + destX = 0; + newOffset += X; + if(endX >= srcEndX){ + destWidth = srcEndX - X; + }else{ + destWidth = WIDTH; + } + }else{ + destX = x - X; + if(endX >= srcEndX){ + destWidth = w; + }else{ + destWidth = endX - x; + } + } + + + if(y <= Y){ + newOffset += scansize * (Y - y); + destY = 0; + if(endY >= srcEndY){ + destHeight = srcEndY - Y; + }else{ + destHeight = HEIGHT; + } + }else{ + destY = y - Y; + if(endY >= srcEndY){ + destHeight = h; + }else{ + destHeight = endY - y; + } + } + consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize); + } + + @Override + public void setDimensions(int w, int h) { + consumer.setDimensions(WIDTH, HEIGHT); + } + +} + diff --git a/awt/java/awt/image/DataBuffer.java b/awt/java/awt/image/DataBuffer.java new file mode 100644 index 0000000..6856aee --- /dev/null +++ b/awt/java/awt/image/DataBuffer.java @@ -0,0 +1,442 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import org.apache.harmony.awt.gl.image.DataBufferListener; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class DataBuffer is a wrapper class for a data array + * to be used for the situation where a suite of functionality + * acts on a set of data in a consistent way even though the + * primitive type of the data may vary from one use to the next. + */ +public abstract class DataBuffer { + + /** The Constant TYPE_BYTE. */ + public static final int TYPE_BYTE = 0; + + /** The Constant TYPE_USHORT. */ + public static final int TYPE_USHORT = 1; + + /** The Constant TYPE_SHORT. */ + public static final int TYPE_SHORT = 2; + + /** The Constant TYPE_INT. */ + public static final int TYPE_INT = 3; + + /** The Constant TYPE_FLOAT. */ + public static final int TYPE_FLOAT = 4; + + /** The Constant TYPE_DOUBLE. */ + public static final int TYPE_DOUBLE = 5; + + /** The Constant TYPE_UNDEFINED. */ + public static final int TYPE_UNDEFINED = 32; + + /** The data type indicates the primitive type of the + * data in this DataBuffer. */ + protected int dataType; + + /** The number of data arrays in this DataBuffer. */ + protected int banks; + + /** The starting index for reading the + * data from the first (or only) internal data array. */ + protected int offset; + + /** The length (number of elements) of the data arrays. */ + protected int size; + + /** The starting indices for reading the + * data from the internal data arrays. */ + protected int offsets[]; + + /** The data changed. */ + boolean dataChanged = true; + + /** The data taken. */ + boolean dataTaken = false; + + /** The listener. */ + DataBufferListener listener; + + static { + AwtImageBackdoorAccessorImpl.init(); + } + + /** + * Instantiates a new data buffer. + * + * @param dataType the data type + * @param size the length (number of elements) of the data arrays + * @param numBanks the number of data arrays to create + * @param offsets the starting indices for reading the + * data from the internal data arrays + */ + protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) { + this.dataType = dataType; + this.size = size; + this.banks = numBanks; + this.offsets = offsets.clone(); + this.offset = offsets[0]; + } + + /** + * Instantiates a new data buffer with all of the + * data arrays starting at the same index. + * + * @param dataType the data type + * @param size the length (number of elements) of the data arrays + * @param numBanks the number of data arrays to create + * @param offset the offset to use for all of the data arrays + */ + protected DataBuffer(int dataType, int size, int numBanks, int offset) { + this.dataType = dataType; + this.size = size; + this.banks = numBanks; + this.offset = offset; + this.offsets = new int[numBanks]; + int i = 0; + while (i < numBanks) { + offsets[i++] = offset; + } + } + + /** + * Instantiates a new data buffer with all of the + * data arrays read from the beginning (at offset zero). + * + * @param dataType the data type + * @param size the length (number of elements) of the data arrays + * @param numBanks the number of data arrays to create + */ + protected DataBuffer(int dataType, int size, int numBanks) { + this.dataType = dataType; + this.size = size; + this.banks = numBanks; + this.offset = 0; + this.offsets = new int[numBanks]; + } + + /** + * Instantiates a new data buffer with one internal data array + * read from the beginning (at offset zero). + * + * @param dataType the data type + * @param size the length (number of elements) of the data arrays + */ + protected DataBuffer(int dataType, int size) { + this.dataType = dataType; + this.size = size; + this.banks = 1; + this.offset = 0; + this.offsets = new int[1]; + } + + /** + * Sets the data value in the specified array at the + * specified index. + * + * @param bank the internal array to the data to + * @param i the index within the array where the data + * should be written + * @param val the value to write into the array + */ + public abstract void setElem(int bank, int i, int val); + + /** + * Sets the float data value in the specified array at the + * specified index. + * + * @param bank the internal array to the data to + * @param i the index within the array where the data + * should be written + * @param val the value to write into the array + */ + public void setElemFloat(int bank, int i, float val) { + setElem(bank, i, (int) val); + } + + /** + * Sets the double data value in the specified array at the + * specified index. + * + * @param bank the internal array to the data to + * @param i the index within the array where the data + * should be written + * @param val the value to write into the array + */ + public void setElemDouble(int bank, int i, double val) { + setElem(bank, i, (int) val); + } + + /** + * Sets the data value in the first array at the + * specified index. + * + * @param i the index within the array where the data + * should be written + * @param val the value to write into the array + */ + public void setElem(int i, int val) { + setElem(0, i, val); + } + + /** + * Gets the data value from the specified data array at the + * specified index. + * + * @param bank the data array to read from + * @param i the index within the array where the data + * should be read + * + * @return the data element + */ + public abstract int getElem(int bank, int i); + + /** + * Gets the float-type data value from the specified + * data array at the specified index. + * + * @param bank the data array to read from + * @param i the index within the array where the data + * should be read + * + * @return the data element + */ + public float getElemFloat(int bank, int i) { + return getElem(bank, i); + } + + /** + * Gets the double-type data value from the specified + * data array at the specified index. + * + * @param bank the data array to read from + * @param i the index within the array where the data + * should be read + * + * @return the data element + */ + public double getElemDouble(int bank, int i) { + return getElem(bank, i); + } + + /** + * Sets the float data value in the first array at the + * specified index. + * + * @param i the index within the array where the data + * should be written + * @param val the value to write into the array + */ + public void setElemFloat(int i, float val) { + setElemFloat(0, i, val); + } + + /** + * Sets the double data value in the first array at the + * specified index. + * + * @param i the index within the array where the data + * should be written + * @param val the value to write into the array + */ + public void setElemDouble(int i, double val) { + setElemDouble(0, i, val); + } + + /** + * Gets the data value from the first + * data array at the specified index and returns it + * as an int. + * + * @param i the index within the array where the data + * should be read + * + * @return the data element + */ + public int getElem(int i) { + return getElem(0, i); + } + + /** + * Gets the data value from the first + * data array at the specified index and returns it + * as a float. + * + * @param i the index within the array where the data + * should be read + * + * @return the data element + */ + public float getElemFloat(int i) { + return getElem(0, i); + } + + /** + * Gets the data value from the first + * data array at the specified index and returns it + * as a double. + * + * @param i the index within the array where the data + * should be read + * + * @return the data element + */ + public double getElemDouble(int i) { + return getElem(i); + } + + /** + * Gets the array giving the offsets corresponding + * to the internal data arrays. + * + * @return the array of offsets + */ + public int[] getOffsets() { + return offsets; + } + + /** + * Gets the size in bits of the primitive data type. + * + * @return the size in bits of the primitive data type + + */ + public int getSize() { + return size; + } + + /** + * Gets the offset corresponding to the first internal + * data array. + * + * @return the offset + */ + public int getOffset() { + return offset; + } + + /** + * Gets the number of data arrays in this DataBuffer. + * + * @return the number of data arrays + */ + public int getNumBanks() { + return banks; + } + + /** + * Gets the primitive type of this buffer's data. + * + * @return the data type + */ + public int getDataType() { + return this.dataType; + } + + /** + * Gets the size in bits of the primitive data type. + * + * @param type the primitive type + * + * @return the size in bits of the primitive data type + */ + public static int getDataTypeSize(int type) { + switch (type) { + + case TYPE_BYTE: + return 8; + + case TYPE_USHORT: + case TYPE_SHORT: + return 16; + + case TYPE_INT: + case TYPE_FLOAT: + return 32; + + case TYPE_DOUBLE: + return 64; + + default: + // awt.22C=Unknown data type {0} + throw new IllegalArgumentException(Messages.getString("awt.22C", type)); //$NON-NLS-1$ + } + } + + /** + * Notifies the listener that the data has changed. + */ + void notifyChanged(){ + if(listener != null && !dataChanged){ + dataChanged = true; + listener.dataChanged(); + } + } + + /** + * Notifies the listener that the data has been released. + */ + void notifyTaken(){ + if(listener != null && !dataTaken){ + dataTaken = true; + listener.dataTaken(); + } + } + + /** + * Release the data. + */ + void releaseData(){ + if(listener != null && dataTaken){ + dataTaken = false; + listener.dataReleased(); + } + } + + /** + * Adds the data buffer listener. + * + * @param listener the listener + */ + void addDataBufferListener(DataBufferListener listener){ + this.listener = listener; + } + + /** + * Removes the data buffer listener. + */ + void removeDataBufferListener(){ + listener = null; + } + + /** + * Validate. + */ + void validate(){ + dataChanged = false; + } + +} + diff --git a/awt/java/awt/image/DataBufferByte.java b/awt/java/awt/image/DataBufferByte.java new file mode 100644 index 0000000..4d29c9c --- /dev/null +++ b/awt/java/awt/image/DataBufferByte.java @@ -0,0 +1,171 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +/** + * The Class DataBufferByte is the subclass of DataBuffer + * for the case where the underlying data is of type byte. + */ +public final class DataBufferByte extends DataBuffer { + + /** The data. */ + byte data[][]; + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + * @param offsets the starting indices for reading the + * data from the internal data arrays + */ + public DataBufferByte(byte dataArrays[][], int size, int offsets[]) { + super(TYPE_BYTE, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + */ + public DataBufferByte(byte dataArrays[][], int size) { + super(TYPE_BYTE, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short + * with a single underlying array of data. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + * @param offset the starting index to use when reading the data + */ + public DataBufferByte(byte dataArray[], int size, int offset) { + super(TYPE_BYTE, size, 1, offset); + data = new byte[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type unsigned short + * with a single underlying array of data starting at + * index 0. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + */ + public DataBufferByte(byte dataArray[], int size) { + super(TYPE_BYTE, size); + data = new byte[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type unsigned short + * with offsets equal to zero. + * + * @param size the length (number of elements) to use + * from the data arrays + * @param numBanks the number of data arrays to create + */ + public DataBufferByte(int size, int numBanks) { + super(TYPE_BYTE, size, numBanks); + data = new byte[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new byte[size]; + } + } + + /** + * Instantiates a new empty data buffer of type unsigned short + * with a single underlying array of data starting at + * index 0. + * + * @param size the length (number of elements) to use + */ + public DataBufferByte(int size) { + super(TYPE_BYTE, size); + data = new byte[1][]; + data[0] = new byte[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = (byte) val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = (byte) val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (data[bank][offsets[bank] + i]) & 0xff; + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank the index of the desired data array + * + * @return the data + */ + public byte[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (data[0][offset + i]) & 0xff; + } + + /** + * Gets the bank data. + * + * @return the bank data + */ + public byte[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data + */ + public byte[] getData() { + notifyTaken(); + return data[0]; + } + +} + diff --git a/awt/java/awt/image/DataBufferDouble.java b/awt/java/awt/image/DataBufferDouble.java new file mode 100644 index 0000000..fa3d324 --- /dev/null +++ b/awt/java/awt/image/DataBufferDouble.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +/** + * The Class DataBufferDouble is the subclass of DataBuffer + * for the case where the underlying data is of type double. + */ +public final class DataBufferDouble extends DataBuffer { + + /** The data. */ + double data[][]; + + /** + * Instantiates a new data buffer of type double. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + * @param offsets the starting indices for reading the + * data from the internal data arrays + */ + public DataBufferDouble(double dataArrays[][], int size, int offsets[]) { + super(TYPE_DOUBLE, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type double. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + */ + public DataBufferDouble(double dataArrays[][], int size) { + super(TYPE_DOUBLE, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type double + * with a single underlying array of data. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + * @param offset the starting index to use when reading the data + */ + public DataBufferDouble(double dataArray[], int size, int offset) { + super(TYPE_DOUBLE, size, 1, offset); + data = new double[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type double + * with a single underlying array of data starting at + * index 0. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + */ + public DataBufferDouble(double dataArray[], int size) { + super(TYPE_DOUBLE, size); + data = new double[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type double + * with offsets equal to zero. + * + * @param size the length (number of elements) to use + * from the data arrays + * @param numBanks the number of data arrays to create + */ + public DataBufferDouble(int size, int numBanks) { + super(TYPE_DOUBLE, size, numBanks); + data = new double[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new double[size]; + } + } + + /** + * Instantiates a new empty data buffer of type double + * with a single underlying array of data starting at + * index 0. + * + * @param size the length (number of elements) to use + */ + public DataBufferDouble(int size) { + super(TYPE_DOUBLE, size); + data = new double[1][]; + data[0] = new double[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemFloat(int bank, int i, float val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int bank, int i, double val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (int) (data[bank][offsets[bank] + i]); + } + + @Override + public float getElemFloat(int bank, int i) { + return (float) (data[bank][offsets[bank] + i]); + } + + @Override + public double getElemDouble(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + @Override + public void setElemFloat(int i, float val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int i, double val) { + data[0][offset + i] = val; + notifyChanged(); + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank the index of the desired data array + * + * @return the data + */ + public double[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (int) (data[0][offset + i]); + } + + @Override + public float getElemFloat(int i) { + return (float) (data[0][offset + i]); + } + + @Override + public double getElemDouble(int i) { + return data[0][offset + i]; + } + + /** + * Gets the bank data. + * + * @return the bank data + */ + public double[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data + */ + public double[] getData() { + notifyTaken(); + return data[0]; + } +} + diff --git a/awt/java/awt/image/DataBufferFloat.java b/awt/java/awt/image/DataBufferFloat.java new file mode 100644 index 0000000..e34245c --- /dev/null +++ b/awt/java/awt/image/DataBufferFloat.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +/** + * The Class DataBufferFloat is the subclass of DataBuffer + * for the case where the underlying data is float. + */ +public final class DataBufferFloat extends DataBuffer { + + /** The data. */ + float data[][]; + + /** + * Instantiates a new data buffer of type float. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + * @param offsets the starting indices for reading the + * data from the internal data arrays + */ + public DataBufferFloat(float dataArrays[][], int size, int offsets[]) { + super(TYPE_FLOAT, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type float. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + */ + public DataBufferFloat(float dataArrays[][], int size) { + super(TYPE_FLOAT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type float + * with a single underlying array of data. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + * @param offset the starting index to use when reading the data + */ + public DataBufferFloat(float dataArray[], int size, int offset) { + super(TYPE_FLOAT, size, 1, offset); + data = new float[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type float + * with a single underlying array of data starting at + * index 0. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + */ + public DataBufferFloat(float dataArray[], int size) { + super(TYPE_FLOAT, size); + data = new float[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type float + * with offsets equal to zero. + * + * @param size the length (number of elements) to use + * from the data arrays + * @param numBanks the number of data arrays to create + */ + public DataBufferFloat(int size, int numBanks) { + super(TYPE_FLOAT, size, numBanks); + data = new float[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new float[size]; + } + } + + /** + * Instantiates a new empty data buffer of type float + * with a single underlying array of data starting at + * index 0. + * + * @param size the length (number of elements) to use + */ + public DataBufferFloat(int size) { + super(TYPE_FLOAT, size); + data = new float[1][]; + data[0] = new float[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemFloat(int bank, int i, float val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int bank, int i, double val) { + data[bank][offsets[bank] + i] = (float) val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (int) (data[bank][offsets[bank] + i]); + } + + @Override + public float getElemFloat(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + @Override + public double getElemDouble(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + @Override + public void setElemFloat(int i, float val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int i, double val) { + data[0][offset + i] = (float) val; + notifyChanged(); + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank the index of the desired array + * + * @return the data + */ + public float[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (int) (data[0][offset + i]); + } + + @Override + public float getElemFloat(int i) { + return data[0][offset + i]; + } + + @Override + public double getElemDouble(int i) { + return data[0][offset + i]; + } + + /** + * Gets the bank data. + * + * @return the bank data + */ + public float[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data + */ + public float[] getData() { + notifyTaken(); + return data[0]; + } +} + diff --git a/awt/java/awt/image/DataBufferInt.java b/awt/java/awt/image/DataBufferInt.java new file mode 100644 index 0000000..43dc188 --- /dev/null +++ b/awt/java/awt/image/DataBufferInt.java @@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +/** + * The Class DataBufferInt is the subclass of DataBuffer + * for the case where the underlying data is of type int. + */ +public final class DataBufferInt extends DataBuffer { + + /** The data. */ + int data[][]; + + /** + * Instantiates a new data buffer of type int. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + * @param offsets the starting indices for reading the + * data from the internal data arrays + */ + public DataBufferInt(int dataArrays[][], int size, int offsets[]) { + super(TYPE_INT, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type int. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + */ + public DataBufferInt(int dataArrays[][], int size) { + super(TYPE_INT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type int + * with a single underlying array of data. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + * @param offset the starting index to use when reading the data + */ + public DataBufferInt(int dataArray[], int size, int offset) { + super(TYPE_INT, size, 1, offset); + data = new int[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type int + * with a single underlying array of data starting at + * index 0. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + */ + public DataBufferInt(int dataArray[], int size) { + super(TYPE_INT, size); + data = new int[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type int + * with offsets equal to zero. + * + * @param size the length (number of elements) to use + * from the data arrays + * @param numBanks the number of data arrays to create + */ + public DataBufferInt(int size, int numBanks) { + super(TYPE_INT, size, numBanks); + data = new int[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new int[size]; + } + } + + /** + * Instantiates a new empty data buffer of type int + * with a single underlying array of data starting at + * index 0. + * + * @param size the length (number of elements) to use + */ + public DataBufferInt(int size) { + super(TYPE_INT, size); + data = new int[1][]; + data[0] = new int[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank the index of the desired data array + * + * @return the data + */ + public int[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return data[0][offset + i]; + } + + /** + * Gets the bank data. + * + * @return the bank data + */ + public int[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data + */ + public int[] getData() { + notifyTaken(); + return data[0]; + } +} + diff --git a/awt/java/awt/image/DataBufferShort.java b/awt/java/awt/image/DataBufferShort.java new file mode 100644 index 0000000..819ba4a --- /dev/null +++ b/awt/java/awt/image/DataBufferShort.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +/** + * The Class DataBufferShort is the subclass of DataBuffer + * for the case where the underlying data is short. + */ +public final class DataBufferShort extends DataBuffer { + + /** The data. */ + short data[][]; + + /** + * Instantiates a new data buffer of type short. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + * @param offsets the starting indices for reading the + * data from the internal data arrays + */ + public DataBufferShort(short dataArrays[][], int size, int offsets[]) { + super(TYPE_SHORT, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type short. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + */ + public DataBufferShort(short dataArrays[][], int size) { + super(TYPE_SHORT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type short + * with a single underlying array of data. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + * @param offset the starting index to use when reading the data + + */ + public DataBufferShort(short dataArray[], int size, int offset) { + super(TYPE_SHORT, size, 1, offset); + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type short + * with a single underlying array of data starting at + * index 0. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + + */ + public DataBufferShort(short dataArray[], int size) { + super(TYPE_SHORT, size); + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type short + * with offsets equal to zero. + * + * @param size the length (number of elements) to use + * from the data arrays + * @param numBanks the number of data arrays to create + */ + public DataBufferShort(int size, int numBanks) { + super(TYPE_SHORT, size, numBanks); + data = new short[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new short[size]; + } + } + + /** + * Instantiates a new empty data buffer of type short + * with a single underlying array of data starting at + * index 0. + * + * @param size the length (number of elements) to use + */ + public DataBufferShort(int size) { + super(TYPE_SHORT, size); + data = new short[1][]; + data[0] = new short[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = (short) val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = (short) val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (data[bank][offsets[bank] + i]); + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank the index of the desired data array + * + * @return the data + */ + public short[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (data[0][offset + i]); + } + + /** + * Gets the bank data. + * + * @return the bank data + */ + public short[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data + */ + public short[] getData() { + notifyTaken(); + return data[0]; + } +} + diff --git a/awt/java/awt/image/DataBufferUShort.java b/awt/java/awt/image/DataBufferUShort.java new file mode 100644 index 0000000..7982678 --- /dev/null +++ b/awt/java/awt/image/DataBufferUShort.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class DataBufferUShort is the subclass of DataBuffer + * for the case where the underlying data is unsigned short. + */ +public final class DataBufferUShort extends DataBuffer { + + /** The data. */ + short data[][]; + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + * @param offsets the starting indices for reading the + * data from the internal data arrays + */ + public DataBufferUShort(short dataArrays[][], int size, int offsets[]) { + super(TYPE_USHORT, size, dataArrays.length, offsets); + for(int i = 0; i < dataArrays.length; i++){ + if(dataArrays[i].length < offsets[i] + size){ + // awt.28d=Length of dataArray[{0}] is less than size + offset[{1}] + throw new IllegalArgumentException(Messages.getString("awt.28D", i, i)); //$NON-NLS-1$ + } + } + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays the data arrays to copy the data from + * @param size the length (number of elements) to use + * from the data arrays + */ + public DataBufferUShort(short dataArrays[][], int size) { + super(TYPE_USHORT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short + * with a single underlying array of data. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + * @param offset the starting index to use when reading the data + */ + public DataBufferUShort(short dataArray[], int size, int offset) { + super(TYPE_USHORT, size, 1, offset); + if(dataArray.length < size + offset){ + // awt.28E=Length of dataArray is less than size + offset + throw new IllegalArgumentException(Messages.getString("awt.28E")); //$NON-NLS-1$ + } + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type unsigned short + * with a single underlying array of data starting at + * index 0. + * + * @param dataArray the data array to copy the data from + * @param size the length (number of elements) to use + */ + public DataBufferUShort(short dataArray[], int size) { + super(TYPE_USHORT, size); + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type unsigned short + * with offsets equal to zero. + * + * @param size the length (number of elements) to use + * from the data arrays + * @param numBanks the number of data arrays to create + */ + public DataBufferUShort(int size, int numBanks) { + super(TYPE_USHORT, size, numBanks); + data = new short[numBanks][]; + int i= 0; + while( i < numBanks) { + data[i++] = new short[size]; + } + } + + /** + * Instantiates a new empty data buffer of type unsigned short + * with a single underlying array of data starting at + * index 0. + * + * @param size the length (number of elements) to use + */ + public DataBufferUShort(int size) { + super(TYPE_USHORT, size); + data = new short[1][]; + data[0] = new short[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = (short)val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = (short)val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (data[bank][offsets[bank] + i]) & 0xffff; + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank the index of the desired data array + * + * @return the data + */ + public short[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (data[0][offset + i]) & 0xffff; + } + + /** + * Gets the bank data. + * + * @return the bank data + */ + public short[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data + */ + public short[] getData() { + notifyTaken(); + return data[0]; + } +} + diff --git a/awt/java/awt/image/DirectColorModel.java b/awt/java/awt/image/DirectColorModel.java new file mode 100644 index 0000000..7a287c0 --- /dev/null +++ b/awt/java/awt/image/DirectColorModel.java @@ -0,0 +1,862 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.color.ColorSpace; +import java.awt.Transparency; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class DirectColorModel represents a standard (packed) RGB + * color model with additional support for converting between sRGB + * color space and 8 or 16 bit linear RGB color space using lookup tables. + */ +public class DirectColorModel extends PackedColorModel { + + /** The from_ linea r_ rg b_ lut. */ + private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from + // Linear RGB Color Space into sRGB + + /** The to_ linea r_8 rg b_ lut. */ + private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from + // sRGB Color Space into Linear RGB + // 8 bit + + /** The to_ linea r_16 rg b_ lut. */ + private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from + // sRGB Color Space into Linear RGB + // 16 bit + + /** The alpha lut. */ + private byte alphaLUT[]; // Lookup table for scale alpha value + + /** The color lu ts. */ + private byte colorLUTs[][]; // Lookup tables for scale color values + + /** The is_s rgb. */ + private boolean is_sRGB; // ColorModel has sRGB ColorSpace + + /** The is_ linea r_ rgb. */ + private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color + // Space + + /** The LINEA r_ rg b_ length. */ + private int LINEAR_RGB_Length; // Linear RGB bit length + + /** The factor. */ + private float fFactor; // Scale factor + + /** + * Instantiates a new direct color model. + * + * @param space the color space + * @param bits the array of component masks + * @param rmask the bitmask corresponding to the red band + * @param gmask the bitmask corresponding to the green band + * @param bmask the bitmask corresponding to the blue band + * @param amask the bitmask corresponding to the alpha band + * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model + * @param transferType the transfer type (primitive java type + * to use for the components) + * + * @throws IllegalArgumentException if the number of bits in the combined + * bitmasks for the color bands is less than one or greater than 32 + */ + public DirectColorModel(ColorSpace space, int bits, int rmask, int gmask, + int bmask, int amask, boolean isAlphaPremultiplied, + int transferType) { + + super(space, bits, rmask, gmask, bmask, amask, isAlphaPremultiplied, + (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), + transferType); + + initLUTs(); + } + + /** + * Instantiates a new direct color model, determining the transfer + * type from the bits array, the transparency from the alpha mask, + * and the default color space {@link ColorSpace#CS_sRGB}. + * + * @param bits the array of component masks + * @param rmask the bitmask corresponding to the red band + * @param gmask the bitmask corresponding to the green band + * @param bmask the bitmask corresponding to the blue band + * @param amask the bitmask corresponding to the alpha band + */ + public DirectColorModel(int bits, int rmask, int gmask, int bmask, + int amask) { + + super(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, rmask, gmask, + bmask, amask, false, + (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), + ColorModel.getTransferType(bits)); + + initLUTs(); + } + + /** + * Instantiates a new direct color model with no alpha channel, + * determining the transfer type from the bits array, + * the default color space {@link ColorSpace#CS_sRGB}, + * and with the transparency set to {@link Transparency#OPAQUE}. + * + * @param bits the array of component masks + * @param rmask the bitmask corresponding to the red band + * @param gmask the bitmask corresponding to the green band + * @param bmask the bitmask corresponding to the blue band + */ + public DirectColorModel(int bits, int rmask, int gmask, int bmask) { + this(bits, rmask, gmask, bmask, 0); + } + + @Override + public Object getDataElements(int components[], int offset, Object obj) { + int pixel = 0; + for (int i = 0; i < numComponents; i++) { + pixel |= (components[offset + i] << offsets[i]) & componentMasks[i]; + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[1]; + } else { + ba = (byte[]) obj; + } + ba[0] = (byte) pixel; + obj = ba; + break; + + case DataBuffer.TYPE_USHORT: + short sa[]; + if (obj == null) { + sa = new short[1]; + } else { + sa = (short[]) obj; + } + sa[0] = (short) pixel; + obj = sa; + break; + + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[1]; + } else { + ia = (int[]) obj; + } + ia[0] = pixel; + obj = ia; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + + return obj; + } + + @Override + public Object getDataElements(int rgb, Object pixel) { + if (equals(ColorModel.getRGBdefault())) { + int ia[]; + if (pixel == null) { + ia = new int[1]; + } else { + ia = (int[]) pixel; + } + ia[0] = rgb; + return ia; + } + + int alpha = (rgb >> 24) & 0xff; + int red = (rgb >> 16) & 0xff; + int green = (rgb >> 8) & 0xff; + int blue = rgb & 0xff; + + float comp[] = new float[numColorComponents]; + float normComp[] = null; + + if (is_sRGB || is_LINEAR_RGB) { + if (is_LINEAR_RGB) { + if (LINEAR_RGB_Length == 8) { + red = to_LINEAR_8RGB_LUT[red] & 0xff; + green = to_LINEAR_8RGB_LUT[green] & 0xff; + blue = to_LINEAR_8RGB_LUT[blue] & 0xff; + } else { + red = to_LINEAR_16RGB_LUT[red] & 0xffff; + green = to_LINEAR_16RGB_LUT[green] & 0xffff; + blue = to_LINEAR_16RGB_LUT[blue] & 0xffff; + } + } + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + if (!hasAlpha) { + normComp = comp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = comp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } else { + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + float rgbComp[] = cs.fromRGB(comp); + if (!hasAlpha) { + normComp = rgbComp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = rgbComp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } + + int pxl = 0; + if (hasAlpha) { + float normAlpha = normComp[numColorComponents]; + alpha = (int) (normAlpha * maxValues[numColorComponents] + 0.5f); + if (isAlphaPremultiplied) { + red = (int) (normComp[0] * normAlpha * maxValues[0] + 0.5f); + green = (int) (normComp[1] * normAlpha * maxValues[1] + 0.5f); + blue = (int) (normComp[2] * normAlpha * maxValues[2] + 0.5f); + } else { + red = (int) (normComp[0] * maxValues[0] + 0.5f); + green = (int) (normComp[1] * maxValues[1] + 0.5f); + blue = (int) (normComp[2] * maxValues[2] + 0.5f); + } + pxl = (alpha << offsets[3]) & componentMasks[3]; + } else { + red = (int) (normComp[0] * maxValues[0] + 0.5f); + green = (int) (normComp[1] * maxValues[1] + 0.5f); + blue = (int) (normComp[2] * maxValues[2] + 0.5f); + } + + pxl |= ((red << offsets[0]) & componentMasks[0]) | + ((green << offsets[1]) & componentMasks[1]) | + ((blue << offsets[2]) & componentMasks[2]); + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (pixel == null) { + ba = new byte[1]; + } else { + ba = (byte[]) pixel; + } + ba[0] = (byte) pxl; + return ba; + + case DataBuffer.TYPE_USHORT: + short sa[]; + if (pixel == null) { + sa = new short[1]; + } else { + sa = (short[]) pixel; + } + sa[0] = (short) pxl; + return sa; + + case DataBuffer.TYPE_INT: + int ia[]; + if (pixel == null) { + ia = new int[1]; + } else { + ia = (int[]) pixel; + } + ia[0] = pxl; + return ia; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } + + @Override + public final ColorModel coerceData(WritableRaster raster, + boolean isAlphaPremultiplied) { + + if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) { + return this; + } + + int minX = raster.getMinX(); + int minY = raster.getMinY(); + int w = raster.getWidth(); + int h = raster.getHeight(); + + int components[] = null; + int transparentComponents[] = new int[numComponents]; + + float alphaFactor = maxValues[numColorComponents]; + + if (isAlphaPremultiplied) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + components = raster.getPixel(x, minY, components); + if (components[numColorComponents] == 0) { + raster.setPixel(x, minY, transparentComponents); + } else { + float alpha = + components[numColorComponents] / + alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + components[n] = + (int) (alpha * components[n] + 0.5f); + } + raster.setPixel(x, minY, components); + } + } + + } + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } else { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + components = raster.getPixel(x, minY, components); + if (components[numColorComponents] != 0) { + float alpha = + alphaFactor / components[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + components[n] = + (int) (alpha * components[n] + 0.5f); + } + raster.setPixel(x, minY, components); + } + } + + } + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + + } + + return new DirectColorModel(cs, pixel_bits, componentMasks[0], + componentMasks[1], componentMasks[2], componentMasks[3], + isAlphaPremultiplied, transferType); + } + + @Override + public String toString() { + // The output format based on 1.5 release behaviour. + // It could be reveled such way: + // BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + // ColorModel cm = bi.getColorModel(); + // System.out.println(cm.toString()); + String str = "DirectColorModel:" + " rmask = " + //$NON-NLS-1$ //$NON-NLS-2$ + Integer.toHexString(componentMasks[0]) + " gmask = " + //$NON-NLS-1$ + Integer.toHexString(componentMasks[1]) + " bmask = " + //$NON-NLS-1$ + Integer.toHexString(componentMasks[2]) + " amask = " + //$NON-NLS-1$ + (!hasAlpha ? "0" : Integer.toHexString(componentMasks[3])); //$NON-NLS-1$ + + return str; + } + + @Override + public final int[] getComponents(Object pixel, int components[], + int offset) { + + if (components == null) { + components = new int[numComponents + offset]; + } + + int intPixel = 0; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) pixel; + intPixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[]) pixel; + intPixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[]) pixel; + intPixel = ia[0]; + break; + + default: + // awt.22D=This transferType ( {0} ) is not supported by this color model + throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ + transferType)); + } + + return getComponents(intPixel, components, offset); + } + + @Override + public int getRed(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[]) inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[]) inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getRed(pixel); + } + + @Override + public int getRGB(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[]) inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[]) inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getRGB(pixel); + } + + @Override + public int getGreen(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[]) inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[]) inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getGreen(pixel); + } + + @Override + public int getBlue(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[]) inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[]) inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getBlue(pixel); + } + + @Override + public int getAlpha(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[]) inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[]) inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getAlpha(pixel); + } + + @Override + public final WritableRaster createCompatibleWritableRaster(int w, int h) { + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + int bandMasks[] = componentMasks.clone(); + + if (pixel_bits > 16) { + return Raster.createPackedRaster(DataBuffer.TYPE_INT, w, h, + bandMasks, null); + } else if (pixel_bits > 8) { + return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, w, h, + bandMasks, null); + } else { + return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, + bandMasks, null); + } + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + SampleModel sm = raster.getSampleModel(); + if (!(sm instanceof SinglePixelPackedSampleModel)) { + return false; + } + + SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm; + + if (sppsm.getNumBands() != numComponents) { + return false; + } + if (raster.getTransferType() != transferType) { + return false; + } + + int maskBands[] = sppsm.getBitMasks(); + return Arrays.equals(maskBands, componentMasks); + } + + @Override + public int getDataElement(int components[], int offset) { + int pixel = 0; + for (int i = 0; i < numComponents; i++) { + pixel |= (components[offset + i] << offsets[i]) & componentMasks[i]; + } + return pixel; + } + + @Override + public final int[] getComponents(int pixel, int components[], int offset) { + if (components == null) { + components = new int[numComponents + offset]; + } + for (int i = 0; i < numComponents; i++) { + components[offset + i] = (pixel & componentMasks[i]) >> offsets[i]; + } + return components; + } + + @Override + public final int getRed(int pixel) { + if (is_sRGB) { + return getComponentFrom_sRGB(pixel, 0); + } + if (is_LINEAR_RGB) { + return getComponentFrom_LINEAR_RGB(pixel, 0); + } + return getComponentFrom_RGB(pixel, 0); + } + + @Override + public final int getRGB(int pixel) { + return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | + (getGreen(pixel) << 8) | getBlue(pixel); + } + + @Override + public final int getGreen(int pixel) { + if (is_sRGB) { + return getComponentFrom_sRGB(pixel, 1); + } + if (is_LINEAR_RGB) { + return getComponentFrom_LINEAR_RGB(pixel, 1); + } + return getComponentFrom_RGB(pixel, 1); + } + + @Override + public final int getBlue(int pixel) { + if (is_sRGB) { + return getComponentFrom_sRGB(pixel, 2); + } + if (is_LINEAR_RGB) { + return getComponentFrom_LINEAR_RGB(pixel, 2); + } + return getComponentFrom_RGB(pixel, 2); + } + + @Override + public final int getAlpha(int pixel) { + if (!hasAlpha) { + return 255; + } + int a = (pixel & componentMasks[3]) >>> offsets[3]; + if (bits[3] == 8) { + return a; + } + return alphaLUT[a] & 0xff; + } + + /** + * Gets the red mask. + * + * @return the red mask + */ + public final int getRedMask() { + return componentMasks[0]; + } + + /** + * Gets the green mask. + * + * @return the green mask + */ + public final int getGreenMask() { + return componentMasks[1]; + } + + /** + * Gets the blue mask. + * + * @return the blue mask + */ + public final int getBlueMask() { + return componentMasks[2]; + } + + /** + * Gets the alpha mask. + * + * @return the alpha mask + */ + public final int getAlphaMask() { + if (hasAlpha) { + return componentMasks[3]; + } + return 0; + } + + /** + * Initialization of Lookup tables. + */ + private void initLUTs() { + is_sRGB = cs.isCS_sRGB(); + is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS); + + if (is_LINEAR_RGB) { + if (maxBitLength > 8) { + LINEAR_RGB_Length = 16; + from_LINEAR_RGB_LUT = + LUTColorConverter.getFrom16lRGBtosRGB_LUT(); + to_LINEAR_16RGB_LUT = + LUTColorConverter.getFromsRGBto16lRGB_LUT(); + } else { + LINEAR_RGB_Length = 8; + from_LINEAR_RGB_LUT = + LUTColorConverter.getFrom8lRGBtosRGB_LUT(); + to_LINEAR_8RGB_LUT = + LUTColorConverter.getFromsRGBto8lRGB_LUT(); + } + fFactor = ((1 << LINEAR_RGB_Length) - 1); + } else { + fFactor = 255.0f; + } + + if (hasAlpha && bits[3] != 8) { + alphaLUT = new byte[maxValues[3] + 1]; + for (int i = 0; i <= maxValues[3]; i++) { + alphaLUT[i] = (byte) (scales[3] * i + 0.5f); + } + + } + + if (!isAlphaPremultiplied) { + colorLUTs = new byte[3][]; + + if (is_sRGB) { + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != 8) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[i]; j++) { + colorLUTs[i][j] = (byte) (scales[i] * j + 0.5f); + } + } + } + } + + if (is_LINEAR_RGB) { + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != LINEAR_RGB_Length) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[0]; j++) { + int idx; + if (LINEAR_RGB_Length == 8) { + idx = (int) (scales[i] * j + 0.5f); + } else { + idx = (int) (scales[i] * j * 257.0f + 0.5f); + } + colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx]; + } + } + } + } + + } + } + + /** + * This method return RGB component value if Color Model has + * sRGB ColorSpace. + * + * @param pixel - INT representation of pixel + * @param idx - index of pixel component + * + * @return - value of the pixel component scaled fro 0 to 255 + */ + private int getComponentFrom_sRGB(int pixel, int idx) { + int comp = (pixel & componentMasks[idx]) >> offsets[idx]; + if (isAlphaPremultiplied) { + int alpha = (pixel & componentMasks[3]) >>> offsets[3]; + comp = alpha == 0 ? 0 : (int) (scales[idx] * comp * 255.0f / + (scales[3] * alpha) + 0.5f); + } else if (bits[idx] != 8) { + comp = colorLUTs[idx][comp] & 0xff; + } + return comp; + } + + /** + * This method return RGB component value if Color Model has + * Linear RGB ColorSpace. + * + * @param pixel - INT representation of pixel + * @param idx - index of pixel component + * + * @return - value of the pixel component scaled fro 0 to 255 + */ + private int getComponentFrom_LINEAR_RGB(int pixel, int idx) { + int comp = (pixel & componentMasks[idx]) >> offsets[idx]; + if (isAlphaPremultiplied) { + float factor = ((1 << LINEAR_RGB_Length) - 1); + int alpha = (pixel & componentMasks[3]) >> offsets[3]; + comp = alpha == 0 ? 0 : (int) (scales[idx] * comp * factor / + (scales[3] * alpha) + 0.5f); + } else if (bits[idx] != LINEAR_RGB_Length) { + comp = colorLUTs[idx][comp] & 0xff; + } else { + comp = from_LINEAR_RGB_LUT[comp] & 0xff; + } + return comp; + } + + /** + * This method return RGB component value if Color Model has + * arbitrary RGB ColorSapce. + * + * @param pixel - INT representation of pixel + * @param idx - index of pixel component + * + * @return - value of the pixel component scaled fro 0 to 255 + */ + private int getComponentFrom_RGB(int pixel, int idx) { + int components[] = getComponents(pixel, null, 0); + float[] normComponents = getNormalizedComponents(components, 0, null, 0); + float[] sRGBcomponents = cs.toRGB(normComponents); + return (int) (sRGBcomponents[idx] * 255.0f + 0.5f); + } + +} + diff --git a/awt/java/awt/image/FilteredImageSource.java b/awt/java/awt/image/FilteredImageSource.java new file mode 100644 index 0000000..6a41fa7 --- /dev/null +++ b/awt/java/awt/image/FilteredImageSource.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.util.Hashtable; + + +/** + * The FilteredImageSource class is used for producing image data for a new + * filtered version of the original image using the specified filter object. + */ +public class FilteredImageSource implements ImageProducer { + + /** The source. */ + private final ImageProducer source; + + /** The filter. */ + private final ImageFilter filter; + + /** The cons table. */ + private final Hashtable consTable = new Hashtable(); + + /** + * Instantiates a new FilteredImageSource object with + * the specified ImageProducer and the ImageFilter objects. + * + * @param orig the specified ImageProducer. + * @param imgf the specified ImageFilter. + */ + public FilteredImageSource(ImageProducer orig, ImageFilter imgf) { + source = orig; + filter = imgf; + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + if(ic != null) { + return consTable.containsKey(ic); + } + return false; + } + + public void startProduction(ImageConsumer ic) { + addConsumer(ic); + ImageConsumer fic = consTable.get(ic); + source.startProduction(fic); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) { + if(ic != null && isConsumer(ic)){ + ImageFilter fic = (ImageFilter) consTable.get(ic); + fic.resendTopDownLeftRight(source); + } + } + + public synchronized void removeConsumer(ImageConsumer ic) { + if(ic != null && isConsumer(ic)){ + ImageConsumer fic = consTable.get(ic); + source.removeConsumer(fic); + consTable.remove(ic); + } + } + + public synchronized void addConsumer(ImageConsumer ic) { + if(ic != null && !isConsumer(ic)){ + ImageConsumer fic = filter.getFilterInstance(ic); + source.addConsumer(fic); + consTable.put(ic, fic); + } + } +} diff --git a/awt/java/awt/image/ImageConsumer.java b/awt/java/awt/image/ImageConsumer.java new file mode 100644 index 0000000..2eba290 --- /dev/null +++ b/awt/java/awt/image/ImageConsumer.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.util.Hashtable; + +/** + * The ImageConsumer interface provides the data about the image + * and about how its data is delivered. A ImageProducer provides + * all of the information about the image using + * the methods defined in this interface. + */ +public interface ImageConsumer { + + /** + * The Constant RANDOMPIXELORDER indicates that the pixels are + * delivered in a random order. + */ + public static final int RANDOMPIXELORDER = 1; + + /** + * The Constant TOPDOWNLEFTRIGHT indicates that the pixels are + * delivered in top-down, left-to-right order. + */ + public static final int TOPDOWNLEFTRIGHT = 2; + + /** + * The Constant COMPLETESCANLINES indicates that the pixels are + * delivered in complete scanline. + */ + public static final int COMPLETESCANLINES = 4; + + /** + * The Constant SINGLEPASS indicates that pixels are delivered + * in a single pass. + */ + public static final int SINGLEPASS = 8; + + /** + * The Constant SINGLEFRAME indicates that image consists of + * single frame. + */ + public static final int SINGLEFRAME = 16; + + /** + * The Constant IMAGEERROR indicates an image error during image producing. + */ + public static final int IMAGEERROR = 1; + + /** + * The Constant SINGLEFRAMEDONE indicates that only one of the + * image's frames is completed. + */ + public static final int SINGLEFRAMEDONE = 2; + + /** + * The Constant STATICIMAGEDONE indicates that the image is completed. + */ + public static final int STATICIMAGEDONE = 3; + + /** + * The Constant IMAGEABORTED indicates that the image producing + * process is aborted. + */ + public static final int IMAGEABORTED = 4; + + /** + * Sets the properties for the image associated with this ImageConsumer. + * + * @param props the properties for the image associated with + * this ImageConsumer. + */ + public void setProperties(Hashtable props); + + /** + * Sets the ColorModel object. + * + * @param model the new ColorModel. + */ + public void setColorModel(ColorModel model); + + /** + * Sets the pixels for the specified rectangular area of the image. + * + * @param x the X coordinate of rectangular area. + * @param y the Y coordinate of rectangular area. + * @param w the width of rectangular area. + * @param h the height of rectangular area. + * @param model the specified ColorModel to be used for pixels + * converting. + * @param pixels the array of pixels. + * @param off the offset of pixels array. + * @param scansize the distance from the one row of pixels + * to the next row in the specified array. + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, + int[] pixels, int off, int scansize); + + /** + * Sets the pixels for the specified rectangular area of the image. + * + * @param x the X coordinate of rectangular area. + * @param y the Y coordinate of rectangular area. + * @param w the width of rectangular area. + * @param h the height of rectangular area. + * @param model the specified ColorModel to be used for pixels + * converting. + * @param pixels the array of pixels. + * @param off the offset of pixels array. + * @param scansize the distance from the one row of pixels + * to the next row in the specified array. + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, + byte[] pixels, int off, int scansize); + + /** + * Sets the dimensions of a source image. + * + * @param width the width of the image. + * @param height the height of the image. + */ + public void setDimensions(int width, int height); + + /** + * Sets the hint flags of pixels order, which is used by + * the ImageConsumer for obtaining pixels from the ImageProducer + * for which this ImageConsumer is added. + * + * @param hintflags the mask of hint flags. + */ + public void setHints(int hintflags); + + /** + * THis method is called in the one of the following cases: + *

    + *
  • The ImageProducer (for which this ImageConsumer is added) + * has been delivered all pixels of the source image.
  • + *
  • A one frame of an animation has been completed.
  • + *
  • An error while loading or producing of the image has occured. + *
+ * + * @param status the status of image producing. + */ + public void imageComplete(int status); + +} + diff --git a/awt/java/awt/image/ImageFilter.java b/awt/java/awt/image/ImageFilter.java new file mode 100644 index 0000000..e386d65 --- /dev/null +++ b/awt/java/awt/image/ImageFilter.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.util.Hashtable; + +/** + * The ImageFilter class provides a filter for delivering image data + * from an ImageProducer to an ImageConsumer. + */ +public class ImageFilter implements ImageConsumer, Cloneable { + + /** The consumer. */ + protected ImageConsumer consumer; + + /** + * Instantiates a new ImageFilter. + */ + public ImageFilter() { + super(); + } + + /** + * Gets an instance of an ImageFilter object which performs + * the filtering for the specified ImageConsumer. + * + * @param ic the specified ImageConsumer. + * + * @return an ImageFilter used to perform the filtering for + * the specified ImageConsumer. + */ + public ImageFilter getFilterInstance(ImageConsumer ic) { + ImageFilter filter = (ImageFilter) clone(); + filter.consumer = ic; + return filter; + } + + @SuppressWarnings("unchecked") + public void setProperties(Hashtable props) { + Hashtable fprops; + if (props == null) { + fprops = new Hashtable(); + } else { + fprops = (Hashtable) props.clone(); + } + String propName = "Filters"; //$NON-NLS-1$ + String prop = "Null filter"; //$NON-NLS-1$ + Object o = fprops.get(propName); + if (o != null) { + if (o instanceof String) { + prop = (String) o + "; " + prop; //$NON-NLS-1$ + } else { + prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } + } + fprops.put(propName, prop); + consumer.setProperties(fprops); + } + + /** + * Returns a copy of this ImageFilter. + * + * @return a copy of this ImageFilter. + */ + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + + /** + * Responds to a request for a Top-Down-Left-Right ordered + * resend of the pixel data from an ImageConsumer. + * + * @param ip the ImageProducer that provides this instance of + * the filter. + */ + public void resendTopDownLeftRight(ImageProducer ip) { + ip.requestTopDownLeftRightResend(this); + } + + public void setColorModel(ColorModel model) { + consumer.setColorModel(model); + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + consumer.setPixels(x, y, w, h, model, pixels, off, scansize); + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + consumer.setPixels(x, y, w, h, model, pixels, off, scansize); + } + + public void setDimensions(int width, int height) { + consumer.setDimensions(width, height); + } + + public void setHints(int hints) { + consumer.setHints(hints); + } + + public void imageComplete(int status) { + consumer.imageComplete(status); + } + +} diff --git a/awt/java/awt/image/ImageObserver.java b/awt/java/awt/image/ImageObserver.java new file mode 100644 index 0000000..418bd07 --- /dev/null +++ b/awt/java/awt/image/ImageObserver.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Image; + +/** + * the ImageObserver interface is an asynchronous update interface + * for receiving notifications about Image construction status. + */ +public interface ImageObserver { + + /** + * The Constant WIDTH indicates that the width of the image is + * available. + */ + public static final int WIDTH = 1; + + /** + * The Constant HEIGHT indicates that the width of the image is + * available. + */ + public static final int HEIGHT = 2; + + /** + * The Constant PROPERTIES indicates that the properties of the image + * are available. + */ + public static final int PROPERTIES = 4; + + /** + * The Constant SOMEBITS indicates that more bits needed for + * drawing a scaled variation of the image pixels are available. + */ + public static final int SOMEBITS = 8; + + /** + * The Constant FRAMEBITS indicates that complete frame of + * a image which was previously drawn is now available + * for drawing again. + */ + public static final int FRAMEBITS = 16; + + /** + * The Constant ALLBITS indicates that an image which + * was previously drawn is now complete and can be drawn again. + */ + public static final int ALLBITS = 32; + + /** + * The Constant ERROR indicates that error occured. + */ + public static final int ERROR = 64; + + /** + * The Constant ABORT indicates that the image producing is + * aborted. + */ + public static final int ABORT = 128; + + /** + * This method is called when information about an Image + * interface becomes available. This method returns true + * if further updates are needed, false if not. + * + * @param img the image to be observed. + * @param infoflags the bitwise OR combination of information flags: + * ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, + * WIDTH. + * @param x the X coordinate. + * @param y the Y coordinate. + * @param width the width. + * @param height the height. + * + * @return true if further updates are needed, false if not. + */ + public boolean imageUpdate(Image img, int infoflags, int x, int y, + int width, int height); + +} + diff --git a/awt/java/awt/image/ImageProducer.java b/awt/java/awt/image/ImageProducer.java new file mode 100644 index 0000000..557ae08 --- /dev/null +++ b/awt/java/awt/image/ImageProducer.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + + +/** + * The ImageProducer provides an interface for objects which produce + * the image data. ImageProducer is used for reconstructing the + * image. Each image contains an ImageProducer. + */ +public interface ImageProducer { + + /** + * Checks if the specified ImageConsumer is registered with this + * ImageProvider or not. + * + * @param ic the ImageConsumer to be checked. + * + * @return true, if the specified ImageConsumer is registered with this + * ImageProvider, false otherwise. + */ + public boolean isConsumer(ImageConsumer ic); + + /** + * Starts a reconstruction of the image data which will + * be delivered to this consumer. This method addes the + * specified ImageConsumer before reconstructing the image. + * + * @param ic the specified ImageConsumer. + */ + public void startProduction(ImageConsumer ic); + + /** + * Requests the ImageProducer to resend the image data + * in ImageConsumer.TOPDOWNLEFTRIGHT order. + * + * @param ic the specified ImageConsumer. + */ + public void requestTopDownLeftRightResend(ImageConsumer ic); + + /** + * Deregisters the specified ImageConsumer. + * + * @param ic the specified ImageConsumer. + */ + public void removeConsumer(ImageConsumer ic); + + /** + * Adds the specified ImageConsumer object to this ImageProducer. + * + * @param ic the specified ImageConsumer. + */ + public void addConsumer(ImageConsumer ic); + +} + diff --git a/awt/java/awt/image/ImagingOpException.java b/awt/java/awt/image/ImagingOpException.java new file mode 100644 index 0000000..ebcaba4 --- /dev/null +++ b/awt/java/awt/image/ImagingOpException.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 5, 2005 + */ + +package java.awt.image; + +/** + * The ImagingOpException class provides error notification when + * the BufferedImageOp or RasterOp filter methods can not perform + * the desired filter operation. + */ +public class ImagingOpException extends RuntimeException { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 8026288481846276658L; + + /** + * Instantiates a new ImagingOpException with a detail message. + * + * @param s the detail message. + */ + public ImagingOpException(String s) { + super(s); + } +} diff --git a/awt/java/awt/image/IndexColorModel.java b/awt/java/awt/image/IndexColorModel.java new file mode 100644 index 0000000..a7043f4 --- /dev/null +++ b/awt/java/awt/image/IndexColorModel.java @@ -0,0 +1,1020 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.math.BigInteger; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class IndexColorModel represents a color model in which the + * color values of the pixels are read from a palette. + */ +public class IndexColorModel extends ColorModel { + + /** The color map. */ + private int colorMap[]; // Color Map + + /** The map size. */ + private int mapSize; // Color Map size + + /** The transparent index. */ + private int transparentIndex; // Index of fully transparent pixel + + /** The gray palette. */ + private boolean grayPalette; // Color Model has Color Map with Gray Pallete + + /** The valid bits. */ + private BigInteger validBits; // Specify valid Color Map values + + /** The Constant CACHESIZE. */ + private static final int CACHESIZE = 20; // Cache size. Cache used for + // improving performace of selection + // nearest color in Color Map + + /** The cachetable. */ + private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table - used for + // storing RGB values and that appropriate indices + // in the Color Map + + + /** The next insert idx. */ + private int nextInsertIdx = 0; // Next index for insertion into Cache table + + /** The total inserted. */ + private int totalInserted = 0; // Number of inserted values into Cache table + + /** + * Instantiates a new index color model. + * + * @param bits the array of component masks + * @param size the size of the color map + * @param cmap the array that gives the color mapping + * @param start the start index of the color mapping data within the cmap array + * @param transferType the transfer type (primitive java type + * to use for the components) + * @param validBits a list of which bits represent valid colormap + * values, or null if all are valid + * + * @throws IllegalArgumentException if the size of the color map is + * less than one + */ + public IndexColorModel(int bits, int size, int cmap[], int start, + int transferType, BigInteger validBits) { + + super(bits, IndexColorModel.createBits(true), + ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, + Transparency.OPAQUE, validateTransferType(transferType)); + + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + transparentIndex = -1; + + if (validBits != null) { + for (int i = 0; i < mapSize; i++) { + if (!validBits.testBit(i)) { + this.validBits = validBits; + } + break; + } + } + + transparency = Transparency.OPAQUE; + int alphaMask = 0xff000000; + int alpha = 0; + + for (int i = 0; i < mapSize; i++, start++) { + colorMap[i] = cmap[start]; + alpha = cmap[start] & alphaMask; + + if (alpha == alphaMask) { + continue; + } + if (alpha == 0) { + if (transparentIndex < 0) { + transparentIndex = i; + } + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + } else if (alpha != alphaMask && + transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + + } + checkPalette(); + + } + + /** + * Instantiates a new index color model. + * + * @param bits the array of component masks + * @param size the size of the color map + * @param cmap the array that gives the color mapping + * @param start the start index of the color mapping data within the cmap array + * @param hasalpha whether this color model uses alpha + * @param trans the transparency supported, @see java.awt.Transparency + * @param transferType the transfer type (primitive java type + * to use for the components) + * + * @throws IllegalArgumentException if the size of the color map is + * less than one + */ + public IndexColorModel(int bits, int size, int cmap[], int start, + boolean hasalpha, int trans, int transferType) { + + super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + (hasalpha || (trans >= 0)), false, Transparency.OPAQUE, + validateTransferType(transferType)); + + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + if (trans >= 0 && trans < mapSize) { + transparentIndex = trans; + transparency = Transparency.BITMASK; + } else { + transparentIndex = -1; + transparency = Transparency.OPAQUE; + } + + int alphaMask = 0xff000000; + int alpha = 0; + + for (int i = 0; i < mapSize; i++, start++) { + if (transparentIndex == i) { + colorMap[i] = cmap[start] & 0x00ffffff; + continue; + } + if (hasalpha) { + alpha = cmap[start] & alphaMask; + colorMap[i] = cmap[start]; + + if (alpha == alphaMask) { + continue; + } + if (alpha == 0) { + if (trans < 0) { + trans = i; + } + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + } else if (alpha != 0 + && transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + } else { + colorMap[i] = alphaMask | cmap[start]; + } + } + checkPalette(); + + } + + /** + * Instantiates a new index color model by building the color map + * from arrays of red, green, blue, and alpha values. + * + * @param bits the array of component masks + * @param size the size of the color map + * @param r the array giving the red components of the entries in the color map + * @param g the array giving the green components of the entries in the color map + * @param b the array giving the blue components of the entries in the color map + * @param a the array giving the alpha components of the entries in the color map + * + * @throws IllegalArgumentException if the size of the color map is + * less than one + * @throws ArrayIndexOutOfBoundsException if the size of one of the + * component arrays is less than the size of the color map + */ + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], + byte a[]) { + + super(bits, IndexColorModel.createBits(true), + ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, + Transparency.OPAQUE, + validateTransferType(ColorModel.getTransferType(bits))); + + createColorMap(size, r, g, b, a, -1); + checkPalette(); + } + + /** + * Instantiates a new index color model by building the color map + * from arrays of red, green, and blue values. + * + * @param bits the array of component masks + * @param size the size of the color map + * @param r the array giving the red components of the entries in the color map + * @param g the array giving the green components of the entries in the color map + * @param b the array giving the blue components of the entries in the color map + * @param trans the transparency supported, @see java.awt.Transparency + * + * @throws IllegalArgumentException if the size of the color map is + * less than one + * @throws ArrayIndexOutOfBoundsException if the size of one of the + * component arrays is less than the size of the color map + */ + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], + int trans) { + + super(bits, IndexColorModel.createBits((trans >= 0)), + ColorSpace.getInstance(ColorSpace.CS_sRGB), (trans >= 0), false, + Transparency.OPAQUE, + validateTransferType(ColorModel.getTransferType(bits))); + + createColorMap(size, r, g, b, null, trans); + checkPalette(); + } + + /** + * Instantiates a new index color model by building the color map + * from arrays of red, green, and blue values. + * + * @param bits the array of component masks + * @param size the size of the color map + * @param r the array giving the red components of the entries in the color map + * @param g the array giving the green components of the entries in the color map + * @param b the array giving the blue components of the entries in the color map + * + * @throws IllegalArgumentException if the size of the color map is + * less than one + * @throws ArrayIndexOutOfBoundsException if the size of one of the + * component arrays is less than the size of the color map + */ + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[]) { + super(bits, IndexColorModel.createBits(false), + ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false, + Transparency.OPAQUE, + validateTransferType(ColorModel.getTransferType(bits))); + + createColorMap(size, r, g, b, null, -1); + checkPalette(); + } + + /** + * Instantiates a new index color model. + * + * @param bits the array of component masks + * @param size the size of the color map + * @param cmap the array that gives the color mapping + * @param start the start index of the color mapping data within the cmap array + * @param hasalpha whether this color model uses alpha + * @param trans the transparency supported, @see java.awt.Transparency + * + * @throws IllegalArgumentException if the size of the color map is + * less than one + */ + public IndexColorModel(int bits, int size, byte cmap[], int start, + boolean hasalpha, int trans) { + + super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + (hasalpha || (trans >= 0)), false, Transparency.OPAQUE, + validateTransferType(ColorModel.getTransferType(bits))); + + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + transparentIndex = -1; + + transparency = Transparency.OPAQUE; + int alpha = 0xff000000; + + for (int i = 0; i < mapSize; i++) { + colorMap[i] = (cmap[start++] & 0xff) << 16 | + (cmap[start++] & 0xff) << 8 | (cmap[start++] & 0xff); + if (trans == i) { + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + if(hasalpha) { + start++; + } + continue; + } + if (hasalpha) { + alpha = cmap[start++] & 0xff; + if (alpha == 0) { + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + if (trans < 0) { + trans = i; + } + } + } else { + if (alpha != 0xff && + transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + } + alpha <<= 24; + } + colorMap[i] |= alpha; + } + + if (trans >= 0 && trans < mapSize) { + transparentIndex = trans; + } + checkPalette(); + + } + + /** + * Instantiates a new index color model. + * + * @param bits the array of component masks + * @param size the size of the color map + * @param cmap the array that gives the color mapping + * @param start the start index of the color mapping data within the cmap array + * @param hasalpha whether this color model uses alpha + * + * @throws IllegalArgumentException if the size of the color map is + * less than one + */ + public IndexColorModel(int bits, int size, byte cmap[], int start, + boolean hasalpha) { + + this(bits, size, cmap, start, hasalpha, -1); + } + + @Override + public Object getDataElements(int[] components, int offset, Object pixel) { + int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 | + components[offset + 2]; + if (hasAlpha) { + rgb |= components[offset + 3] << 24; + } else { + rgb |= 0xff000000; + } + return getDataElements(rgb, pixel); + } + + @Override + public synchronized Object getDataElements(int rgb, Object pixel) { + int red = (rgb >> 16) & 0xff; + int green = (rgb >> 8) & 0xff; + int blue = rgb & 0xff; + int alpha = rgb >>> 24; + int pixIdx = 0; + + for (int i = 0; i < totalInserted; i++) { + int idx = i * 2; + if (rgb == cachetable[idx]) { + return createDataObject(cachetable[idx + 1], pixel); + } + } + + if (!hasAlpha && grayPalette) { + int grey = (red * 77 + green * 150 + blue * 29 + 128) >>> 8; + int minError = 255; + int error = 0; + + for (int i = 0; i < mapSize; i++) { + error = Math.abs((colorMap[i] & 0xff) - grey); + if (error < minError) { + pixIdx = i; + if (error == 0) { + break; + } + minError = error; + } + } + } else if (alpha == 0 && transparentIndex > -1) { + pixIdx = transparentIndex; + } else { + int minAlphaError = 255; + int minError = 195075; // 255^2 + 255^2 + 255^2 + int alphaError; + int error = 0; + + for (int i = 0; i < mapSize; i++) { + int pix = colorMap[i]; + if (rgb == pix) { + pixIdx = i; + break; + } + alphaError = Math.abs(alpha - (pix >>> 24)); + if (alphaError <= minAlphaError) { + minAlphaError = alphaError; + + int buf = ((pix >> 16) & 0xff) - red; + error = buf * buf; + + if (error < minError) { + buf = ((pix >> 8) & 0xff) - green; + error += buf * buf; + + if (error < minError) { + buf = (pix & 0xff) - blue; + error += buf * buf; + + if (error < minError) { + pixIdx = i; + minError = error; + } + } + } + } + } + } + + cachetable[nextInsertIdx] = rgb; + cachetable[nextInsertIdx + 1] = pixIdx; + + nextInsertIdx = (nextInsertIdx + 2) % (CACHESIZE * 2); + if (totalInserted < CACHESIZE) { + totalInserted++; + } + + return createDataObject(pixIdx, pixel); + } + + /** + * Converts an image from indexed to RGB format. + * + * @param raster the raster containing the source image + * @param forceARGB whether to use the default RGB color model + * + * @return the buffered image + * + * @throws IllegalArgumentException if the raster is not compatible with + * this color model + */ + public BufferedImage convertToIntDiscrete(Raster raster, + boolean forceARGB) { + + if (!isCompatibleRaster(raster)) { + // awt.265=The raster argument is not compatible with this IndexColorModel + throw new IllegalArgumentException(Messages.getString("awt.265")); //$NON-NLS-1$ + } + + ColorModel model; + if (forceARGB || transparency == Transparency.TRANSLUCENT) { + model = ColorModel.getRGBdefault(); + } else if (transparency == Transparency.BITMASK) { + model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00, + 0x000000ff, 0x01000000); + } else { + model = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff); + } + + int w = raster.getWidth(); + int h = raster.getHeight(); + + WritableRaster distRaster = model.createCompatibleWritableRaster(w, h); + + int minX = raster.getMinX(); + int minY = raster.getMinY(); + + Object obj = null; + int pixels[] = null; + + for (int i = 0; i < h; i++, minY++) { + obj = raster.getDataElements(minX, minY, w, 1, obj); + if (obj instanceof byte[]) { + byte ba[] = (byte[]) obj; + if (pixels == null) { + pixels = new int[ba.length]; + } + for (int j = 0; j < ba.length; j++) { + pixels[j] = colorMap[ba[j] & 0xff]; + } + } else if (obj instanceof short[]) { + short sa[] = (short[]) obj; + if (pixels == null) { + pixels = new int[sa.length]; + } + for (int j = 0; j < sa.length; j++) { + pixels[j] = colorMap[sa[j] & 0xffff]; + } + } + if (obj instanceof int[]) { + int ia[] = (int[]) obj; + if (pixels == null) { + pixels = new int[ia.length]; + } + for (int j = 0; j < ia.length; j++) { + pixels[j] = colorMap[ia[j]]; + } + } + + distRaster.setDataElements(0, i, w, 1, pixels); + } + + return new BufferedImage(model, distRaster, false, null); + } + + /** + * Gets the valid pixels. + * + * @return the valid pixels + */ + public BigInteger getValidPixels() { + return validBits; + } + + @Override + public String toString() { + // The output format based on 1.5 release behaviour. + // It could be reveled such way: + // BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED); + // ColorModel cm = bi.getColorModel(); + // System.out.println(cm.toString()); + String str = "IndexColorModel: #pixel_bits = " + pixel_bits + //$NON-NLS-1$ + " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$ + " transparency = "; //$NON-NLS-1$ + + if (transparency == Transparency.OPAQUE) { + str = str + "Transparency.OPAQUE"; //$NON-NLS-1$ + } else if (transparency == Transparency.BITMASK) { + str = str + "Transparency.BITMASK"; //$NON-NLS-1$ + } else { + str = str + "Transparency.TRANSLUCENT"; //$NON-NLS-1$ + } + + str = str + " transIndex = " + transparentIndex + " has alpha = " + //$NON-NLS-1$ //$NON-NLS-2$ + hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$ + + return str; + } + + @Override + public int[] getComponents(Object pixel, int components[], int offset) { + int pixIdx = -1; + if (pixel instanceof byte[]) { + byte ba[] = (byte[]) pixel; + pixIdx = ba[0] & 0xff; + } else if (pixel instanceof short[]) { + short sa[] = (short[]) pixel; + pixIdx = sa[0] & 0xffff; + } else if (pixel instanceof int[]) { + int ia[] = (int[]) pixel; + pixIdx = ia[0]; + } else { + // awt.219=This transferType is not supported by this color model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + + return getComponents(pixIdx, components, offset); + } + + @Override + public WritableRaster createCompatibleWritableRaster(int w, int h) { + WritableRaster raster; + if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1, + pixel_bits, null); + } else if (pixel_bits <= 8) { + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, + 1, null); + } else if (pixel_bits <= 16) { + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w, + h, 1, null); + } else { + // awt.266=The number of bits in a pixel is greater than 16 + throw new UnsupportedOperationException(Messages.getString("awt.266")); //$NON-NLS-1$ + } + + return raster; + } + + @Override + public boolean isCompatibleSampleModel(SampleModel sm) { + if (sm == null) { + return false; + } + + if (!(sm instanceof MultiPixelPackedSampleModel) + && !(sm instanceof ComponentSampleModel)) { + return false; + } + + if (sm.getTransferType() != transferType) { + return false; + } + if (sm.getNumBands() != 1) { + return false; + } + + return true; + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { + return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, + pixel_bits); + } + int bandOffsets[] = new int[1]; + bandOffsets[0] = 0; + return new ComponentSampleModel(transferType, w, h, 1, w, + bandOffsets); + + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + int sampleSize = raster.getSampleModel().getSampleSize(0); + return (raster.getTransferType() == transferType && + raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize); + } + + @Override + public int getDataElement(int components[], int offset) { + int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 + | components[offset + 2]; + + if (hasAlpha) { + rgb |= components[offset + 3] << 24; + } else { + rgb |= 0xff000000; + } + + int pixel; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[]) getDataElements(rgb, null); + pixel = ba[0] & 0xff; + break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[]) getDataElements(rgb, null); + pixel = sa[0] & 0xffff; + break; + default: + // awt.267=The transferType is invalid + throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ + } + + return pixel; + } + + /** + * Gets the color map. + * + * @param rgb the destination array where the color map is written + */ + public final void getRGBs(int rgb[]) { + System.arraycopy(colorMap, 0, rgb, 0, mapSize); + } + + /** + * Gets the red component of the color map. + * + * @param r the destination array + */ + public final void getReds(byte r[]) { + for (int i = 0; i < mapSize; i++) { + r[i] = (byte) (colorMap[i] >> 16); + } + } + + /** + * Gets the green component of the color map. + * + * @param g the destination array + */ + public final void getGreens(byte g[]) { + for (int i = 0; i < mapSize; i++) { + g[i] = (byte) (colorMap[i] >> 8); + } + } + + /** + * Gets the blue component of the color map. + * + * @param b the destination array + */ + public final void getBlues(byte b[]) { + for (int i = 0; i < mapSize; i++) { + b[i] = (byte) colorMap[i]; + } + } + + /** + * Gets the alpha component of the color map. + * + * @param a the destination array + */ + public final void getAlphas(byte a[]) { + for (int i = 0; i < mapSize; i++) { + a[i] = (byte) (colorMap[i] >> 24); + } + } + + @Override + public int[] getComponents(int pixel, int components[], int offset) { + if (components == null) { + components = new int[offset + numComponents]; + } + + components[offset + 0] = getRed(pixel); + components[offset + 1] = getGreen(pixel); + components[offset + 2] = getBlue(pixel); + if (hasAlpha && (components.length - offset) > 3) { + components[offset + 3] = getAlpha(pixel); + } + + return components; + } + + /** + * Checks if the specified pixel is valid for this color model. + * + * @param pixel the pixel + * + * @return true, if the pixel is valid + */ + public boolean isValid(int pixel) { + if (validBits == null) { + return (pixel >= 0 && pixel < mapSize); + } + return (pixel < mapSize && validBits.testBit(pixel)); + } + + @Override + public final int getRed(int pixel) { + return (colorMap[pixel] >> 16) & 0xff; + } + + @Override + public final int getRGB(int pixel) { + return colorMap[pixel]; + } + + @Override + public final int getGreen(int pixel) { + return (colorMap[pixel] >> 8) & 0xff; + } + + @Override + public final int getBlue(int pixel) { + return colorMap[pixel] & 0xff; + } + + @Override + public final int getAlpha(int pixel) { + return (colorMap[pixel] >> 24) & 0xff; + } + + @Override + public int[] getComponentSize() { + return bits.clone(); + } + + /** + * Checks if this color model validates pixels. + * + * @return true, if all pixels are valid, otherwise false + */ + public boolean isValid() { + return (validBits == null); + } + + @Override + public void finalize() { + // TODO: implement + return; + } + + /** + * Gets the index that represents the transparent pixel. + * + * @return the index that represents the transparent pixel + */ + public final int getTransparentPixel() { + return transparentIndex; + } + + @Override + public int getTransparency() { + return transparency; + } + + /** + * Gets the size of the color map. + * + * @return the map size + */ + public final int getMapSize() { + return mapSize; + } + + /** + * Creates the color map. + * + * @param size the size + * @param r the r + * @param g the g + * @param b the b + * @param a the a + * @param trans the trans + */ + private void createColorMap(int size, byte r[], byte g[], byte b[], + byte a[], int trans) { + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + if (trans >= 0 && trans < mapSize) { + transparency = Transparency.BITMASK; + transparentIndex = trans; + } else { + transparency = Transparency.OPAQUE; + transparentIndex = -1; + } + int alpha = 0; + + for (int i = 0; i < mapSize; i++) { + colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) | + (b[i] & 0xff); + + if (trans == i) { + continue; + } + + if (a == null) { + colorMap[i] |= 0xff000000; + } else { + alpha = a[i] & 0xff; + if (alpha == 0xff) { + colorMap[i] |= 0xff000000; + } else if (alpha == 0) { + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + if (transparentIndex < 0) { + transparentIndex = i; + } + } else { + colorMap[i] |= (a[i] & 0xff) << 24; + if (transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + } + } + + } + + } + + /** + * This method checking, if Color Map has Gray Palette. + */ + private void checkPalette() { + grayPalette = false; + if (transparency > Transparency.OPAQUE) { + return; + } + int rgb = 0; + + for (int i = 0; i < mapSize; i++) { + rgb = colorMap[i]; + if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) || + ((rgb >> 8) & 0xff) != (rgb & 0xff)) { + return; + } + } + grayPalette = true; + } + + /** + * Construction an array pixel representation. + * + * @param colorMapIdx - index into Color Map + * @param pixel - pixel + * + * @return - an array pixel representation + */ + private Object createDataObject(int colorMapIdx, Object pixel) { + if (pixel == null) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte[] ba = new byte[1]; + ba[0] = (byte) colorMapIdx; + pixel = ba; + break; + case DataBuffer.TYPE_USHORT: + short[] sa = new short[1]; + sa[0] = (short) colorMapIdx; + pixel = sa; + break; + default: + // awt.267=The transferType is invalid + throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ + } + } else if (pixel instanceof byte[] + && transferType == DataBuffer.TYPE_BYTE) { + byte ba[] = (byte[]) pixel; + ba[0] = (byte) colorMapIdx; + pixel = ba; + } else if (pixel instanceof short[]&& + transferType == DataBuffer.TYPE_USHORT) { + short[] sa = (short[]) pixel; + sa[0] = (short) colorMapIdx; + pixel = sa; + } else if (pixel instanceof int[]) { + int ia[] = (int[]) pixel; + ia[0] = colorMapIdx; + pixel = ia; + } else { + // awt.268=The pixel is not a primitive array of type transferType + throw new ClassCastException(Messages.getString("awt.268")); //$NON-NLS-1$ + } + return pixel; + } + + /** + * Creates the bits. + * + * @param hasAlpha the has alpha + * + * @return the int[] + */ + private static int[] createBits(boolean hasAlpha) { + + int numChannels; + if (hasAlpha) { + numChannels = 4; + } else { + numChannels = 3; + } + + int bits[] = new int[numChannels]; + for (int i = 0; i < numChannels; i++) { + bits[i] = 8; + } + + return bits; + + } + + /** + * Validate transfer type. + * + * @param transferType the transfer type + * + * @return the int + */ + private static int validateTransferType(int transferType) { + if (transferType != DataBuffer.TYPE_BYTE && + transferType != DataBuffer.TYPE_USHORT) { + // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT + throw new IllegalArgumentException(Messages.getString("awt.269")); //$NON-NLS-1$ + } + return transferType; + } + + /** + * Checks if is gray pallete. + * + * @return true, if is gray pallete + */ + boolean isGrayPallete(){ + return grayPalette; + } + +} + + diff --git a/awt/java/awt/image/Kernel.java b/awt/java/awt/image/Kernel.java new file mode 100644 index 0000000..c6f00e2 --- /dev/null +++ b/awt/java/awt/image/Kernel.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Sep 28, 2005 + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Kernel class provides a matrix. This matrix is stored as a float array + * which describes how a specified pixel affects the value calculated for + * the pixel's position in the output image of a filtering operation. + * The X, Y origins indicate the kernel matrix element which corresponds to + * the pixel position for which an output value is being calculated. + */ +public class Kernel implements Cloneable { + + /** The x origin. */ + private final int xOrigin; + + /** The y origin. */ + private final int yOrigin; + + /** The width. */ + private int width; + + /** The height. */ + private int height; + + /** The data. */ + float data[]; + + /** + * Instantiates a new Kernel with the specified float array. + * The width*height elements of the data array are copied. + * + * @param width the width of the Kernel. + * @param height the height of the Kernel. + * @param data the data of Kernel. + */ + public Kernel(int width, int height, float[] data) { + int dataLength = width*height; + if (data.length < dataLength) { + // awt.22B=Length of data should not be less than width*height + throw new IllegalArgumentException(Messages.getString("awt.22B")); //$NON-NLS-1$ + } + + this.width = width; + this.height = height; + + this.data = new float[dataLength]; + System.arraycopy(data, 0, this.data, 0, dataLength); + + xOrigin = (width-1)/2; + yOrigin = (height-1)/2; + } + + /** + * Gets the width of this Kernel. + * + * @return the width of this Kernel. + */ + public final int getWidth() { + return width; + } + + /** + * Gets the height of this Kernel. + * + * @return the height of this Kernel. + */ + public final int getHeight() { + return height; + } + + /** + * Gets the float data array of this Kernel. + * + * @param data the float array where the resulted data will be stored. + * + * @return the float data array of this Kernel. + */ + public final float[] getKernelData(float[] data) { + if (data == null) { + data = new float[this.data.length]; + } + System.arraycopy(this.data, 0, data, 0, this.data.length); + + return data; + } + + /** + * Gets the X origin of this Kernel. + * + * @return the X origin of this Kernel. + */ + public final int getXOrigin() { + return xOrigin; + } + + /** + * Gets the Y origin of this Kernel. + * + * @return the Y origin of this Kernel. + */ + public final int getYOrigin() { + return yOrigin; + } + + /** + * Returns a copy of this Kernel object. + * + * @return the copy of this Kernel object. + */ + @Override + public Object clone() { + return new Kernel(width, height, data); + } +} diff --git a/awt/java/awt/image/LookupOp.java b/awt/java/awt/image/LookupOp.java new file mode 100644 index 0000000..f9bd2c7 --- /dev/null +++ b/awt/java/awt/image/LookupOp.java @@ -0,0 +1,647 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + +import java.awt.*; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Point2D; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The LookupOp class perfoms a lookup operation which transforms a + * source image by filtering each band using a table of data. + * The table may contain a single array or it may contain a + * different data array for each band of the image. + */ +public class LookupOp implements BufferedImageOp, RasterOp { + + /** The lut. */ + private final LookupTable lut; + + /** The hints. */ + private RenderingHints hints; + + // TODO remove when this field is used + /** The can use ipp. */ + @SuppressWarnings("unused") + private final boolean canUseIpp; + + // We don't create levels/values when it is possible to reuse old + /** The cached levels. */ + private int cachedLevels[]; + + /** The cached values. */ + private int cachedValues[]; + // Number of channels for which cache is valid. + // If negative number of channels is same as positive but skipAlpha was specified + /** The valid for channels. */ + private int validForChannels; + + /** The level initializer. */ + static int levelInitializer[] = new int[0x10000]; + + static { + // TODO + // System.loadLibrary("imageops"); + + for (int i=1; i<=0x10000; i++) { + levelInitializer[i-1] = i; + } + } + + /** + * Instantiates a new LookupOp object from the specified + * LookupTable object and a RenderingHints object. + * + * @param lookup the specified LookupTable object. + * @param hints the RenderingHints object or null. + */ + public LookupOp(LookupTable lookup, RenderingHints hints) { + if (lookup == null){ + throw new NullPointerException(Messages.getString("awt.01", "lookup")); //$NON-NLS-1$ //$NON-NLS-2$ + } + lut = lookup; + this.hints = hints; + canUseIpp = lut instanceof ByteLookupTable || lut instanceof ShortLookupTable; + } + + /** + * Gets the LookupTable of the specified Object. + * + * @return the LookupTable of the specified Object. + */ + public final LookupTable getTable() { + return lut; + } + + public final RenderingHints getRenderingHints() { + return hints; + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt == null) { + dstPt = new Point2D.Float(); + } + + dstPt.setLocation(srcPt); + return dstPt; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { + if (dstCM == null) { + dstCM = src.getColorModel(); + + // Sync transfer type with LUT for component color model + if (dstCM instanceof ComponentColorModel) { + int transferType = dstCM.getTransferType(); + if (lut instanceof ByteLookupTable) { + transferType = DataBuffer.TYPE_BYTE; + } else if (lut instanceof ShortLookupTable) { + transferType = DataBuffer.TYPE_SHORT; + } + + dstCM = new ComponentColorModel( + dstCM.cs, + dstCM.hasAlpha(), + dstCM.isAlphaPremultiplied, + dstCM.transparency, + transferType + ); + } + } + + WritableRaster r = + dstCM.isCompatibleSampleModel(src.getSampleModel()) ? + src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : + dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage( + dstCM, + r, + dstCM.isAlphaPremultiplied(), + null + ); + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else { + if (src.getNumBands() != dst.getNumBands()) { + throw new IllegalArgumentException(Messages.getString("awt.237")); //$NON-NLS-1$ } + } + if (src.getWidth() != dst.getWidth()){ + throw new IllegalArgumentException(Messages.getString("awt.28F")); //$NON-NLS-1$ } + } + if (src.getHeight() != dst.getHeight()){ + throw new IllegalArgumentException(Messages.getString("awt.290")); //$NON-NLS-1$ } + } + } + + if (lut.getNumComponents() != 1 && lut.getNumComponents() != src.getNumBands()) { + // awt.238=The number of arrays in the LookupTable does not meet the restrictions + throw new IllegalArgumentException(Messages.getString("awt.238")); //$NON-NLS-1$ + } + + // TODO + // if (!canUseIpp || ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0) + if (slowFilter(src, dst, false) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + ColorModel srcCM = src.getColorModel(); + + if (srcCM instanceof IndexColorModel) { + // awt.220=Source should not have IndexColorModel + throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$ + } + + // Check if the number of scaling factors matches the number of bands + int nComponents = srcCM.getNumComponents(); + int nLUTComponents = lut.getNumComponents(); + boolean skipAlpha; + if (srcCM.hasAlpha()) { + if (nLUTComponents == 1 || nLUTComponents == nComponents-1) { + skipAlpha = true; + } else if (nLUTComponents == nComponents) { + skipAlpha = false; + } else { + // awt.229=Number of components in the LUT does not match the number of bands + throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$ + } + } else if (nLUTComponents == 1 || nLUTComponents == nComponents) { + skipAlpha = false; + } else { + // awt.229=Number of components in the LUT does not match the number of bands + throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$ + } + + BufferedImage finalDst = null; + if (dst == null) { + finalDst = dst; + dst = createCompatibleDestImage(src, null); + } else { + if (src.getWidth() != dst.getWidth()){ + throw new IllegalArgumentException(Messages.getString("awt.291")); //$NON-NLS-1$ + } + + if (src.getHeight() != dst.getHeight()){ + throw new IllegalArgumentException(Messages.getString("awt.292")); //$NON-NLS-1$ + } + + if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and + // BufferedImage.TYPE_INT_ARGB as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src + .getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst + .getType() == BufferedImage.TYPE_INT_ARGB))) { + finalDst = dst; + dst = createCompatibleDestImage(src, null); + } + } + } + + // TODO + //if (!canUseIpp || ippFilter(src.getRaster(), dst.getRaster(), src.getType(), skipAlpha) != 0) + if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return dst; + } + + /** + * Slow filter. + * + * @param src the src + * @param dst the dst + * @param skipAlpha the skip alpha + * + * @return the int + */ + private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) { + int minSrcX = src.getMinX(); + int minDstX = dst.getMinX(); + int minSrcY = src.getMinY(); + int minDstY = dst.getMinY(); + + int skippingChannels = skipAlpha ? 1 : 0; + int numBands2Process = src.getNumBands() - skippingChannels; + + int numBands = src.getNumBands(); + int srcHeight = src.getHeight(); + int srcWidth = src.getWidth(); + + int[] pixels = null; + int offset = lut.getOffset(); + + if (lut instanceof ByteLookupTable){ + byte[][] byteData = ((ByteLookupTable)lut).getTable(); + pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels); + + if (lut.getNumComponents() != 1){ + for (int i=0; i < pixels.length; i+= numBands){ + for (int b = 0; b < numBands2Process; b++){ + pixels[i+b] = byteData[b][pixels[i+b]-offset] & 0xFF; + } + } + } else { + for (int i=0; i < pixels.length; i+= numBands){ + for (int b = 0; b < numBands2Process; b++){ + pixels[i+b] = byteData[0][pixels[i+b]-offset] & 0xFF; + } + } + } + + dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels); + } else if (lut instanceof ShortLookupTable){ + short[][] shortData = ((ShortLookupTable)lut).getTable(); + pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels); + + if (lut.getNumComponents() != 1){ + for (int i=0; i < pixels.length; i+= numBands){ + for (int b = 0; b < numBands2Process; b++){ + pixels[i+b] = shortData[b][pixels[i+b]-offset] & 0xFFFF; + } + } + } else { + for (int i=0; i < pixels.length; i+= numBands){ + for (int b = 0; b < numBands2Process; b++){ + pixels[i+b] = shortData[0][pixels[i+b]-offset] & 0xFFFF; + } + } + } + + dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels); + } else { + int pixel[] = new int[src.getNumBands()]; + int maxY = minSrcY + srcHeight; + int maxX = minSrcX + srcWidth; + for (int srcY=minSrcY, dstY = minDstY; srcY < maxY; srcY++, dstY++){ + for (int srcX=minSrcX, dstX = minDstX; srcX < maxX; srcX++, dstX++){ + src.getPixel(srcX, srcY, pixel); + lut.lookupPixel(pixel, pixel); + dst.setPixel(dstX, dstY, pixel); + } + } + } + + return 0; + } + + /** + * Creates the byte levels. + * + * @param channels the channels + * @param skipAlpha the skip alpha + * @param levels the levels + * @param values the values + * @param channelsOrder the channels order + */ + private final void createByteLevels( + int channels, boolean skipAlpha, + int levels[], int values[], int channelsOrder[] + ) { + byte data[][] = ((ByteLookupTable)lut).getTable(); + int nLevels = data[0].length; + int offset = lut.getOffset(); + + // Use one data array for all channels or use several data arrays + int dataIncrement = data.length > 1 ? 1 : 0; + + for (int ch = 0, dataIdx = 0; ch= data.length)) { + continue; + } + + System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels); + for (int from=0, to=channelBase; from 1 ? 1 : 0; + + for (int ch = 0, dataIdx = 0; ch= data.length)) { + continue; + } + + int channelBase = nLevels * channelOffset; + System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels); + for (int from=0, to=channelBase; from properties; + + /** The consumers. */ + Vector consumers; + + /** The animated. */ + boolean animated; + + /** The fullbuffers. */ + boolean fullbuffers; + + /** The data type. */ + int dataType; + + /** The Constant DATA_TYPE_BYTE. */ + static final int DATA_TYPE_BYTE = 0; + + /** The Constant DATA_TYPE_INT. */ + static final int DATA_TYPE_INT = 1; + + /** + * Instantiates a new MemoryImageSource with the specified + * parameters. + * + * @param w the width of the rectangular area of pixels. + * @param h the height of the rectangular area of pixels. + * @param cm the specified ColorModel. + * @param pix the pixel array. + * @param off the offset in the pixel array. + * @param scan the distance from one pixel's row to the next + * in the pixel array. + * @param props the set of properties to be used for image + * processing. + */ + public MemoryImageSource(int w, int h, ColorModel cm, int pix[], + int off, int scan, Hashtable props) { + init(w, h, cm, pix, off, scan, props); + } + + /** + * Instantiates a new MemoryImageSource with the specified + * parameters. + * + * @param w the width of the rectangular area of pixels. + * @param h the height of the rectangular area of pixels. + * @param cm the specified ColorModel. + * @param pix the pixel array. + * @param off the offset in the pixel array. + * @param scan the distance from one pixel's row to the next + * in the pixel array. + * @param props the set of properties to be used for image + * processing. + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], + int off, int scan, Hashtable props) { + init(w, h, cm, pix, off, scan, props); + } + + /** + * Instantiates a new MemoryImageSource with the specified + * parameters and default RGB ColorModel. + * + * @param w the width of the rectangular area of pixels. + * @param h the height of the rectangular area of pixels. + * @param pix the pixel array. + * @param off the offset in the pixel array. + * @param scan the distance from one pixel's row to the next + * in the pixel array. + * @param props the set of properties to be used for image + * processing. + */ + public MemoryImageSource(int w, int h, int pix[], int off, int scan, + Hashtable props) { + init(w, h, ColorModel.getRGBdefault(), pix, off, scan, props); + } + + /** + * Instantiates a new MemoryImageSource with the specified + * parameters. + * + * @param w the width of the rectangular area of pixels. + * @param h the height of the rectangular area of pixels. + * @param cm the specified ColorModel. + * @param pix the pixel array. + * @param off the offset in the pixel array. + * @param scan the distance from one pixel's row to the next + * in the pixel array. + */ + public MemoryImageSource(int w, int h, ColorModel cm, int pix[], + int off, int scan) { + init(w, h, cm, pix, off, scan, null); + } + + /** + * Instantiates a new MemoryImageSource with the specified + * parameters. + * + * @param w the width of the rectangular area of pixels. + * @param h the height of the rectangular area of pixels. + * @param cm the specified ColorModel. + * @param pix the pixel array. + * @param off the offset in the pixel array. + * @param scan the distance from one pixel's row to the next + * in the pixel array. + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], + int off, int scan) { + init(w, h, cm, pix, off, scan, null); + } + + /** + * Instantiates a new MemoryImageSource with the specified + * parameters and default RGB ColorModel. + * + * @param w the width of the rectangular area of pixels. + * @param h the height of the rectangular area of pixels. + * @param pix the pixels array. + * @param off the offset in the pixel array. + * @param scan the distance from one pixel's row to the next + * in the pixel array. + */ + public MemoryImageSource(int w, int h, int pix[], int off, int scan) { + init(w, h, ColorModel.getRGBdefault(), pix, off, scan, null); + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + return consumers.contains(ic); + } + + public void startProduction(ImageConsumer ic) { + if(!isConsumer(ic) && ic != null) { + consumers.addElement(ic); + } + try{ + setHeader(ic); + setPixels(ic, 0, 0, width, height); + if(animated){ + ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + }else{ + ic.imageComplete(ImageConsumer.STATICIMAGEDONE); + if(isConsumer(ic)) { + removeConsumer(ic); + } + } + }catch(Exception e){ + if(isConsumer(ic)) { + ic.imageComplete(ImageConsumer.IMAGEERROR); + } + if(isConsumer(ic)) { + removeConsumer(ic); + } + } + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) { + } + + public synchronized void removeConsumer(ImageConsumer ic) { + consumers.removeElement(ic); + } + + public synchronized void addConsumer(ImageConsumer ic) { + if(ic == null || consumers.contains(ic)) { + return; + } + consumers.addElement(ic); + } + + /** + * Replaces the pixel data with a new pixel array for holding + * the pixels for this image. If an animation + * flag is set to true value by the setAnimated() method, + * the new pixels will be immediately delivered to the ImageConsumers. + * + * @param newpix the new pixel array. + * @param newmodel the new ColorModel. + * @param offset the offset in the array. + * @param scansize the distance from one row of pixels to the next row + * in the pixel array + */ + public synchronized void newPixels(int newpix[], ColorModel newmodel, + int offset, int scansize) { + this.dataType = DATA_TYPE_INT; + this.iData = newpix; + this.cm = newmodel; + this.offset = offset; + this.scanline = scansize; + newPixels(); + } + + /** + * Replaces the pixel data with a new pixel array for holding + * the pixels for this image. If an animation + * flag is set to true value by the setAnimated() method, + * the new pixels will be immediately delivered to the ImageConsumers. + * + * @param newpix the new pixel array. + * @param newmodel the new ColorModel. + * @param offset the offset in the array. + * @param scansize the distance from one row of pixels to the next row + * in the pixel array + */ + public synchronized void newPixels(byte newpix[], ColorModel newmodel, + int offset, int scansize) { + this.dataType = DATA_TYPE_BYTE; + this.bData = newpix; + this.cm = newmodel; + this.offset = offset; + this.scanline = scansize; + newPixels(); + } + + /** + * Sets the full buffer updates flag to true. If this is an + * animated image, the image consumers hints are updated + * accordingly. + * + * @param fullbuffers the true if the pixel buffer should be sent always. + */ + public synchronized void setFullBufferUpdates(boolean fullbuffers) { + if(this.fullbuffers == fullbuffers) { + return; + } + this.fullbuffers = fullbuffers; + if(animated){ + Object consAr[] = consumers.toArray(); + for (Object element : consAr) { + ImageConsumer con = (ImageConsumer)element; + try{ + if(fullbuffers){ + con.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | + ImageConsumer.COMPLETESCANLINES); + }else{ + con.setHints(ImageConsumer.RANDOMPIXELORDER); + } + }catch(Exception e){ + if(isConsumer(con)) { + con.imageComplete(ImageConsumer.IMAGEERROR); + } + if(isConsumer(con)) { + removeConsumer(con); + } + } + } + } + } + + /** + * Sets the flag that tells whether this memory image has more + * than one frame (for animation): true for multiple frames, + * false if this class represents a single frame image. + * + * @param animated whether this image represents an animation. + */ + public synchronized void setAnimated(boolean animated) { + if(this.animated == animated) { + return; + } + Object consAr[] = consumers.toArray(); + for (Object element : consAr) { + ImageConsumer con = (ImageConsumer)element; + try{ + con.imageComplete(ImageConsumer.STATICIMAGEDONE); + }catch(Exception e){ + if(isConsumer(con)) { + con.imageComplete(ImageConsumer.IMAGEERROR); + } + } + if(isConsumer(con)){ + removeConsumer(con); + } + } + this.animated = animated; + } + + /** + * Sends the specified rectangular area of the buffer to + * ImageConsumers and notifies them that an animation frame + * is completed only if framenotify parameter is true. + * That works only if the animated flag has been set to true + * by the setAnimated() method. If the full buffer update flag + * has been set to true by the setFullBufferUpdates() method, + * then the entire buffer will always be sent ignoring parameters. + * + * @param x the X coordinate of the rectangular area. + * @param y the Y coordinate of rthe ectangular area. + * @param w the width of the rectangular area. + * @param h the height of the rectangular area. + * @param framenotify true if a SINGLEFRAMEDONE notification + * should be sent to the registered consumers, false otherwise. + */ + public synchronized void newPixels(int x, int y, int w, int h, + boolean framenotify) { + if(animated){ + if(fullbuffers){ + x = 0; + y = 0; + w = width; + h = height; + }else{ + if(x < 0){ + w += x; + x = 0; + } + if(w > width) { + w = width - x; + } + if(y < 0){ + h += y; + y = 0; + } + } + if(h > height) { + h = height - y; + } + Object consAr[] = consumers.toArray(); + for (Object element : consAr) { + ImageConsumer con = (ImageConsumer)element; + try{ + if(w > 0 && h > 0) { + setPixels(con, x, y, w, h); + } + if(framenotify) { + con.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + } + }catch(Exception ex){ + if(isConsumer(con)) { + con.imageComplete(ImageConsumer.IMAGEERROR); + } + if(isConsumer(con)) { + removeConsumer(con); + } + } + } + } + } + + /** + * Sends the specified rectangular area of the buffer to + * the ImageConsumers and notifies them that an animation frame + * is completed if the animated flag has been set to true + * by the setAnimated() method. If the full buffer update flag + * has been set to true by the setFullBufferUpdates() method, + * then the entire buffer will always be sent ignoring parameters. + * + * @param x the X coordinate of the rectangular area. + * @param y the Y coordinate of the rectangular area. + * @param w the width of the rectangular area. + * @param h the height of the rectangular area. + */ + public synchronized void newPixels(int x, int y, int w, int h) { + newPixels(x, y, w, h, true); + } + + /** + * Sends a new buffer of pixels to the ImageConsumers + * and notifies them that an animation frame is completed if + * the animated flag has been set to true by the setAnimated() method. + */ + public void newPixels() { + newPixels(0, 0, width, height, true); + } + + /** + * Inits the. + * + * @param width the width + * @param height the height + * @param model the model + * @param pixels the pixels + * @param off the off + * @param scan the scan + * @param prop the prop + */ + private void init(int width, int height, ColorModel model, byte pixels[], + int off, int scan, Hashtable prop){ + + this.width = width; + this.height = height; + this.cm = model; + this.bData = pixels; + this.offset = off; + this.scanline = scan; + this.properties = prop; + this.dataType = DATA_TYPE_BYTE; + this.consumers = new Vector(); + + } + + /** + * Inits the. + * + * @param width the width + * @param height the height + * @param model the model + * @param pixels the pixels + * @param off the off + * @param scan the scan + * @param prop the prop + */ + private void init(int width, int height, ColorModel model, int pixels[], + int off, int scan, Hashtable prop){ + + this.width = width; + this.height = height; + this.cm = model; + this.iData = pixels; + this.offset = off; + this.scanline = scan; + this.properties = prop; + this.dataType = DATA_TYPE_INT; + this.consumers = new Vector(); + } + + /** + * Sets the pixels. + * + * @param con the con + * @param x the x + * @param y the y + * @param w the w + * @param h the h + */ + private void setPixels(ImageConsumer con, int x, int y, int w, int h){ + int pixelOff = scanline * y + offset + x; + + switch(dataType){ + case DATA_TYPE_BYTE: + con.setPixels(x, y, w, h, cm, bData, pixelOff, scanline); + break; + case DATA_TYPE_INT: + con.setPixels(x, y, w, h, cm, iData, pixelOff, scanline); + break; + default: + // awt.22A=Wrong type of pixels array + throw new IllegalArgumentException(Messages.getString("awt.22A")); //$NON-NLS-1$ + } + } + + /** + * Sets the header. + * + * @param con the new header + */ + private synchronized void setHeader(ImageConsumer con){ + con.setDimensions(width, height); + con.setProperties(properties); + con.setColorModel(cm); + con.setHints(animated ? (fullbuffers ? (ImageConsumer.TOPDOWNLEFTRIGHT | + ImageConsumer.COMPLETESCANLINES) : ImageConsumer.RANDOMPIXELORDER) : + (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES | + ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME)); + } + +} + diff --git a/awt/java/awt/image/MultiPixelPackedSampleModel.java b/awt/java/awt/image/MultiPixelPackedSampleModel.java new file mode 100644 index 0000000..dd44b49 --- /dev/null +++ b/awt/java/awt/image/MultiPixelPackedSampleModel.java @@ -0,0 +1,454 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The MultiPixelPackedSampleModel class represents image data with one + * band. This class packs multiple pixels with one sample in one data + * element and supports the following data types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT. + */ +public class MultiPixelPackedSampleModel extends SampleModel { + + /** The pixel bit stride. */ + private int pixelBitStride; + + /** The scanline stride. */ + private int scanlineStride; + + /** The data bit offset. */ + private int dataBitOffset; + + /** The bit mask. */ + private int bitMask; + + /** The data element size. */ + private int dataElementSize; + + /** The pixels per data element. */ + private int pixelsPerDataElement; + + /** + * Instantiates a new MultiPixelPackedSampleModel with the specified + * parameters. + * + * @param dataType the data type of the samples. + * @param w the width of the image data. + * @param h the height of the image data. + * @param numberOfBits the number of bits per pixel. + * @param scanlineStride the scanline stride of the of the image data. + * @param dataBitOffset the array of the band offsets. + */ + public MultiPixelPackedSampleModel(int dataType, int w, int h, + int numberOfBits, int scanlineStride, int dataBitOffset) { + + super(dataType, w, h, 1); + if (dataType != DataBuffer.TYPE_BYTE && + dataType != DataBuffer.TYPE_USHORT && + dataType != DataBuffer.TYPE_INT) { + // awt.61=Unsupported data type: {0} + throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$ + dataType)); + } + + this.scanlineStride = scanlineStride; + if(numberOfBits == 0) { + // awt.20C=Number of Bits equals to zero + throw new RasterFormatException(Messages.getString("awt.20C")); //$NON-NLS-1$ + } + this.pixelBitStride = numberOfBits; + this.dataElementSize = DataBuffer.getDataTypeSize(dataType); + if(dataElementSize % pixelBitStride != 0) { + // awt.20D=The number of bits per pixel is not a power of 2 or pixels span data element boundaries + throw new RasterFormatException(Messages.getString("awt.20D")); //$NON-NLS-1$ + } + + if(dataBitOffset % numberOfBits != 0) { + // awt.20E=Data Bit offset is not a multiple of pixel bit stride + throw new RasterFormatException(Messages.getString("awt.20E")); //$NON-NLS-1$ + } + this.dataBitOffset = dataBitOffset; + + this.pixelsPerDataElement = dataElementSize / pixelBitStride; + this.bitMask = (1 << numberOfBits) - 1; + } + + /** + * Instantiates a new MultiPixelPackedSampleModel with the specified + * parameters. + * + * @param dataType the data type of the samples. + * @param w the width of the image data. + * @param h the height of the image data. + * @param numberOfBits the number of bits per pixel. + */ + public MultiPixelPackedSampleModel(int dataType, int w, int h, + int numberOfBits) { + + this(dataType, w, h, numberOfBits, (numberOfBits * w + + DataBuffer.getDataTypeSize(dataType) - 1) / + DataBuffer.getDataTypeSize(dataType), 0); + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[1]; + } else { + bdata = (byte[]) obj; + } + bdata[0] = (byte) getSample(x, y, 0, data); + obj = bdata; + break; + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[1]; + } else { + sdata = (short[]) obj; + } + sdata[0] = (short) getSample(x, y, 0, data); + obj = sdata; + break; + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[1]; + } else { + idata = (int[]) obj; + } + idata[0] = getSample(x, y, 0, data); + obj = idata; + break; + } + + return obj; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + setSample(x, y, obj, data, 1, 0); + } + + /** + * Compares this MultiPixelPackedSampleModel object with + * the specified object. + * + * @param o the Object to be compared. + * + * @return true, if the object is a MultiPixelPackedSampleModel + * with the same data parameter values as this MultiPixelPackedSampleModel, + * false otherwise. + */ + @Override + public boolean equals(Object o) { + if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) { + return false; + } + + MultiPixelPackedSampleModel model = (MultiPixelPackedSampleModel) o; + return this.width == model.width && + this.height == model.height && + this.numBands == model.numBands && + this.dataType == model.dataType && + this.pixelBitStride == model.pixelBitStride && + this.bitMask == model.bitMask && + this.pixelsPerDataElement == model.pixelsPerDataElement && + this.dataElementSize == model.dataElementSize && + this.dataBitOffset == model.dataBitOffset && + this.scanlineStride == model.scanlineStride; + } + + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands != null && bands.length != 1) { + // awt.20F=Number of bands must be only 1 + throw new RasterFormatException(Messages.getString("awt.20F")); //$NON-NLS-1$ + } + return createCompatibleSampleModel(width, height); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride); + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixel[]; + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + pixel[0] = getSample(x, y, 0, data); + return pixel; + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + setSample(x, y, iArray, data, 2, 0); + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height || b != 0) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int bitnum = dataBitOffset + x * pixelBitStride; + int elem = data.getElem(y * scanlineStride + bitnum / dataElementSize); + int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - + pixelBitStride; + + return (elem >> shift) & bitMask; + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (b != 0) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + setSample(x, y, null, data, 3, s); + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer dataBuffer = null; + int size = scanlineStride * height; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + dataBuffer = new DataBufferByte(size + (dataBitOffset + 7) / 8); + break; + case DataBuffer.TYPE_USHORT: + dataBuffer = new DataBufferUShort(size + (dataBitOffset + 15) / 16); + break; + case DataBuffer.TYPE_INT: + dataBuffer = new DataBufferInt(size + (dataBitOffset + 31) / 32); + break; + } + return dataBuffer; + } + + /** + * Gets the offset of the specified pixel in the data array. + * + * @param x the X coordinate of the specified pixel. + * @param y the Y coordinate of the specified pixel. + * + * @return the offset of the specified pixel. + */ + public int getOffset(int x, int y) { + return y * scanlineStride + (x * pixelBitStride + dataBitOffset) / + dataElementSize; + } + + @Override + public int getSampleSize(int band) { + return pixelBitStride; + } + + /** + * Gets the bit offset in the data element which + * is stored for the specified pixel of a scanline. + * + * @param x the pixel. + * + * @return the bit offset of the pixel in the data element. + */ + public int getBitOffset(int x) { + return (x * pixelBitStride + dataBitOffset) % dataElementSize; + } + + @Override + public int[] getSampleSize() { + int sampleSizes[] = { pixelBitStride }; + return sampleSizes; + } + + /** + * Returns a hash code of this MultiPixelPackedSampleModel class. + * + * @return the hash code of this MultiPixelPackedSampleModel class. + */ + @Override + public int hashCode() { + int hash = 0; + int tmp = 0; + + hash = width; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= height; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= numBands; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataType; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= scanlineStride; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= pixelBitStride; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataBitOffset; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= bitMask; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataElementSize; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= pixelsPerDataElement; + return hash; + } + + @Override + public int getTransferType() { + if (pixelBitStride > 16) { + return DataBuffer.TYPE_INT; + } else if (pixelBitStride > 8) { + return DataBuffer.TYPE_USHORT; + } else { + return DataBuffer.TYPE_BYTE; + } + } + + /** + * Gets the scanline stride of this MultiPixelPackedSampleModel. + * + * @return the scanline stride of this MultiPixelPackedSampleModel. + */ + public int getScanlineStride() { + return scanlineStride; + } + + /** + * Gets the pixel bit stride of this MultiPixelPackedSampleModel. + * + * @return the pixel bit stride of this MultiPixelPackedSampleModel. + */ + public int getPixelBitStride() { + return pixelBitStride; + } + + @Override + public int getNumDataElements() { + return 1; + } + + /** + * Gets the data bit offset. + * + * @return the data bit offset. + */ + public int getDataBitOffset() { + return dataBitOffset; + } + + /** + * This method is used by other methods of this class. The behaviour of + * this method depends on the method which has been invoke this one. The + * argument methodId is used to choose valid behaviour in a particular case. + * If methodId is equal to 1 it means that this method has been invoked by + * the setDataElements() method, 2 - means setPixel(), and setSample() in + * any other cases. + * + * @param x the x + * @param y the y + * @param obj the obj + * @param data the data + * @param methodId the method id + * @param s the s + */ + private void setSample(final int x, final int y, final Object obj, + final DataBuffer data, final int methodId, int s) { + if ((x < 0) || (y < 0) || (x >= this.width) || (y >= this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages + .getString("awt.63")); //$NON-NLS-1$ + } + + final int bitnum = dataBitOffset + x * pixelBitStride; + final int idx = y * scanlineStride + bitnum / dataElementSize; + final int shift = dataElementSize - (bitnum & (dataElementSize - 1)) + - pixelBitStride; + final int mask = ~(bitMask << shift); + int elem = data.getElem(idx); + + switch (methodId) { + case 1: { // Invoked from setDataElements() + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + s = ((byte[]) obj)[0] & 0xff; + break; + case DataBuffer.TYPE_USHORT: + s = ((short[]) obj)[0] & 0xffff; + break; + case DataBuffer.TYPE_INT: + s = ((int[]) obj)[0]; + break; + } + break; + } + case 2: { // Invoked from setPixel() + s = ((int[]) obj)[0]; + break; + } + } + + elem &= mask; + elem |= (s & bitMask) << shift; + data.setElem(idx, elem); + } +} + diff --git a/awt/java/awt/image/PackedColorModel.java b/awt/java/awt/image/PackedColorModel.java new file mode 100644 index 0000000..7aaefbf --- /dev/null +++ b/awt/java/awt/image/PackedColorModel.java @@ -0,0 +1,383 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class PackedColorModel represents a color model where the + * components are just the red, green, and blue bands, plus an alpha + * band if alpha is supported. + */ +public abstract class PackedColorModel extends ColorModel { + + /** The component masks. */ + int componentMasks[]; + + /** The offsets. */ + int offsets[]; + + /** The scales. */ + float scales[]; + + /** + * Instantiates a new packed color model. + * + * @param space the color space + * @param bits the array of component masks + * @param colorMaskArray the array that gives the bitmask corresponding + * to each color band (red, green, and blue) + * @param alphaMask the bitmask corresponding to the alpha band + * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model + * @param trans the transparency strategy, @see java.awt.Transparency + * @param transferType the transfer type (primitive java type + * to use for the components) + * + * @throws IllegalArgumentException if the number of bits in the combined + * bitmasks for the color bands is less than one or greater than 32 + */ + public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[], + int alphaMask, boolean isAlphaPremultiplied, int trans, + int transferType) { + + super(bits, createBits(colorMaskArray, alphaMask), space, + (alphaMask == 0 ? false : true), isAlphaPremultiplied, trans, + validateTransferType(transferType)); + + if (pixel_bits < 1 || pixel_bits > 32) { + // awt.236=The bits is less than 1 or greater than 32 + throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$ + } + + componentMasks = new int[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + componentMasks[i] = colorMaskArray[i]; + } + + if (hasAlpha) { + componentMasks[numColorComponents] = alphaMask; + if (this.bits[numColorComponents] == 1) { + transparency = Transparency.BITMASK; + } + } + + parseComponents(); + } + + /** + * Instantiates a new packed color model. + * + * @param space the color space + * @param bits the array of component masks + * @param rmask the bitmask corresponding to the red band + * @param gmask the bitmask corresponding to the green band + * @param bmask the bitmask corresponding to the blue band + * @param amask the bitmask corresponding to the alpha band + * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model + * @param trans the transparency strategy, @see java.awt.Transparency + * @param transferType the transfer type (primitive java type + * to use for the components) + * + * @throws IllegalArgumentException if the number of bits in the combined + * bitmasks for the color bands is less than one or greater than 32 + */ + public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask, + int bmask, int amask, boolean isAlphaPremultiplied, int trans, + int transferType) { + + super(bits, createBits(rmask, gmask, bmask, amask), space, + (amask == 0 ? false : true), isAlphaPremultiplied, trans, + validateTransferType(transferType)); + + if (pixel_bits < 1 || pixel_bits > 32) { + // awt.236=The bits is less than 1 or greater than 32 + throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$ + } + + if (cs.getType() != ColorSpace.TYPE_RGB) { + // awt.239=The space is not a TYPE_RGB space + throw new IllegalArgumentException(Messages.getString("awt.239")); //$NON-NLS-1$ + } + + for (int i = 0; i < numColorComponents; i++) { + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + // awt.23A=The min/max normalized component values are not 0.0/1.0 + throw new IllegalArgumentException(Messages.getString("awt.23A")); //$NON-NLS-1$ + } + } + componentMasks = new int[numComponents]; + componentMasks[0] = rmask; + componentMasks[1] = gmask; + componentMasks[2] = bmask; + + if (hasAlpha) { + componentMasks[3] = amask; + if (this.bits[3] == 1) { + transparency = Transparency.BITMASK; + } + } + + parseComponents(); + } + + @Override + public WritableRaster getAlphaRaster(WritableRaster raster) { + if(!hasAlpha) { + return null; + } + + int x = raster.getMinX(); + int y = raster.getMinY(); + int w = raster.getWidth(); + int h = raster.getHeight(); + int band[] = new int[1]; + band[0] = raster.getNumBands() - 1; + return raster.createWritableChild(x, y, w, h, x, y, band); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof PackedColorModel)) { + return false; + } + PackedColorModel cm = (PackedColorModel) obj; + + return (pixel_bits == cm.getPixelSize() && + transferType == cm.getTransferType() && + cs.getType() == cm.getColorSpace().getType() && + hasAlpha == cm.hasAlpha() && + isAlphaPremultiplied == cm.isAlphaPremultiplied() && + transparency == cm.getTransparency() && + numColorComponents == cm.getNumColorComponents()&& + numComponents == cm.getNumComponents() && + Arrays.equals(bits, cm.getComponentSize()) && + Arrays.equals(componentMasks, cm.getMasks())); + } + + @Override + public boolean isCompatibleSampleModel(SampleModel sm) { + if (sm == null) { + return false; + } + if (!(sm instanceof SinglePixelPackedSampleModel)) { + return false; + } + SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel) sm; + + return ((esm.getNumBands() == numComponents) && + (esm.getTransferType() == transferType) && + Arrays.equals(esm.getBitMasks(), componentMasks)); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new SinglePixelPackedSampleModel(transferType, w, h, + componentMasks); + } + + /** + * Gets the bitmask corresponding to the specified color component. + * + * @param index the index of the desired color + * + * @return the mask + */ + public final int getMask(int index) { + return componentMasks[index]; + } + + /** + * Gets the bitmasks of the components. + * + * @return the masks + */ + public final int[] getMasks() { + return (componentMasks.clone()); + } + + /** + * Creates the bits. + * + * @param colorMaskArray the color mask array + * @param alphaMask the alpha mask + * + * @return the int[] + */ + private static int[] createBits(int colorMaskArray[], int alphaMask) { + int bits[]; + int numComp; + if (alphaMask == 0) { + numComp = colorMaskArray.length; + } else { + numComp = colorMaskArray.length + 1; + } + + bits = new int[numComp]; + int i = 0; + for (; i < colorMaskArray.length; i++) { + bits[i] = countCompBits(colorMaskArray[i]); + if (bits[i] < 0) { + // awt.23B=The mask of the {0} component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23B", i)); //$NON-NLS-1$ + } + } + + if (i < numComp) { + bits[i] = countCompBits(alphaMask); + + if (bits[i] < 0) { + // awt.23C=The mask of the alpha component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$ + } + } + + return bits; + } + + /** + * Creates the bits. + * + * @param rmask the rmask + * @param gmask the gmask + * @param bmask the bmask + * @param amask the amask + * + * @return the int[] + */ + private static int[] createBits(int rmask, int gmask, int bmask, + int amask) { + + int numComp; + if (amask == 0) { + numComp = 3; + } else { + numComp = 4; + } + int bits[] = new int[numComp]; + + bits[0] = countCompBits(rmask); + if (bits[0] < 0) { + // awt.23D=The mask of the red component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23D")); //$NON-NLS-1$ + } + + bits[1] = countCompBits(gmask); + if (bits[1] < 0) { + // awt.23E=The mask of the green component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23E")); //$NON-NLS-1$ + } + + bits[2] = countCompBits(bmask); + if (bits[2] < 0) { + // awt.23F=The mask of the blue component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23F")); //$NON-NLS-1$ + } + + if (amask != 0) { + bits[3] = countCompBits(amask); + if (bits[3] < 0) { + // awt.23C=The mask of the alpha component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$ + } + } + + return bits; + } + + /** + * Count comp bits. + * + * @param compMask the comp mask + * + * @return the int + */ + private static int countCompBits(int compMask) { + int bits = 0; + if (compMask != 0) { + // Deleting final zeros + while ((compMask & 1) == 0) { + compMask >>>= 1; + } + // Counting component bits + while ((compMask & 1) == 1) { + compMask >>>= 1; + bits++; + } + } + + if (compMask != 0) { + return -1; + } + + return bits; + } + + /** + * Validate transfer type. + * + * @param transferType the transfer type + * + * @return the int + */ + private static int validateTransferType(int transferType) { + if (transferType != DataBuffer.TYPE_BYTE && + transferType != DataBuffer.TYPE_USHORT && + transferType != DataBuffer.TYPE_INT) { + // awt.240=The transferType not is one of DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT + throw new IllegalArgumentException(Messages.getString("awt.240")); //$NON-NLS-1$ + } + return transferType; +} + + /** + * Parses the components. + */ + private void parseComponents() { + offsets = new int[numComponents]; + scales = new float[numComponents]; + for (int i = 0; i < numComponents; i++) { + int off = 0; + int mask = componentMasks[i]; + while ((mask & 1) == 0) { + mask >>>= 1; + off++; + } + offsets[i] = off; + if (bits[i] == 0) { + scales[i] = 256.0f; // May be any value different from zero, + // because will dividing by zero + } else { + scales[i] = 255.0f / maxValues[i]; + } + } + + } + +} + diff --git a/awt/java/awt/image/PixelGrabber.java b/awt/java/awt/image/PixelGrabber.java new file mode 100644 index 0000000..cecd5c8 --- /dev/null +++ b/awt/java/awt/image/PixelGrabber.java @@ -0,0 +1,408 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Image; +import java.util.Hashtable; + +import org.apache.harmony.awt.internal.nls.Messages; + +public class PixelGrabber implements ImageConsumer { + + int width; + int height; + int X; + int Y; + int offset; + int scanline; + ImageProducer producer; + + byte bData[]; + int iData[]; + ColorModel cm; + + private int grabberStatus; + private int dataType; + private boolean isGrabbing; + private boolean isRGB; + + + private static final int DATA_TYPE_BYTE = 0; + private static final int DATA_TYPE_INT = 1; + private static final int DATA_TYPE_UNDEFINED = 2; + + private static final int ALL_BITS = (ImageObserver.FRAMEBITS | + ImageObserver.ALLBITS); + + private static final int GRABBING_STOP = ALL_BITS | ImageObserver.ERROR; + + + + public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, int[] pix, + int off, int scansize) { + initialize(ip, x, y, w, h, pix, off, scansize, true); + } + + public PixelGrabber(Image img, int x, int y, int w, int h, int[] pix, + int off, int scansize) { + initialize(img.getSource(), x, y, w, h, pix, off, scansize, true); + } + + public PixelGrabber(Image img, int x, int y, int w, int h, boolean forceRGB) { + initialize(img.getSource(), x, y, w, h, null, 0, 0, forceRGB); + } + + public void setProperties(Hashtable props) { + return; + } + + public synchronized Object getPixels() { + switch(dataType){ + case DATA_TYPE_BYTE: + return bData; + case DATA_TYPE_INT: + return iData; + default: + return null; + } + } + + public void setColorModel(ColorModel model) { + return; + } + + public void setPixels(int srcX, int srcY, int srcW, int srcH, + ColorModel model, byte[] pixels, int srcOff, int srcScan) { + if(srcY < Y){ + int delta = Y - srcY; + if(delta >= height) { + return; + } + srcY += delta; + srcH -= delta; + srcOff += srcScan * delta; + } + + if(srcY + srcH > Y + height){ + srcH = Y + height - srcY; + if(srcH <= 0) { + return; + } + } + + if(srcX < X){ + int delta = X - srcX; + if(delta >= width) { + return; + } + srcW -= delta; + srcX += delta; + srcOff += delta; + } + + if(srcX + srcW > X + width){ + srcW = X + width - srcX; + if(srcW <= 0) { + return; + } + } + if(scanline == 0) { + scanline = width; + } + int realOff = offset + (srcY - Y) * scanline + (srcX - X); + switch(dataType){ + case DATA_TYPE_UNDEFINED: + cm = model; + if(model != ColorModel.getRGBdefault()){ + bData = new byte[width * height]; + isRGB = false; + dataType = DATA_TYPE_BYTE; + }else{ + iData = new int[width * height]; + isRGB = true; + dataType = DATA_TYPE_INT; + } + case DATA_TYPE_BYTE: + if(!isRGB && cm == model){ + for(int y = 0; y < srcH; y++){ + System.arraycopy(pixels, srcOff, bData, realOff, srcW); + srcOff += srcScan; + realOff += scanline; + } + break; + } + forceToRGB(); + case DATA_TYPE_INT: + for(int y = 0; y < srcH; y++){ + for(int x = 0; x < srcW; x++){ + iData[realOff + x] = cm.getRGB(pixels[srcOff + x] & 0xff); + } + srcOff += srcScan; + realOff += scanline; + } + } + + return; + } + + public void setPixels(int srcX, int srcY, int srcW, int srcH, + ColorModel model, int[] pixels, int srcOff, int srcScan) { + + if(srcY < Y){ + int delta = Y - srcY; + if(delta >= height) { + return; + } + srcY += delta; + srcH -= delta; + srcOff += srcScan * delta; + } + + if(srcY + srcH > Y + height){ + srcH = Y + height - srcY; + if(srcH <= 0) { + return; + } + } + + if(srcX < X){ + int delta = X - srcX; + if(delta >= width) { + return; + } + srcW -= delta; + srcX += delta; + srcOff += delta; + } + + if(srcX + srcW > X + width){ + srcW = X + width - srcX; + if(srcW <= 0) { + return; + } + } + if(scanline == 0) { + scanline = width; + } + int realOff = offset + (srcY - Y) * scanline + (srcX - X); + + int mask = 0xFF; + + switch(dataType){ + case DATA_TYPE_UNDEFINED: + cm = model; + iData = new int[width * height]; + dataType = DATA_TYPE_INT; + isRGB = (cm == ColorModel.getRGBdefault()); + + case DATA_TYPE_INT: + if(cm == model){ + for(int y = 0; y < srcH; y++){ + System.arraycopy(pixels, srcOff, iData, realOff, srcW); + srcOff += srcScan; + realOff += scanline; + } + break; + } + mask = 0xFFFFFFFF; + + case DATA_TYPE_BYTE: + forceToRGB(); + for(int y = 0; y < srcH; y++){ + for(int x = 0; x < srcW; x++){ + iData[realOff+x] = cm.getRGB(pixels[srcOff+x] & mask); + } + srcOff += srcScan; + realOff += scanline; + } + } + } + + public synchronized ColorModel getColorModel() { + return cm; + } + + public synchronized boolean grabPixels(long ms) + throws InterruptedException { + if((grabberStatus & GRABBING_STOP) != 0){ + return ((grabberStatus & ALL_BITS) != 0); + } + + long start = System.currentTimeMillis(); + + if(!isGrabbing){ + isGrabbing = true; + grabberStatus &= ~ImageObserver.ABORT; + producer.startProduction(this); + } + while((grabberStatus & GRABBING_STOP) == 0){ + if(ms != 0){ + ms = start + ms - System.currentTimeMillis(); + if(ms <= 0) { + break; + } + } + wait(ms); + } + + return ((grabberStatus & ALL_BITS) != 0); + } + + public void setDimensions(int w, int h) { + if(width < 0) { + width = w - X; + } + if(height < 0) { + height = h - Y; + } + + grabberStatus |= ImageObserver.WIDTH | ImageObserver.HEIGHT; + + if(width <=0 || height <=0){ + imageComplete(STATICIMAGEDONE); + return; + } + + if(isRGB && dataType == DATA_TYPE_UNDEFINED){ + iData = new int[width * height]; + dataType = DATA_TYPE_INT; + scanline = width; + } + } + + public void setHints(int hints) { + return; + } + + public synchronized void imageComplete(int status) { + switch(status){ + case IMAGEABORTED: + grabberStatus |= ImageObserver.ABORT; + break; + case IMAGEERROR: + grabberStatus |= ImageObserver.ERROR | ImageObserver.ABORT; + break; + case SINGLEFRAMEDONE: + grabberStatus |= ImageObserver.FRAMEBITS; + break; + case STATICIMAGEDONE: + grabberStatus |= ImageObserver.ALLBITS; + break; + default: + // awt.26A=Incorrect ImageConsumer completion status + throw new IllegalArgumentException(Messages.getString("awt.26A")); //$NON-NLS-1$ + } + isGrabbing = false; + producer.removeConsumer(this); + notifyAll(); + } + + public boolean grabPixels() throws InterruptedException { + return grabPixels(0); + } + + public synchronized void startGrabbing() { + if((grabberStatus & GRABBING_STOP) != 0){ + return; + } + if(!isGrabbing){ + isGrabbing = true; + grabberStatus &= ~ImageObserver.ABORT; + producer.startProduction(this); + } + } + + public synchronized void abortGrabbing() { + imageComplete(IMAGEABORTED); + } + + public synchronized int status() { + return grabberStatus; + } + + public synchronized int getWidth() { + if(width < 0) { + return -1; + } + return width; + } + + public synchronized int getStatus() { + return grabberStatus; + } + + public synchronized int getHeight() { + if(height < 0) { + return -1; + } + return height; + } + + private void initialize(ImageProducer ip, int x, int y, int w, int h, + int pixels[], int off, int scansize, boolean forceRGB){ + + producer = ip; + X = x; + Y = y; + width = w; + height = h; + iData = pixels; + dataType = (pixels == null) ? DATA_TYPE_UNDEFINED : DATA_TYPE_INT; + offset = off; + scanline = scansize; + if(forceRGB){ + cm = ColorModel.getRGBdefault(); + isRGB = true; + } + } + + /** + * Force pixels to INT RGB mode + */ + private void forceToRGB(){ + if (isRGB) + return; + + switch(dataType){ + case DATA_TYPE_BYTE: + iData = new int[width * height]; + for(int i = 0; i < iData.length; i++){ + iData[i] = cm.getRGB(bData[i] & 0xff); + } + dataType = DATA_TYPE_INT; + bData = null; + break; + + case DATA_TYPE_INT: + int buff[] = new int[width * height]; + for(int i = 0; i < iData.length; i++){ + buff[i] = cm.getRGB(iData[i]); + } + iData = buff; + break; + } + offset = 0; + scanline = width; + cm = ColorModel.getRGBdefault(); + isRGB = true; + } + +} diff --git a/awt/java/awt/image/PixelInterleavedSampleModel.java b/awt/java/awt/image/PixelInterleavedSampleModel.java new file mode 100644 index 0000000..e41473e --- /dev/null +++ b/awt/java/awt/image/PixelInterleavedSampleModel.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The PixelInterleavedSampleModel class represents image data + * as represented as interleaved pixels and for which each sample of + * a pixel takes one data element of the DataBuffer. + */ +public class PixelInterleavedSampleModel extends ComponentSampleModel { + + /** + * Instantiates a new PixelInterleavedSampleModel with the + * specified parameters. + * + * @param dataType the data type of the samples. + * @param w the width of the image data. + * @param h the height of the image data. + * @param pixelStride the pixel stride of the image data. + * @param scanlineStride the scanline stride of the of the image data. + * @param bandOffsets the array of the band offsets. + */ + public PixelInterleavedSampleModel(int dataType, int w, int h, + int pixelStride, int scanlineStride, int bandOffsets[]) { + + super(dataType, w, h, pixelStride, scanlineStride, bandOffsets); + + int maxOffset = bandOffsets[0]; + int minOffset = bandOffsets[0]; + for (int i = 1; i < bandOffsets.length; i++) { + if (bandOffsets[i] > maxOffset) { + maxOffset = bandOffsets[i]; + } + if (bandOffsets[i] < minOffset) { + minOffset = bandOffsets[i]; + } + } + + maxOffset -= minOffset; + + if (maxOffset > scanlineStride) { + // awt.241=Any offset between bands is greater than the Scanline stride + throw new IllegalArgumentException(Messages.getString("awt.241")); //$NON-NLS-1$ + } + + if (maxOffset > pixelStride) { + // awt.242=Pixel stride is less than any offset between bands + throw new IllegalArgumentException(Messages.getString("awt.242")); //$NON-NLS-1$ + } + + if (pixelStride * w > scanlineStride) { + // awt.243=Product of Pixel stride and w is greater than Scanline stride + throw new IllegalArgumentException(Messages.getString("awt.243")); //$NON-NLS-1$ + } + + } + + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + int newOffsets[] = new int[bands.length]; + for (int i = 0; i < bands.length; i++) { + newOffsets[i] = bandOffsets[bands[i]]; + } + + return new PixelInterleavedSampleModel(dataType, width, height, + pixelStride, scanlineStride, newOffsets); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + int newOffsets[]; + int minOffset = bandOffsets[0]; + + for (int i = 1; i < numBands; i++) { + if (bandOffsets[i] < minOffset) { + minOffset = bandOffsets[i]; + } + } + + if (minOffset > 0) { + newOffsets = new int[numBands]; + for (int i = 0; i < numBands; i++) { + newOffsets[i] = bandOffsets[i] - minOffset; + } + } else { + newOffsets = bandOffsets; + } + + return new PixelInterleavedSampleModel(dataType, w, h, pixelStride, + pixelStride * w, newOffsets); + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + int tmp = hash >>> 8; + hash <<= 8; + hash |= tmp; + + return hash ^ 0x66; + } + +} + diff --git a/awt/java/awt/image/RGBImageFilter.java b/awt/java/awt/image/RGBImageFilter.java new file mode 100644 index 0000000..9a76997 --- /dev/null +++ b/awt/java/awt/image/RGBImageFilter.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + + +/** + * The RGBImageFilter class represents a filter which modifies + * pixels of an image in the default RGB ColorModel. + */ +public abstract class RGBImageFilter extends ImageFilter { + + /** + * The origmodel is the ColorModel to be replaced by newmodel + * when substituteColorModel is called. + */ + protected ColorModel origmodel; + + /** + * The newmodel is the ColorModel with which to replace origmodel + * when substituteColorModel is called. + */ + protected ColorModel newmodel; + + /** + * The canFilterIndexColorModel indicates if it is + * acceptable to apply the color filtering of the filterRGB + * method to the color table entries of an IndexColorModel + * object. + * */ + protected boolean canFilterIndexColorModel; + + /** + * Instantiates a new RGBImageFilter. + */ + public RGBImageFilter() {} + + /** + * Filters an IndexColorModel object by calling filterRGB function for + * each entry of IndexColorModel. + * + * @param icm the IndexColorModel to be filtered. + * + * @return the IndexColorModel. + */ + public IndexColorModel filterIndexColorModel(IndexColorModel icm) { + int transferType = icm.getTransferType(); + int bits = icm.getPixelSize(); + int mapSize = icm.getMapSize(); + int colorMap[] = new int[mapSize]; + int filteredColorMap[] = new int[mapSize]; + icm.getRGBs(colorMap); + int trans = -1; + boolean hasAlpha = false; + for(int i = 0; i < mapSize; i++){ + filteredColorMap[i] = filterRGB(-1, -1, colorMap[i]); + int alpha = filteredColorMap[i] >>> 24; + if(alpha != 0xff){ + if(!hasAlpha) { + hasAlpha = true; + } + if(alpha == 0 && trans < 0) { + trans = i; + } + } + } + + return new IndexColorModel(bits, mapSize, filteredColorMap, 0, + hasAlpha, trans, transferType); + } + + /** + * Replaces the original color model and the new one. + * + * @param oldcm the old ColorModel. + * @param newcm the new ColorModel. + */ + public void substituteColorModel(ColorModel oldcm, ColorModel newcm) { + origmodel = oldcm; + newmodel = newcm; + } + + @Override + public void setColorModel(ColorModel model) { + if(model instanceof IndexColorModel && + canFilterIndexColorModel){ + IndexColorModel icm = (IndexColorModel) model; + ColorModel filteredModel = filterIndexColorModel(icm); + substituteColorModel(model, filteredModel); + consumer.setColorModel(filteredModel); + }else{ + consumer.setColorModel(ColorModel.getRGBdefault()); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, + int[] pixels, int off, int scansize) { + + if(model == null || model == origmodel){ + consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize); + }else{ + int rgbPixels[] = new int[w]; + for(int sy = y, pixelsOff = off; sy < y + h; + sy++, pixelsOff += scansize){ + + for(int sx = x, idx = 0; sx < x + w; sx++, idx++){ + rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx]); + } + filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w); + } + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, + byte[] pixels, int off, int scansize) { + + if(model == null || model == origmodel){ + consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize); + }else{ + int rgbPixels[] = new int[w]; + for(int sy = y, pixelsOff = off; sy < y + h; + sy++, pixelsOff += scansize){ + + for(int sx = x, idx = 0; sx < x + w; sx++, idx++){ + rgbPixels[idx] = + model.getRGB(pixels[pixelsOff + idx] & 0xff); + } + filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w); + } + } + } + + /** + * Filters a region of pixels in the default RGB ColorModel + * by calling the filterRGB method for them. + * + * @param x the X coordinate of region. + * @param y the Y coordinate of region. + * @param w the width ofregion. + * @param h the height of region. + * @param pixels the pixels array. + * @param off the offset of array. + * @param scansize the distance between rows of pixels in the array. + */ + public void filterRGBPixels(int x, int y, int w, int h, + int[] pixels, int off, int scansize) { + + for(int sy = y, lineOff = off; sy < y + h; sy++, lineOff += scansize){ + for(int sx = x, idx = 0; sx < x + w; sx++, idx++){ + pixels[lineOff + idx] = + filterRGB(sx, sy, pixels[lineOff + idx]); + } + } + consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), + pixels, off, scansize); + } + + /** + * Coverts a single input pixel in the default RGB ColorModel + * to a single output pixel. + * + * @param x the X pixel's coordinate. + * @param y the Y pixel's coordinate. + * @param rgb a pixel in the default RGB color model. + * + * @return a filtered pixel in the default RGB color model. + */ + public abstract int filterRGB(int x, int y, int rgb); + +} + diff --git a/awt/java/awt/image/Raster.java b/awt/java/awt/image/Raster.java new file mode 100644 index 0000000..4b2426e --- /dev/null +++ b/awt/java/awt/image/Raster.java @@ -0,0 +1,1412 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Point; +import java.awt.Rectangle; + +import org.apache.harmony.awt.gl.image.OrdinaryWritableRaster; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Raster class represents a rectangular area of pixels. + * This class is defined by DataBuffer and SampleModel objects. + * The DataBuffer object stores sample values and DSampleModel defines + * the location of sample in this DataBuffer. + */ +public class Raster { + + /** The DataBuffer of this Raster. */ + protected DataBuffer dataBuffer; + + /** The height of this Raster. */ + protected int height; + + /** The X coordinate of the upper left pixel in this Raster. */ + protected int minX; + + /** The Y coordinate of the upper left pixel in this Raster. */ + protected int minY; + + /** The number of bands in this Raster. */ + protected int numBands; + + /** The number of data elements. */ + protected int numDataElements; + + /** The parent of this Raster. */ + protected Raster parent; + + /** The SampleModel of this Raster. */ + protected SampleModel sampleModel; + + /** + * The X translation from the coordinate space of the + * SampleModel of this Raster. + */ + protected int sampleModelTranslateX; + + /** + * The Y translation from the coordinate space of the + * SampleModel of this Raster. + */ + protected int sampleModelTranslateY; + + /** The width of this Raster. */ + protected int width; + + /** + * Creates a Raster object with a BandedSampleModel and the specified + * DataBuffer. The number of bands is defined by the length of bandOffsets + * or bankIndices arrays. + * + * @param dataBuffer the specified DataBuffer. + * @param w the width of the image data. + * @param h the height of the image data. + * @param bankIndices the bank indices of bands. + * @param bandOffsets the band offsets of bands. + * @param location the location which defines the upper left corner + * of Raster. + * + * @return the WritableRaster object. + */ + public static WritableRaster createBandedRaster(DataBuffer dataBuffer, + int w, int h, int scanlineStride, int bankIndices[], + int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bankIndices == null || bandOffsets == null) { + // awt.277=bankIndices or bandOffsets is null + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$ + } + + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + + if (dataType != DataBuffer.TYPE_BYTE + && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + BandedSampleModel sampleModel = new BandedSampleModel(dataType, w, h, + scanlineStride, bankIndices, bandOffsets); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + } + + /** + * Creates a Raster object with a BandedSampleModel and the specified + * data type. The Data type can be one of the following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType the data type of the samples: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w the width of the image data. + * @param h the height of the image data. + * @param scanlineStride the scanline stride of the image data. + * @param bankIndices the bank indices of bands. + * @param bandOffsets the band offsets of bands. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster object. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, + int scanlineStride, int bankIndices[], int bandOffsets[], + Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bankIndices == null || bandOffsets == null) { + // awt.277=bankIndices or bandOffsets is null + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE + && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + int maxOffset = bandOffsets[0]; + int maxBank = bankIndices[0]; + + for (int i = 0; i < bankIndices.length; i++) { + if (bandOffsets[i] > maxOffset) { + maxOffset = bandOffsets[i]; + } + if (bankIndices[i] > maxBank) { + maxBank = bankIndices[i]; + } + } + + int numBanks = maxBank + 1; + int dataSize = scanlineStride * (h - 1) + w + maxOffset; + + DataBuffer data = null; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(dataSize, numBanks); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(dataSize, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(dataSize, numBanks); + break; + } + return createBandedRaster(data, w, h, scanlineStride, bankIndices, + bandOffsets, location); + } + + /** + * Creates a Raster object with a BandedSampleModel and the specified + * data type. The Data type can be one of the following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType the data type of the samples: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w the width of the image data. + * @param h the height of the image data. + * @param bands the number of bands. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster object. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, + int bands, Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bands < 1) { + // awt.279=bands is less than 1 + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.279")); //$NON-NLS-1$ + } + + int bandOffsets[] = new int[bands]; + int bankIndices[] = new int[bands]; + + for (int i = 0; i < bands; i++) { + bandOffsets[i] = 0; + bankIndices[i] = i; + } + return createBandedRaster(dataType, w, h, w, bankIndices, bandOffsets, + location); + } + + /** + * Creates a Raster object with a PixelInterleavedSampleModel + * and the specified DataBuffer. + * + * @param dataBuffer the DataBuffer. + * @param w the width of image data. + * @param h the height of image data. + * @param scanlineStride the scanline stride of the image data. + * @param pixelStride the pixel stride of image data. + * @param bandOffsets the band offsets of bands. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster object. + */ + public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, + int w, int h, int scanlineStride, int pixelStride, + int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + if (dataType != DataBuffer.TYPE_BYTE + && dataType != DataBuffer.TYPE_USHORT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (dataBuffer.getNumBanks() > 1) { + // awt.27A=dataBuffer has more than one bank + throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$ + } + + if (bandOffsets == null) { + // awt.27B=bandOffsets is null + throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$ + } + + PixelInterleavedSampleModel sampleModel = + new PixelInterleavedSampleModel(dataType, w, h, + pixelStride, scanlineStride, bandOffsets); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + + } + + /** + * Creates a Raster object with a PixelInterleavedSampleModel + * and the specified data type. The Data type can be one of the + * following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType the data type of the samples: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w the width of image data. + * @param h the height of image data. + * @param scanlineStride the scanline stride of the image data. + * @param pixelStride the pixel stride of image data. + * @param bandOffsets the band offsets of bands. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster object. + */ + public static WritableRaster createInterleavedRaster(int dataType, int w, + int h, int scanlineStride, int pixelStride, int bandOffsets[], + Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE + && dataType != DataBuffer.TYPE_USHORT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (bandOffsets == null) { + // awt.27B=bandOffsets is null + throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$ + } + + int minOffset = bandOffsets[0]; + for (int i = 1; i < bandOffsets.length; i++) { + if (bandOffsets[i] < minOffset) { + minOffset = bandOffsets[i]; + } + } + int size = (h - 1) * scanlineStride + w * pixelStride + minOffset; + DataBuffer data = null; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + } + + return createInterleavedRaster(data, w, h, scanlineStride, pixelStride, + bandOffsets, location); + } + + /** + * Creates a Raster object with a PixelInterleavedSampleModel + * and the specified data type. The Data type can be one of the + * following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType the data type of samples: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w the width of image data. + * @param h the height of image data. + * @param bands the number of bands. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster. + */ + public static WritableRaster createInterleavedRaster(int dataType, int w, + int h, int bands, Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE + && dataType != DataBuffer.TYPE_USHORT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + int bandOffsets[] = new int[bands]; + for (int i = 0; i < bands; i++) { + bandOffsets[i] = i; + } + + return createInterleavedRaster(dataType, w, h, w * bands, bands, + bandOffsets, location); + } + + /** + * Creates a Raster object with a SinglePixelPackedSampleModel + * and the specified DataBuffer. + * + * @param dataBuffer the DataBuffer. + * @param w the width of the image data. + * @param h the height of the image data. + * @param scanlineStride the scanline stride of the image data. + * @param bandMasks the band masks. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, + int w, int h, int scanlineStride, int bandMasks[], Point location) { + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bandMasks == null) { + // awt.27C=bandMasks is null + throw new RasterFormatException(Messages.getString("awt.27C")); //$NON-NLS-1$ + } + + if (dataBuffer.getNumBanks() > 1) { + // awt.27A=dataBuffer has more than one bank + throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + if (dataType != DataBuffer.TYPE_BYTE + && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + SinglePixelPackedSampleModel sampleModel = + new SinglePixelPackedSampleModel(dataType, w, h, + scanlineStride, bandMasks); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + } + + /** + * Creates a Raster object with a MultiPixelPackedSampleModel + * and the specified DataBuffer. + * + * @param dataBuffer the DataBuffer. + * @param w the width of the image data. + * @param h the height of the image data. + * @param bitsPerPixel the number of bits per pixel. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, + int w, int h, int bitsPerPixel, Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + if (dataBuffer.getNumBanks() > 1) { + // awt.27A=dataBuffer has more than one bank + throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + if (dataType != DataBuffer.TYPE_BYTE + && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + MultiPixelPackedSampleModel sampleModel = + new MultiPixelPackedSampleModel(dataType, w, h, bitsPerPixel); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + + } + + /** + * Creates a Raster object with a MultiPixelPackedSampleModel + * and the specified DataBuffer. + * + * @param dataType the data type of samples: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w the width of the image data. + * @param h the height of the image data. + * @param bands the number of bands. + * @param bitsPerBand the number of bits per band. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(int dataType, int w, int h, + int bands, int bitsPerBand, Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bands < 1 || bitsPerBand < 1) { + // awt.27D=bitsPerBand or bands is not greater than zero + throw new IllegalArgumentException(Messages.getString("awt.27D")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE + && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (bitsPerBand * bands > DataBuffer.getDataTypeSize(dataType)) { + // awt.27E=The product of bitsPerBand and bands is greater than the number of bits held by dataType + throw new IllegalArgumentException(Messages.getString("awt.27E")); //$NON-NLS-1$ + } + + if (bands > 1) { + + int bandMasks[] = new int[bands]; + int mask = (1 << bitsPerBand) - 1; + + for (int i = 0; i < bands; i++) { + bandMasks[i] = mask << (bitsPerBand * (bands - 1 - i)); + } + + return createPackedRaster(dataType, w, h, bandMasks, location); + } + DataBuffer data = null; + int size = ((bitsPerBand * w + + DataBuffer.getDataTypeSize(dataType) - 1) / + DataBuffer.getDataTypeSize(dataType)) * h; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size); + break; + } + return createPackedRaster(data, w, h, bitsPerBand, location); + } + + /** + * Creates a Raster object with a SinglePixelPackedSampleModel + * and the specified DataBuffer. + * + * @param dataType the data type of samples: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w the width of the image data. + * @param h the height of the image data. + * @param bandMasks the band masks. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(int dataType, int w, int h, + int bandMasks[], Point location) { + + if (dataType != DataBuffer.TYPE_BYTE + && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long) location.x + w > Integer.MAX_VALUE + || (long) location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bandMasks == null) { + // awt.27C=bandMasks is null + throw new NullPointerException(Messages.getString("awt.27C")); //$NON-NLS-1$ + } + + DataBuffer data = null; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(w * h); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(w * h); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(w * h); + break; + } + + return createPackedRaster(data, w, h, w, bandMasks, location); + } + + /** + * Creates a Raster object with the specified DataBuffer and SampleModel. + * + * @param sm the specified SampleModel. + * @param db the specified DataBuffer. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the Raster. + */ + public static Raster createRaster(SampleModel sm, DataBuffer db, + Point location) { + + if (sm == null || db == null) { + // awt.27F=SampleModel or DataBuffer is null + throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + return new Raster(sm, db, location); + } + + /** + * Creates a WritableRaster with the specified SampleModel and DataBuffer. + * + * @param sm the specified SampleModel. + * @param db the specified DataBuffer. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster. + */ + public static WritableRaster createWritableRaster(SampleModel sm, + DataBuffer db, Point location) { + + if (sm == null || db == null) { + // awt.27F=SampleModel or DataBuffer is null + throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + return new OrdinaryWritableRaster(sm, db, location); + } + + /** + * Creates a WritableRaster with the specified SampleModel. + * + * @param sm the specified SampleModel. + * @param location the location which defines the upper left corner + * of the Raster. + * + * @return the WritableRaster. + */ + public static WritableRaster createWritableRaster(SampleModel sm, + Point location) { + + if (sm == null) { + // awt.280=SampleModel is null + throw new NullPointerException(Messages.getString("awt.280")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + return createWritableRaster(sm, sm.createDataBuffer(), location); + } + + /** + * Instantiates a new Raster object with the specified SampleModel and + * DataBuffer. + * + * @param sampleModel the specified SampleModel. + * @param dataBuffer the specified DataBuffer. + * @param origin the specified origin. + */ + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, + Point origin) { + + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, + sampleModel.getWidth(), sampleModel.getHeight()), origin, null); + } + + /** + * Instantiates a new Raster object with the specified SampleModel, + * DataBuffer, rectangular region and parent Raster. + * + * @param sampleModel the specified SampleModel. + * @param dataBuffer the specified DataBuffer. + * @param aRegion the a rectangular region which defines the new image bounds. + * @param sampleModelTranslate this point defines the translation point + * from the SampleModel coordinates to the new Raster coordinates. + * @param parent the parent of this Raster. + */ + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, + Rectangle aRegion, Point sampleModelTranslate, Raster parent) { + + if (sampleModel == null || dataBuffer == null || aRegion == null + || sampleModelTranslate == null) { + // awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate is null + throw new NullPointerException(Messages.getString("awt.281")); //$NON-NLS-1$ + } + + if (aRegion.width <= 0 || aRegion.height <= 0) { + // awt.282=aRegion has width or height less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.282")); //$NON-NLS-1$ + } + + if ((long) aRegion.x + (long) aRegion.width > Integer.MAX_VALUE) { + // awt.283=Overflow X coordinate of Raster + throw new RasterFormatException(Messages.getString("awt.283")); //$NON-NLS-1$ + } + + if ((long) aRegion.y + (long) aRegion.height > Integer.MAX_VALUE) { + // awt.284=Overflow Y coordinate of Raster + throw new RasterFormatException(Messages.getString("awt.284")); //$NON-NLS-1$ + } + + if (sampleModel instanceof ComponentSampleModel) { + validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, + ((ComponentSampleModel) sampleModel).getScanlineStride()); + } else if (sampleModel instanceof MultiPixelPackedSampleModel) { + validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, + ((MultiPixelPackedSampleModel) sampleModel) + .getScanlineStride()); + } else if (sampleModel instanceof SinglePixelPackedSampleModel) { + validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, + ((SinglePixelPackedSampleModel) sampleModel) + .getScanlineStride()); + } + + this.sampleModel = sampleModel; + this.dataBuffer = dataBuffer; + this.minX = aRegion.x; + this.minY = aRegion.y; + this.width = aRegion.width; + this.height = aRegion.height; + this.sampleModelTranslateX = sampleModelTranslate.x; + this.sampleModelTranslateY = sampleModelTranslate.y; + this.parent = parent; + this.numBands = sampleModel.getNumBands(); + this.numDataElements = sampleModel.getNumDataElements(); + + } + + /** + * Instantiates a new Raster with the specified SampleModel. + * + * @param sampleModel the specified SampleModel. + * @param origin the origin. + */ + protected Raster(SampleModel sampleModel, Point origin) { + this(sampleModel, sampleModel.createDataBuffer(), new Rectangle( + origin.x, origin.y, sampleModel.getWidth(), sampleModel + .getHeight()), origin, null); + } + + /** + * Creates the child of this Raster by sharing the specified rectangular + * area in this Raste. The parentX, parentY, width + * and height parameters specify the rectangular area to be shared. + * + * @param parentX the X coordinate of the upper left corner of this Raster. + * @param parentY the Y coordinate of the upper left corner of this Raster. + * @param width the width of the child area. + * @param height the height of the child area. + * @param childMinX the X coordinate of child area mapped to the parentX + * coordinate. + * @param childMinY the Y coordinate of child area mapped to the parentY + * coordinate. + * @param bandList the array of band indicies. + * + * @return the Raster. + */ + public Raster createChild(int parentX, int parentY, int width, int height, + int childMinX, int childMinY, int bandList[]) { + if (width <= 0 || height <= 0) { + // awt.285=Width or Height of child Raster is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.285")); //$NON-NLS-1$ + } + + if (parentX < this.minX || parentX + width > this.minX + this.width) { + // awt.286=parentX disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.286")); //$NON-NLS-1$ + } + + if (parentY < this.minY || parentY + height > this.minY + this.height) { + // awt.287=parentY disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.287")); //$NON-NLS-1$ + } + + if ((long) parentX + width > Integer.MAX_VALUE) { + // awt.288=parentX + width results in integer overflow + throw new RasterFormatException(Messages.getString("awt.288")); //$NON-NLS-1$ + } + + if ((long) parentY + height > Integer.MAX_VALUE) { + // awt.289=parentY + height results in integer overflow + throw new RasterFormatException(Messages.getString("awt.289")); //$NON-NLS-1$ + } + + if ((long) childMinX + width > Integer.MAX_VALUE) { + // awt.28A=childMinX + width results in integer overflow + throw new RasterFormatException(Messages.getString("awt.28A")); //$NON-NLS-1$ + } + + if ((long) childMinY + height > Integer.MAX_VALUE) { + // awt.28B=childMinY + height results in integer overflow + throw new RasterFormatException(Messages.getString("awt.28B")); //$NON-NLS-1$ + } + + SampleModel childModel; + + if (bandList == null) { + childModel = sampleModel; + } else { + childModel = sampleModel.createSubsetSampleModel(bandList); + } + + int childTranslateX = childMinX - parentX; + int childTranslateY = childMinY - parentY; + + return new Raster(childModel, dataBuffer, new Rectangle(childMinX, + childMinY, width, height), new Point(childTranslateX + + sampleModelTranslateX, childTranslateY + + sampleModelTranslateY), this); + } + + /** + * Create a compatible WritableRaster with the same parameters + * as this Raster. + * + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster() { + return new OrdinaryWritableRaster(sampleModel, new Point(0, 0)); + } + + /** + * Create a compatible WritableRaster with the same parameters + * as this Raster and the specified size. + * + * @param w the width of the new WritableRaster. + * @param h the height of the new WritableRaster. + * + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster(int w, int h) { + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + SampleModel sm = sampleModel.createCompatibleSampleModel(w, h); + + return new OrdinaryWritableRaster(sm, new Point(0, 0)); + } + + /** + * Create a compatible WritableRaster with the same parameters + * as this Raster and the specified size and location. + * + * @param x the X coordinate of the new WritableRaster. + * @param y the Y coordinate of the new WritableRaster. + * @param w the width of the new WritableRaster. + * @param h the height of the new WritableRaster. + * + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster(int x, int y, int w, + int h) { + + WritableRaster raster = createCompatibleWritableRaster(w, h); + + return raster.createWritableChild(0, 0, w, h, x, y, null); + } + + /** + * Create a compatible WritableRaster with the same parameters + * as this Raster and the specified rectangle which determines + * new WritableRaster's location and size. + * + * @param rect the specified Rectangle. + * + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster(Rectangle rect) { + if (rect == null) { + // awt.28C=Rect is null + throw new NullPointerException(Messages.getString("awt.28C")); //$NON-NLS-1$ + } + + return createCompatibleWritableRaster(rect.x, rect.y, rect.width, + rect.height); + } + + /** + * Creates the translated child of this Raster. The New Raster + * object is a reference to the this Raster with a + * different location. + * + * @param childMinX the X coordinate of the new Raster. + * @param childMinY the Y coordinate of the new Raster. + * + * @return the Raster. + */ + public Raster createTranslatedChild(int childMinX, int childMinY) { + return createChild(minX, minY, width, height, childMinX, childMinY, + null); + } + + /** + * Gets the bounds of this Raster as a rectangle. + * + * @return the bounds of this Raster. + */ + public Rectangle getBounds() { + return new Rectangle(minX, minY, width, height); + } + + /** + * Gets the DataBuffer associated with this Raster. + * + * @return the DataBuffer associated with this Raster. + */ + public DataBuffer getDataBuffer() { + return dataBuffer; + } + + /** + * Gets the data elements which represent the pixel data of the specified + * rectangle area as a primitive array. The following image data types + * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, + * or DataBuffer.TYPE_DOUBLE. + * + * @param x the X coordinate of the area of pixels. + * @param y the Y coordinate of the area of pixels. + * @param w the width of the area of pixels. + * @param h the height of the area of pixels. + * @param outData the resulting array. + * + * @return the data elements of the specified area of this Raster. + */ + public Object getDataElements(int x, int y, int w, int h, Object outData) { + return sampleModel.getDataElements(x - sampleModelTranslateX, y + - sampleModelTranslateY, w, h, outData, dataBuffer); + } + + /** + * Gets the data elements which represent the specified pixel of + * this Raster as a primitive array. The following image data types + * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, + * or DataBuffer.TYPE_DOUBLE. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param outData the resulting data. + * + * @return the data elements of the specified pixel of this Raster. + */ + public Object getDataElements(int x, int y, Object outData) { + return sampleModel.getDataElements(x - sampleModelTranslateX, y + - sampleModelTranslateY, outData, dataBuffer); + } + + /** + * Gets the height of this Raster. + * + * @return the height of this Raster. + */ + public final int getHeight() { + return height; + } + + /** + * Gets the minimum X coordinate of this Raster. + * + * @return the minimum X coordinate of this Raster. + */ + public final int getMinX() { + return minX; + } + + /** + * Gets the minimum Y coordinate of this Raster. + * + * @return the minimum Y coordinate of this Raster. + */ + public final int getMinY() { + return minY; + } + + /** + * Gets the number of bands in this Raster. + * + * @return the number of bands in this Raster. + */ + public final int getNumBands() { + return numBands; + } + + /** + * Gets the number of data elements for one pixel. + * + * @return the number of data elements for one pixel. + */ + public final int getNumDataElements() { + return numDataElements; + } + + /** + * Gets the parent Raster for this Raster object. + * + * @return the parent Raster for this Raster object. + */ + public Raster getParent() { + return parent; + } + + /** + * Gets a double array of samples for the specified pixel in this Raster. + * + * @param x the pixel's X coordinate. + * @param y the pixel's Y coordinate. + * @param dArray the double array where result array will be stored. + * + * @return the double array of samples for the specified pixel in + * this Raster. + */ + public double[] getPixel(int x, int y, double dArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, y + - sampleModelTranslateY, dArray, dataBuffer); + } + + /** + * Gets a float array of samples for the specified pixel in this Raster. + * + * @param x the pixel's X coordinate. + * @param y the pixel's Y coordinate. + * @param fArray the float array where the result array will be stored. + * + * @return the float array of samples for the specified pixel in + * this Raster. + */ + public float[] getPixel(int x, int y, float fArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, y + - sampleModelTranslateY, fArray, dataBuffer); + } + + /** + * Gets an int array of samples for the specified pixel in this Raster. + * + * @param x the pixel's X coordinate. + * @param y the pixel's Y coordinate. + * @param iArray the int array where the result array will be stored. + * + * @return the int array of samples for the specified pixel in + * this Raster. + */ + public int[] getPixel(int x, int y, int iArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, y + - sampleModelTranslateY, iArray, dataBuffer); + } + + /** + * Gets an double array of samples for the specified rectangular + * area of pixels in this Raster. + * + * @param x the X coordinate of the area of pixels. + * @param y the Y coordinate of the area of pixels. + * @param w the width of the area of pixels. + * @param h the height of the area of pixels. + * @param dArray the resulting array. + * + * @return the double array of samples for the specified rectangular + * area of pixels in this Raster. + */ + public double[] getPixels(int x, int y, int w, int h, double dArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, y + - sampleModelTranslateY, w, h, dArray, dataBuffer); + } + + /** + * Gets an float array of samples for the specified rectangular + * area of pixels in this Raster. + * + * @param x the X coordinate of the area of pixels. + * @param y the Y coordinate of the area of pixels. + * @param w the width of the area of pixels. + * @param h the height of the area of pixels. + * @param fArray the resulting array. + * + * @return the float array of samples for the specified rectangular + * area of pixels in this Raster. + */ + public float[] getPixels(int x, int y, int w, int h, float fArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, y + - sampleModelTranslateY, w, h, fArray, dataBuffer); + } + + /** + * Gets an int array of samples for the specified rectangular + * area of pixels in this Raster. + * + * @param x the X coordinate of the area of pixels. + * @param y the Y coordinate of the area of pixels. + * @param w the width of pixel's the area of pixels. + * @param h the height of pixel's the area of pixels. + * @param iArray the resulting array. + * + * @return the int array of samples for the specified rectangular + * area of pixels in this Raster. + */ + public int[] getPixels(int x, int y, int w, int h, int iArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, y + - sampleModelTranslateY, w, h, iArray, dataBuffer); + } + + /** + * Gets the sample for the specified band of the specified + * pixel as an int. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the band. + * + * @return the sample for the specified band of the specified + * pixel as an int. + */ + public int getSample(int x, int y, int b) { + return sampleModel.getSample(x - sampleModelTranslateX, y + - sampleModelTranslateY, b, dataBuffer); + } + + /** + * Gets the sample for the specified band of the specified + * pixel as a double. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the band. + * + * @return the sample for the specified band of the specified + * pixel as a double. + */ + public double getSampleDouble(int x, int y, int b) { + return sampleModel.getSampleDouble(x - sampleModelTranslateX, y + - sampleModelTranslateY, b, dataBuffer); + } + + /** + * Gets the sample for the specified band of the specified + * pixel as a float. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the band. + * + * @return the sample for the specified band of the specified + * pixel as a float. + */ + public float getSampleFloat(int x, int y, int b) { + return sampleModel.getSampleFloat(x - sampleModelTranslateX, y + - sampleModelTranslateY, b, dataBuffer); + } + + /** + * Gets the SampleModel associated with this Raster. + * + * @return the SampleModel associated with this Raster. + */ + public SampleModel getSampleModel() { + return sampleModel; + } + + /** + * Gets the translation of the X coordinate from the SampleModel + * coordinate system to the Rasters's coordinate system. + * + * @return the value of the translation of the X coordinate from + * the SampleModel coordinate system to the Rasters's + * coordinate system. + */ + public final int getSampleModelTranslateX() { + return sampleModelTranslateX; + } + + /** + * Gets the translation of the Y coordinate from the SampleModel + * coordinate system to the Rasters's coordinate system. + * + * @return the value of the translation of the Y coordinate from + * the SampleModel coordinate system to the Rasters's + * coordinate system. + + */ + public final int getSampleModelTranslateY() { + return sampleModelTranslateY; + } + + /** + * Gets the double array of samples for the specified band + * of the specified rectangular area of pixels in this Raster + * as a double array. + * + * @param x the X coordinate of the rectangular area of pixels. + * @param y the Y coordinate of the rectangular area of pixels. + * @param w the width of the rectangular area of pixels. + * @param h the height of the rectangular area of pixels. + * @param b the band. + * @param dArray the resulting double array. + * + * @return the double array of samples for the specified band + * of the specified rectangular area of pixels. + */ + public double[] getSamples(int x, int y, int w, int h, int b, + double dArray[]) { + + return sampleModel.getSamples(x - sampleModelTranslateX, y + - sampleModelTranslateY, w, h, b, dArray, dataBuffer); + } + + /** + * Gets the float array of samples for the specified band + * of the specified rectangular area of pixels in this Raster + * as a float array. + * + * @param x the X coordinate of the rectangular area of pixels. + * @param y the Y coordinate of the rectangular area of pixels. + * @param w the width of the rectangular area of pixels. + * @param h the height of the rectangular area of pixels. + * @param b the band. + * @param fArray the resulting float array. + * + * @return the float array of samples for the specified band + * of the specified rectangular area of pixels. + */ + public float[] getSamples(int x, int y, int w, int h, int b, float fArray[]) { + + return sampleModel.getSamples(x - sampleModelTranslateX, y + - sampleModelTranslateY, w, h, b, fArray, dataBuffer); + } + + /** + * Gets the int array of samples for the specified band + * of the specified rectangular area of pixels in this Raster + * as a int array. + * + * @param x the X coordinate of the rectangular area of pixels. + * @param y the Y coordinate of the rectangular area of pixels. + * @param w the width of the rectangular area of pixels. + * @param h the height of the rectangular area of pixels. + * @param b the band. + * @param iArray the resulting int array. + * + * @return the int array of samples for the specified band + * of the specified rectangular area of pixels. + */ + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[]) { + return sampleModel.getSamples(x - sampleModelTranslateX, y + - sampleModelTranslateY, w, h, b, iArray, dataBuffer); + } + + /** + * Gets the transfer type for pixels of this Raster. + * @see SampleModel#getTransferType() + * + * @return the transfer type for pixels of this Raster. + */ + public final int getTransferType() { + return sampleModel.getTransferType(); + } + + /** + * Gets the width of this Raster. + * + * @return the width of this Raster. + */ + public final int getWidth() { + return width; + } + + /** + * Validate data buffer. + * + * @param dataBuffer the data buffer + * @param w the w + * @param h the h + * @param scanlineStride the scanline stride + */ + private static void validateDataBuffer(final DataBuffer dataBuffer, final int w, + final int h, final int scanlineStride) { + if (dataBuffer.getSize() < (scanlineStride * (h - 1) + w - 1)) { + // awt.298=dataBuffer is too small + throw new RasterFormatException(Messages.getString("awt.298")); //$NON-NLS-1$ + } + } +} + + diff --git a/awt/java/awt/image/RasterFormatException.java b/awt/java/awt/image/RasterFormatException.java new file mode 100644 index 0000000..8577dad --- /dev/null +++ b/awt/java/awt/image/RasterFormatException.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + + +/** + * The RasterFormatException class represents the exception + * that is thrown when there's an invalid layout + * in the Raster. + */ +public class RasterFormatException extends RuntimeException { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 96598996116164315L; + + /** + * Instantiates a new RasterFormatException with the + * specified detail message. + * + * @param s the detail message. + */ + public RasterFormatException(String s) { + super(s); + } + +} + diff --git a/awt/java/awt/image/RasterOp.java b/awt/java/awt/image/RasterOp.java new file mode 100644 index 0000000..e8933ee --- /dev/null +++ b/awt/java/awt/image/RasterOp.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * The RasterOp interface provides methods for performing transformations + * from source data to destination data for Raster objects. The source and + * destination objects should contain the appropriate number of bands for + * the particular classes which implement this interface. + */ +public interface RasterOp { + + /** + * Creates a destination WritableRaster with the specified Raster; + * this destination image data is empty and has the correct size + * and number of bands. + * + * @param src the source Raster. + * + * @return the WritableRaster. + */ + public WritableRaster createCompatibleDestRaster(Raster src); + + /** + * Performs a filter operation on the source Raster and stores the resulting + * image data to the destination WritableRaster. + * + * @param src the source Raster. + * @param dst the destination WritableRaster, where the result is stored. + * + * @return the filtered WritableRaster. + */ + public WritableRaster filter(Raster src, WritableRaster dst); + + /** + * Gets the bounds of the filtered Raster. + * + * @param src the source Raster to be filtered. + * + * @return the rectangle bounds of the filtered Raster. + */ + public Rectangle2D getBounds2D(Raster src); + + /** + * Gets the point of the destination image which corresponds + * to the specified point in the source raster. + * + * @param srcPoint the point of the source raster. + * @param dstPoint the point where the result will be stored. + * + * @return the destination point. + */ + public Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint); + + /** + * Gets the RenderingHints of the RasterOp. + * + * @return the RenderingHints of the RasterOp. + */ + public RenderingHints getRenderingHints(); +} diff --git a/awt/java/awt/image/RenderedImage.java b/awt/java/awt/image/RenderedImage.java new file mode 100644 index 0000000..db3a4c8 --- /dev/null +++ b/awt/java/awt/image/RenderedImage.java @@ -0,0 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Rectangle; +import java.util.Vector; + +/** + * The RenderedImage interface should be implemented by all objects which + * contains image data. The image data is represented as a single tile or + * an array of tiles. + */ +public interface RenderedImage { + + /** + * Gets the property with the specified name from the property set + * of this RenderedImage. + * + * @param name the property's name. + * + * @return the property value corresponded to this property's name. + */ + public Object getProperty(String name); + + /** + * Copies the region of this RenderedImage to the specified + * WritableRaster. The bounds of the region are the bounds of the + * WritableRaster. + * + * @param raster the WritableRaster. + * + * @return the created WritableRaster. + */ + public WritableRaster copyData(WritableRaster raster); + + /** + * Gets the image data of the image's region as one tile. + * + * @param rect the rectangular region of RenderedImage. + * + * @return the image data of the image's region as one tile. + */ + public Raster getData(Rectangle rect); + + /** + * Gets all RenderedImage objects which are the source of this + * RenderedImage object. + * + * @return a Vector of RenderedImage objects which are the source + * of this RenderedImage object or null, if there is no information + * about them. + */ + public Vector getSources(); + + /** + * Gets the set of all property names for this RenderedImage. + * + * @return the array of all property names for this RenderedImage. + */ + public String[] getPropertyNames(); + + /** + * Gets the SampleModel of this RenderedImage. + * + * @return the SampleModel of this RenderedImage. + */ + public SampleModel getSampleModel(); + + /** + * Gets the tile corresponded to the specified indices in the tile + * array. + * + * @param tileX the X index of the tile. + * @param tileY the Y index of the tile. + * + * @return the tile corresponded to the specified indices in the tile + * array. + */ + public Raster getTile(int tileX, int tileY); + + /** + * Gets the image data of this image as one tile. + * + * @return the image data of this image as one tile. + */ + public Raster getData(); + + /** + * Gets the ColorModel of this RenderedImage. + * + * @return the ColorModel of this RenderedImage. + */ + public ColorModel getColorModel(); + + /** + * Gets the width of the RenderedImage. + * + * @return the width of the RenderedImage. + */ + public int getWidth(); + + /** + * Gets the tile width. + * + * @return the tile width in pixels. + */ + public int getTileWidth(); + + /** + * Gets the tile height. + * + * @return the tile height in pixels. + */ + public int getTileHeight(); + + /** + * Gets the Y offset of the tile grid. + * + * @return the Y offset of the tile grid. + */ + public int getTileGridYOffset(); + + /** + * Gets the X offset of the tile grid. + * + * @return the X offset of the tile grid. + */ + public int getTileGridXOffset(); + + /** + * Gets the number of tiles along Y direction. + * + * @return the number of tiles along Y direction. + */ + public int getNumYTiles(); + + /** + * Gets the number of tiles along X direction. + * + * @return the number of tiles along X direction. + */ + public int getNumXTiles(); + + /** + * Gets the minimum Y coordinate of this RenderedImage. + * + * @return the minimum Y coordinate of this RenderedImage. + */ + public int getMinY(); + + /** + * Gets the minimum X coordinate of this RenderedImage. + * + * @return the minimum X coordinate of this RenderedImage. + */ + public int getMinX(); + + /** + * Gets the minimum tile's index along the Y direction. + * + * @return the minimum tile's index along the Y direction. + */ + public int getMinTileY(); + + /** + * Gets the minimum tile's index along the X direction. + * + * @return the minimum tile's index along the X direction. + */ + public int getMinTileX(); + + /** + * Gets the height of the RenderedImage. + * + * @return the height of the RenderedImage. + */ + public int getHeight(); + +} + diff --git a/awt/java/awt/image/ReplicateScaleFilter.java b/awt/java/awt/image/ReplicateScaleFilter.java new file mode 100644 index 0000000..9298125 --- /dev/null +++ b/awt/java/awt/image/ReplicateScaleFilter.java @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.util.Hashtable; + +import org.apache.harmony.awt.internal.nls.Messages; + + +/** + * The ReplicateScaleFilter class scales an source image + * by replicating rows and columns of pixels to scale up or + * omitting rows and columns of pixels to scale down. + */ +public class ReplicateScaleFilter extends ImageFilter { + + /** The width of a source image. */ + protected int srcWidth; + + /** The height of a source image. */ + protected int srcHeight; + + /** The width of a destination image. */ + protected int destWidth; + + /** The height of a destination image. */ + protected int destHeight; + + /** The int array of source rows. */ + protected int[] srcrows; + + /** The int array of source columns. */ + protected int[] srccols; + + /** + * An Object (byte array with a destination width) provides + * a row of pixel data to the ImageConsumer. + */ + protected Object outpixbuf; + + /** + * Instantiates a new ReplicateScaleFilter that filters + * the image with the specified width and height. + * + * @param width the width of scaled image. + * @param height the height of scaled image. + */ + public ReplicateScaleFilter(int width, int height) { + if(width == 0 || height == 0) { + // awt.234=Width or Height equals zero + throw new IllegalArgumentException(Messages.getString("awt.234")); //$NON-NLS-1$ + } + + this.destWidth = width; + this.destHeight = height; + } + + @SuppressWarnings("unchecked") + @Override + public void setProperties(Hashtable props) { + Hashtable fprops; + if(props == null) { + fprops = new Hashtable(); + } else { + fprops = (Hashtable) props.clone(); + } + String propName = "Rescale Filters"; //$NON-NLS-1$ + String prop = "destWidth=" + destWidth + "; " + //$NON-NLS-1$ //$NON-NLS-2$ + "destHeight=" + destHeight; //$NON-NLS-1$ + Object o = fprops.get(propName); + if(o != null){ + if(o instanceof String){ + prop = (String)o + "; " + prop; //$NON-NLS-1$ + }else{ + prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } + } + fprops.put(propName, prop); + consumer.setProperties(fprops); + } + + // setPixels methods produce pixels according to Java API Spacification + + @Override + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int off, int scansize) { + + if(srccols == null) { + initArrays(); + } + int buff[]; + if(outpixbuf == null || !(outpixbuf instanceof int[])){ + buff = new int[destWidth]; + outpixbuf = buff; + }else{ + buff = (int[])outpixbuf; + } + + int wa = (srcWidth - 1) >>> 1; + int ha = (srcHeight - 1) >>> 1; + int dstX = (x * destWidth + wa) / srcWidth; + int dstY = (y * destHeight + ha) / srcHeight; + + int sx, sy, dx, dy; + dy = dstY; + while((dy < destHeight) && ((sy = srcrows[dy]) < y + h)){ + dx = dstX; + int srcOff = off + (sy - y) * scansize; + while((dx < destWidth) && ((sx = srccols[dx]) < x + w)){ + buff[dx] = pixels[srcOff + (sx - x)]; + dx++; + } + + consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, + dstX, destWidth); + dy++; + } + } + + @Override + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int off, int scansize) { + + if(srccols == null) { + initArrays(); + } + byte buff[]; + if(outpixbuf == null || !(outpixbuf instanceof byte[])){ + buff = new byte[destWidth]; + outpixbuf = buff; + }else{ + buff = (byte[])outpixbuf; + } + + int wa = (srcWidth - 1) >>> 1; + int ha = (srcHeight - 1) >>> 1; + int dstX = (x * destWidth + wa) / srcWidth; + int dstY = (y * destHeight + ha) / srcHeight; + + int sx, sy, dx, dy; + dy = dstY; + while((dy < destHeight) && ((sy = srcrows[dy]) < y + h)){ + dx = dstX; + int srcOff = off + (sy - y) * scansize; + while((dx < destWidth) && ((sx = srccols[dx]) < x + w)){ + buff[dx] = pixels[srcOff + (sx - x)]; + dx++; + } + + consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, + dstX, destWidth); + dy++; + } + } + + @Override + public void setDimensions(int w, int h) { + srcWidth = w; + srcHeight = h; + + if(destWidth < 0 && destHeight < 0){ + destWidth = srcWidth; + destHeight = srcHeight; + }else if(destWidth < 0){ + destWidth = destHeight * srcWidth / srcHeight; + }else if(destHeight < 0){ + destHeight = destWidth * srcHeight / srcWidth; + } + consumer.setDimensions(destWidth, destHeight); + } + + /** + * Initialization of srccols and srcrows arrays. + */ + private void initArrays(){ + if ((destWidth < 0) || (destHeight < 0)) { + throw new IndexOutOfBoundsException(); + } + + srccols = new int[destWidth]; + int ca = srcWidth >>> 1; + for(int i = 0; i < destWidth; i++){ + srccols[i] = (i * srcWidth + ca) / destWidth; + } + + srcrows = new int[destHeight]; + int ra = srcHeight >>> 1; + for(int i = 0; i < destHeight; i++){ + srcrows[i] = (i * srcHeight + ra) / destHeight; + } + } + +} + + diff --git a/awt/java/awt/image/RescaleOp.java b/awt/java/awt/image/RescaleOp.java new file mode 100644 index 0000000..0e96031 --- /dev/null +++ b/awt/java/awt/image/RescaleOp.java @@ -0,0 +1,659 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 6, 2005 + */ + +package java.awt.image; + +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.*; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class RescaleOp performs rescaling of the source image data + * by multiplying the pixel values with a scale factor + * and then adding an offset. + */ +public class RescaleOp implements BufferedImageOp, RasterOp { + + /** The scale factors. */ + private float scaleFactors[]; + + /** The offsets. */ + private float offsets[]; + + /** The hints. */ + private RenderingHints hints; + + static { + // TODO + //System.loadLibrary("imageops"); + } + + /** + * Instantiates a new RescaleOp object with the specified + * scale factors and offsets. + * + * @param scaleFactors the array of scale factor values. + * @param offsets the array of offset values. + * @param hints the RenderingHints or null. + */ + public RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints) { + int numFactors = Math.min(scaleFactors.length, offsets.length); + + this.scaleFactors = new float[numFactors]; + this.offsets = new float[numFactors]; + + System.arraycopy(scaleFactors, 0, this.scaleFactors, 0, numFactors); + System.arraycopy(offsets, 0, this.offsets, 0, numFactors); + + this.hints = hints; + } + + /** + * Instantiates a new RescaleOp object with the specified + * scale factor and offset. + * + * @param scaleFactor the scale factor. + * @param offset the offset. + * @param hints the RenderingHints or null. + */ + public RescaleOp(float scaleFactor, float offset, RenderingHints hints) { + scaleFactors = new float[1]; + offsets = new float[1]; + + scaleFactors[0] = scaleFactor; + offsets[0] = offset; + + this.hints = hints; + } + + /** + * Gets the number of scaling factors. + * + * @return the number of scaling factors. + */ + public final int getNumFactors() { + return scaleFactors.length; + } + + public final RenderingHints getRenderingHints() { + return hints; + } + + /** + * Gets the scale factors of this RescaleOp. + * + * @param scaleFactors the desired scale factors array will be copied + * to this array. + * + * @return the scale factors array. + */ + public final float[] getScaleFactors(float[] scaleFactors) { + if (scaleFactors == null) { + scaleFactors = new float[this.scaleFactors.length]; + } + + int minLength = Math.min(scaleFactors.length, this.scaleFactors.length); + System.arraycopy(this.scaleFactors, 0, scaleFactors, 0, minLength); + return scaleFactors; + } + + /** + * Gets the offsets array of this RescaleOp. + * + * @param offsets the desired offsets array will be copied to this array. + * + * @return the offsets array of this RescaleOp. + */ + public final float[] getOffsets(float[] offsets) { + if (offsets == null) { + offsets = new float[this.offsets.length]; + } + + int minLength = Math.min(offsets.length, this.offsets.length); + System.arraycopy(this.offsets, 0, offsets, 0, minLength); + return offsets; + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt == null) { + dstPt = new Point2D.Float(); + } + + dstPt.setLocation(srcPt); + return dstPt; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { + if (dstCM == null) { + dstCM = src.getColorModel(); + } + + if (dstCM instanceof IndexColorModel) { + dstCM = ColorModel.getRGBdefault(); + } + + WritableRaster r = + dstCM.isCompatibleSampleModel(src.getSampleModel()) ? + src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : + dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage( + dstCM, + r, + dstCM.isAlphaPremultiplied(), + null + ); + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else { + if (src.getNumBands() != dst.getNumBands()) { + // awt.21D=Number of src bands ({0}) does not match number of dst bands ({1}) + throw new IllegalArgumentException(Messages.getString("awt.21D", //$NON-NLS-1$ + src.getNumBands(), dst.getNumBands())); + } + } + + if ( + this.scaleFactors.length != 1 && + this.scaleFactors.length != src.getNumBands() + ) { + // awt.21E=Number of scaling constants is not equal to the number of bands + throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ + } + + // TODO + //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0) + if (slowFilter(src, dst, false) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + /** + * Slow filter. + * + * @param src the src + * @param dst the dst + * @param skipAlpha the skip alpha + * + * @return the int + */ + private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) { + SampleModel sm = src.getSampleModel(); + + int numBands = src.getNumBands(); + int srcHeight = src.getHeight(); + int srcWidth = src.getWidth(); + + int srcMinX = src.getMinX(); + int srcMinY = src.getMinY(); + int dstMinX = dst.getMinX(); + int dstMinY = dst.getMinY(); + + int[] maxValues = new int[numBands]; + int[] masks = new int[numBands]; + int[] sampleSizes = sm.getSampleSize(); + + for (int i=0; i < numBands; i++){ + maxValues[i] = (1 << sampleSizes[i]) - 1; + masks[i] = ~(maxValues[i]); + } + + // Processing bounds + float[] pixels = null; + pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels); + + // Cycle over pixels to be calculated + if (skipAlpha) { // Always suppose that alpha channel is the last band + if (scaleFactors.length > 1) { + for (int i = 0; i < pixels.length; ){ + for (int bandIdx = 0; bandIdx < numBands-1; bandIdx++, i++){ + pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + + i++; + } + } else { + for (int i = 0; i < pixels.length; ){ + for (int bandIdx = 0; bandIdx < numBands-1; bandIdx++, i++){ + pixels[i] = pixels[i] * scaleFactors[0] + offsets[0]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + + i++; + } + } + } else { + if (scaleFactors.length > 1) { + for (int i = 0; i < pixels.length; ){ + for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++){ + pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + } + } else { + for (int i = 0; i < pixels.length; ){ + for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++){ + pixels[i] = pixels[i] * scaleFactors[0] + offsets[0]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + } + } + } + + dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, pixels); + + return 0; + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + ColorModel srcCM = src.getColorModel(); + + if (srcCM instanceof IndexColorModel) { + // awt.220=Source should not have IndexColorModel + throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$ + } + + // Check if the number of scaling factors matches the number of bands + int nComponents = srcCM.getNumComponents(); + boolean skipAlpha; + if (srcCM.hasAlpha()) { + if (scaleFactors.length == 1 || scaleFactors.length == nComponents-1) { + skipAlpha = true; + } else if (scaleFactors.length == nComponents) { + skipAlpha = false; + } else { + // awt.21E=Number of scaling constants is not equal to the number of bands + throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ + } + } else if (scaleFactors.length == 1 || scaleFactors.length == nComponents) { + skipAlpha = false; + } else { + // awt.21E=Number of scaling constants is not equal to the number of bands + throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ + } + + BufferedImage finalDst = null; + if (dst == null) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } else if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same + if ( + !((src.getType() == BufferedImage.TYPE_INT_RGB || + src.getType() == BufferedImage.TYPE_INT_ARGB) && + (dst.getType() == BufferedImage.TYPE_INT_RGB || + dst.getType() == BufferedImage.TYPE_INT_ARGB)) + ) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } + } + + // TODO + //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType(), skipAlpha) != 0) + if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return finalDst; + } + + // Don't forget to pass allocated arrays for levels and values, size should be numBands*4 + /** + * Creates the levels. + * + * @param sm the sm + * @param numBands the num bands + * @param skipAlpha the skip alpha + * @param levels the levels + * @param values the values + * @param channelsOrder the channels order + */ + private final void createLevels( + SampleModel sm, int numBands, boolean skipAlpha, + int levels[], int values[], int channelsOrder[] + ) { + // Suppose same sample size for all channels, otherwise use slow filter + int maxValue = (1 << sm.getSampleSize(0)) - 1; + + // For simplicity introduce these arrays + float extScaleFactors[] = new float[numBands]; + float extOffsets[] = new float[numBands]; + + if (scaleFactors.length != 1) { + System.arraycopy(scaleFactors, 0, extScaleFactors, 0, scaleFactors.length); + System.arraycopy(offsets, 0, extOffsets, 0, scaleFactors.length); + } else { + for (int i = 0; i < numBands; i++) { + extScaleFactors[i] = scaleFactors[0]; + extOffsets[i] = offsets[0]; + } + } + + if (skipAlpha) { + extScaleFactors[numBands-1] = 1; + extOffsets[numBands-1] = 0; + } + + // Create a levels + for (int i=0; i maxValue){ + minLevel = maxValue; + } + + if (maxLevel < 0) { + maxLevel = 0; + } else if (maxLevel > maxValue){ + maxLevel = maxValue; + } + + levels[i*4] = 0; + if (minLevel > maxLevel) { + levels[i*4+1] = (int) maxLevel; + levels[i*4+2] = (int) minLevel; + } else { + levels[i*4+1] = (int) minLevel; + levels[i*4+2] = (int) maxLevel; + } + levels[i*4+3] = maxValue+1; + + // Fill values + for (int k=0; k<4; k++) { + int idx = i*4+k; + values[idx] = (int) (extScaleFactors[i] * levels[idx] + extOffsets[i]); + if (values[idx] < 0) { + values[idx] = 0; + } else if (values[idx] > maxValue){ + values[idx] = maxValue; + } + } + } + + // Reorder data if channels are stored in different order + if (channelsOrder != null) { + int len = numBands*4; + int savedLevels[] = new int[len]; + int savedValues[] = new int[len]; + System.arraycopy(levels, 0, savedLevels, 0, len); + System.arraycopy(values, 0, savedValues, 0, len); + for (int i = 0; i < channelsOrder.length; i++) { + System.arraycopy(savedLevels, i*4, levels, channelsOrder[i]*4, 4); + System.arraycopy(savedValues, i*4, values, channelsOrder[i]*4, 4); + } + } + } + + // TODO remove when this method is used + /** + * Ipp filter. + * + * @param src the src + * @param dst the dst + * @param imageType the image type + * @param skipAlpha the skip alpha + * + * @return the int + */ + @SuppressWarnings("unused") + private final int ippFilter( + Raster src, WritableRaster dst, + int imageType, boolean skipAlpha + ) { + int res; + + int srcStride, dstStride; + int channels; + int offsets[] = null; + int channelsOrder[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_INT_RGB: { + channels = 4; + srcStride = src.getWidth()*4; + dstStride = dst.getWidth()*4; + channelsOrder = new int[] {2, 1, 0, 3}; + break; + } + + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth()*4; + dstStride = dst.getWidth()*4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth()*3; + dstStride = dst.getWidth()*3; + channelsOrder = new int[] {2, 1, 0}; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst, skipAlpha); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if ( + srcSM instanceof PixelInterleavedSampleModel && + dstSM instanceof PixelInterleavedSampleModel + ) { + // Check PixelInterleavedSampleModel + if ( + srcSM.getDataType() != DataBuffer.TYPE_BYTE || + dstSM.getDataType() != DataBuffer.TYPE_BYTE + ) { + return slowFilter(src, dst, skipAlpha); + } + + channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels + if (!(channels == 1 || channels == 3 || channels == 4)) { + return slowFilter(src, dst, skipAlpha); + } + + srcStride = ((ComponentSampleModel) srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel) dstSM).getScanlineStride(); + + channelsOrder = ((ComponentSampleModel) srcSM).getBandOffsets(); + } else if ( + srcSM instanceof SinglePixelPackedSampleModel && + dstSM instanceof SinglePixelPackedSampleModel + ) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM; + + channels = sppsm1.getNumBands(); + + // TYPE_INT_RGB, TYPE_INT_ARGB... + if ( + sppsm1.getDataType() != DataBuffer.TYPE_INT || + sppsm2.getDataType() != DataBuffer.TYPE_INT || + !(channels == 3 || channels == 4) + ) { + return slowFilter(src, dst, skipAlpha); + } + + // Check compatibility of sample models + if ( + !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) || + !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks()) + ) { + return slowFilter(src, dst, skipAlpha); + } + + for (int i=0; i + * The image data is represented as a Raster with a DataBuffer + * and a SampleModel. The SampleModel allows access to the samples in the + * DataBuffer. + */ +public abstract class SampleModel { + + /** The width of the image data which this SampleModel describes. */ + protected int width; + + /** The height of the image data which this SampleModel describes. */ + protected int height; + + /** The number of bands of image data which this SampleModel describes. */ + protected int numBands; + + /** The data type of the image data which this SampleModel describes. */ + protected int dataType; + + /** + * Instantiates a new SampleModel with the specified data type, + * width, height and number of bands. + * + * @param dataType the data type of the image data. + * @param w the width of the image data. + * @param h the height of the image data. + * @param numBands the number of bands of the image data. + */ + public SampleModel(int dataType, int w, int h, int numBands) { + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + double squre = ((double) w) * ((double) h); + if (squre >= Integer.MAX_VALUE) { + // awt.22F=The product of w and h is greater than Integer.MAX_VALUE + throw new IllegalArgumentException(Messages.getString("awt.22F")); //$NON-NLS-1$ + } + + if (dataType < DataBuffer.TYPE_BYTE || + dataType > DataBuffer.TYPE_DOUBLE && + dataType != DataBuffer.TYPE_UNDEFINED) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (numBands < 1) { + // awt.231=Number of bands must be more then 0 + throw new IllegalArgumentException(Messages.getString("awt.231")); //$NON-NLS-1$ + } + + this.dataType = dataType; + this.width = w; + this.height = h; + this.numBands = numBands; + + } + + /** + * Gets the data array for the specified pixel of the specified + * DataBuffer with one of the following types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param obj the Object is a data where the result will be stored. + * @param data the image data. + * + * @return the data array for the specified pixel of the specified + * DataBuffer. + */ + public abstract Object getDataElements(int x, int y, Object obj, + DataBuffer data); + + /** + * Gets the array of pixel data for the specified rectangular + * area of pixels of the specified DataBuffer with one of + * the following types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * + * @param x the X coordinate of the rectangular pixel area. + * @param y the Y coordinate of the rectangular pixel area. + * @param w the width of the rectangular pixel area. + * @param h the height of the rectangular pixel area. + * @param obj the Object is an array with the primitive type, + * where the result array will be stored. + * @param data the image data. + * + * @return the array of pixel data for the specified rectangular + * area of pixels of the specified DataBuffer object. + */ + public Object getDataElements(int x, int y, int w, int h, Object obj, + DataBuffer data) { + int numDataElements = getNumDataElements(); + int idx = 0; + + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + byte bbuf[] = null; + + if (obj == null) { + bdata = new byte[numDataElements * w * h]; + } else { + bdata = (byte[]) obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + bbuf = (byte[]) getDataElements(j, i, bbuf, data); + for (int n = 0; n < numDataElements; n++) { + bdata[idx++] = bbuf[n]; + } + } + } + obj = bdata; + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[]; + short sbuf[] = null; + + if (obj == null) { + sdata = new short[numDataElements * w * h]; + } else { + sdata = (short[]) obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + sbuf = (short[]) getDataElements(j, i, sbuf, data); + for (int n = 0; n < numDataElements; n++) { + sdata[idx++] = sbuf[n]; + } + } + } + obj = sdata; + break; + + case DataBuffer.TYPE_INT: + int idata[]; + int ibuf[] = null; + + if (obj == null) { + idata = new int[numDataElements * w * h]; + } else { + idata = (int[]) obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + ibuf = (int[]) getDataElements(j, i, ibuf, data); + for (int n = 0; n < numDataElements; n++) { + idata[idx++] = ibuf[n]; + } + } + } + obj = idata; + break; + + case DataBuffer.TYPE_FLOAT: + float fdata[]; + float fbuf[] = null; + + if (obj == null) { + fdata = new float[numDataElements * w * h]; + } else { + fdata = (float[]) obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + fbuf = (float[]) getDataElements(j, i, fbuf, data); + for (int n = 0; n < numDataElements; n++) { + fdata[idx++] = fbuf[n]; + } + } + } + obj = fdata; + break; + + case DataBuffer.TYPE_DOUBLE: + double ddata[]; + double dbuf[] = null; + + if (obj == null) { + ddata = new double[numDataElements * w * h]; + } else { + ddata = (double[]) obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + dbuf = (double[]) getDataElements(j, i, dbuf, data); + for (int n = 0; n < numDataElements; n++) { + ddata[idx++] = dbuf[n]; + } + } + } + obj = ddata; + break; + + } + + return obj; + } + + /** + * Sets the data for a single pixel in the specified DataBuffer + * from a primitive array with one of the following types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param obj the Object - the array of primitive pixel data + * to be set. + * @param data the image data. + */ + public abstract void setDataElements(int x, int y, Object obj, + DataBuffer data); + + /** + * Sets the data elements for a rectangular area of pixels in + * the specified DataBuffer from a primitive array with one of + * the following types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x the X coordinate of the specified rectangular area. + * @param y the Y coordinate of the specified rectangular area. + * @param w the width of rectangle. + * @param h the height of rectangle. + * @param obj the Object - the array of primitive pixel data + * to be set. + * @param data the image data. + */ + public void setDataElements(int x, int y, int w, int h, Object obj, + DataBuffer data) { + int numDataElements = getNumDataElements(); + int idx = 0; + + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bbuf[] = new byte[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + bbuf[n] = ((byte[]) obj)[idx++]; + } + setDataElements(j, i, bbuf, data); + } + } + + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sbuf[] = new short[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + sbuf[n] = ((short[]) obj)[idx++]; + } + setDataElements(j, i, sbuf, data); + } + } + break; + + case DataBuffer.TYPE_INT: + int ibuf[] = new int[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + ibuf[n] = ((int[]) obj)[idx++]; + } + setDataElements(j, i, ibuf, data); + } + } + break; + + case DataBuffer.TYPE_FLOAT: + float fbuf[] = new float[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + fbuf[n] = ((float[]) obj)[idx++]; + } + setDataElements(j, i, fbuf, data); + } + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dbuf[] = new double[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + dbuf[n] = ((double[]) obj)[idx++]; + } + setDataElements(j, i, dbuf, data); + } + } + break; + + } + } + + /** + * Creates a new SampleModel with the specified bands of + * this SampleModel. + * + * @param bands the array of bands from this SampleModel. + * + * @return the SampleModel with the specified bands of + * this SampleModel. + */ + public abstract SampleModel createSubsetSampleModel(int bands[]); + + /** + * Creates the SampleModel which has the same data as in + * this SampleModel with a different width and height. + * + * @param a0 the width of the image data. + * @param a1 the height of the image data. + * + * @return the SampleModel which has the same data as in + * this SampleModel with a different width and height. + */ + public abstract SampleModel createCompatibleSampleModel(int a0, int a1); + + /** + * Gets the samples of the specified pixel as a int array. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param iArray the int array where result will be stored. + * @param data the image data. + * + * @return the int array with the samples of the specified pixel. + + */ + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixel[]; + + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + /** + * Sets a pixel of the DataBuffer from a int array of samples. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param iArray the int array. + * @param data the image data. + */ + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + /** + * Gets the samples of the specified pixel as a float array. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param fArray the float array where result will be stored. + * @param data the image data. + * + * @return the float array with the samples of the specified pixel. + */ + public float[] getPixel(int x, int y, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + float pixel[]; + + if (fArray == null) { + pixel = new float[numBands]; + } else { + pixel = fArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSampleFloat(x, y, i, data); + } + + return pixel; + } + + /** + * Sets a pixel of the DataBuffer from a float array of samples. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param fArray the float array. + * @param data the image data. + */ + public void setPixel(int x, int y, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, fArray[i], data); + } + } + + /** + * Gets the samples of the specified pixel as a double array. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param dArray the double array where result will be stored. + * @param data the image data. + * + * @return the double array with the samples of the specified pixel. + */ + public double[] getPixel(int x, int y, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + double pixel[]; + + if (dArray == null) { + pixel = new double[numBands]; + } else { + pixel = dArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSampleDouble(x, y, i, data); + } + + return pixel; + } + + /** + * Sets a pixel of the DataBuffer from a double array of samples. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param dArray the double array. + * @param data the image data. + */ + public void setPixel(int x, int y, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, dArray[i], data); + } + } + + /** + * Gets the sample of a specified band for the specified pixel + * as an int. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param b the specified band. + * @param data the image data. + * + * @return the sample of a specified band for the specified pixel. + */ + public abstract int getSample(int x, int y, int b, DataBuffer data); + + /** + * Gets the sample of a specified band for the specified pixel + * as a float. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param b the specified band. + * @param data the image data. + * + * @return the sample of a specified band for the specified pixel. + + */ + public float getSampleFloat(int x, int y, int b, DataBuffer data) { + return getSample(x, y, b, data); + } + + /** + * Gets the sample of a specified band for the specified pixel + * as a double. + * + * @param x the X coordinate of pixel. + * @param y the Y coordinate of pixel. + * @param b the specified band. + * @param data the image data. + * + * @return the sample of a specified band for the specified pixel. + */ + public double getSampleDouble(int x, int y, int b, DataBuffer data) { + return getSample(x, y, b, data); + } + + /** + * Gets the samples of the specified rectangular area of pixels + * as a int array. + * + * @param x the X coordinate of the rectangle of pixels. + * @param y the Y coordinate of the rectangle of pixels. + * @param w the width of the rectangle of pixels. + * @param h the height of the rectangle of pixels. + * @param iArray the int array where result will be stored. + * @param data the image data. + * + * @return the int array with the samples of the specified + * rectangular area of pixels. + */ + public int[] getPixels(int x, int y, int w, int h, int iArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixels[]; + int idx = 0; + + if (iArray == null) { + pixels = new int[w * h * numBands]; + } else { + pixels = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSample(j, i, n, data); + } + } + } + return pixels; + } + + /** + * Sets all of the samples for a rectangular area of pixels of the DataBuffer + * from an int array. + * + * @param x the X coordinate of the rectangle of pixels. + * @param y the Y coordinate of the rectangle of pixels. + * @param w the width of the rectangle of pixels. + * @param h the height of the rectangle of pixels. + * @param iArray the int array. + * @param data the image data. + */ + public void setPixels(int x, int y, int w, int h, int iArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + /** + * Gets the samples of the specified rectangular area of pixels + * as a float array. + * + * @param x the X coordinate of the rectangle of pixels. + * @param y the Y coordinate of the rectangle of pixels. + * @param w the width of the rectangle of pixels. + * @param h the height of the rectangle of pixels. + * @param fArray the float array where result will be stored. + * @param data the image data. + * + * @return the float array with the samples of the specified + * rectangular area of pixels. + */ + public float[] getPixels(int x, int y, int w, int h, float fArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + float pixels[]; + int idx = 0; + + if (fArray == null) { + pixels = new float[w * h * numBands]; + } else { + pixels = fArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSampleFloat(j, i, n, data); + } + } + } + return pixels; + } + + /** + * Sets all of the samples for a rectangular area of pixels of the DataBuffer + * from a float array. + * + * @param x the X coordinate of the rectangle of pixels. + * @param y the Y coordinate of the rectangle of pixels. + * @param w the width of the rectangle of pixels. + * @param h the height of the rectangle of pixels. + * @param fArray the float array. + * @param data the image data. + */ + public void setPixels(int x, int y, int w, int h, float fArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, fArray[idx++], data); + } + } + } + } + + /** + * Gets the samples of the specified rectangular area of pixels + * as a double array. + * + * @param x the X coordinate of the rectangle of pixels. + * @param y the Y coordinate of the rectangle of pixels. + * @param w the width of the rectangle of pixels. + * @param h the height of the rectangle of pixels. + * @param dArray the double array where result will be stored. + * @param data the image data. + * + * @return the double array with the samples of the specified + * rectangular area of pixels. + */ + public double[] getPixels(int x, int y, int w, int h, double dArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + double pixels[]; + int idx = 0; + + if (dArray == null) { + pixels = new double[w * h * numBands]; + } else { + pixels = dArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSampleDouble(j, i, n, data); + } + } + } + return pixels; + } + + /** + * Sets all of the samples for a rectangular area of pixels of the DataBuffer + * from a double array. + * + * @param x the X coordinate of the rectangle of pixels. + * @param y the Y coordinate of the rectangle of pixels. + * @param w the width of the rectangle of pixels. + * @param h the height of the rectangle of pixels. + * @param dArray the double array. + * @param data the image data. + */ + public void setPixels(int x, int y, int w, int h, double dArray[], + DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, dArray[idx++], data); + } + } + } + } + + /** + * Sets a sample of the specified band for the specified pixel + * in the DataBuffer as int value. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the specified band. + * @param s the sample as an int value. + * @param data the image data. + */ + public abstract void setSample(int x, int y, int b, int s, DataBuffer data); + + /** + * Gets the samples of a specified band for a specified rectangular + * area of pixels as a int array. + * + * @param x the X coordinate of the rectangle. + * @param y the Y coordinate of the rectangle. + * @param w the width of the rectangle. + * @param h the height of the rectangle. + * @param b the specified band. + * @param iArray the int array where result will be stored. + * @param data the image data. + * + * @return the samples of a specified band for a specified rectangular + * area of pixels. + */ + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], + DataBuffer data) { + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + /** + * Sets the samples from an int array in the specified band for + * the specified rectangle of pixels. + * + * @param x the X coordinate of the rectangle. + * @param y the Y coordinate of the rectangle. + * @param w the width of the rectangle. + * @param h the height of the rectangle. + * @param b the specified band. + * @param iArray the int array. + * @param data the image data. + */ + public void setSamples(int x, int y, int w, int h, int b, int iArray[], + DataBuffer data) { + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, iArray[idx++], data); + } + } + } + + /** + * Gets the samples of a specified band for a specified rectangular + * area of pixels as a float array. + * + * @param x the X coordinate of the rectangle. + * @param y the Y coordinate of the rectangle. + * @param w the width of the rectangle. + * @param h the height of the rectangle. + * @param b the specified band. + * @param fArray the float array where result will be stored. + * @param data the image data. + * + * @return the samples of a specified band for a specified rectangular + * area of pixels. + */ + public float[] getSamples(int x, int y, int w, int h, int b, + float fArray[], DataBuffer data) { + float samples[]; + int idx = 0; + + if (fArray == null) { + samples = new float[w * h]; + } else { + samples = fArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSampleFloat(j, i, b, data); + } + } + + return samples; + } + + /** + * Sets the samples from an float array in the specified band for + * the specified rectangle of pixels. + * + * @param x the X coordinate of the rectangle. + * @param y the Y coordinate of the rectangle. + * @param w the width of the rectangle. + * @param h the height of the rectangle. + * @param b the specified band. + * @param fArray the float array + * @param data the image data. + */ + public void setSamples(int x, int y, int w, int h, int b, float fArray[], + DataBuffer data) { + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, fArray[idx++], data); + } + } + } + + /** + * Gets the samples of a specified band for a specified rectangular + * area of pixels as a double array. + * + * @param x the X coordinate of the rectangle. + * @param y the Y coordinate of the rectangle. + * @param w the width of the rectangle. + * @param h the height of the rectangle. + * @param b the specified band. + * @param dArray the double array where result will be stored. + * @param data the image data. + * + * @return the samples of a specified band for a specified rectangular + * area of pixels. + */ + public double[] getSamples(int x, int y, int w, int h, int b, + double dArray[], DataBuffer data) { + double samples[]; + int idx = 0; + + if (dArray == null) { + samples = new double[w * h]; + } else { + samples = dArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSampleDouble(j, i, b, data); + } + } + + return samples; + } + + /** + * Sets the samples from an double array in the specified band for + * the specified rectangle of pixels. + * + * @param x the X coordinate of the rectangle. + * @param y the Y coordinate of the rectangle. + * @param w the width of the rectangle. + * @param h the height of the rectangle. + * @param b the specified band. + * @param dArray the double array + * @param data the image data. + */ + public void setSamples(int x, int y, int w, int h, int b, double dArray[], + DataBuffer data) { + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, dArray[idx++], data); + } + } + } + + /** + * Sets a sample of the specified band for the specified pixel + * in the DataBuffer as float value. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the specified band. + * @param s the sample as float value. + * @param data the image data. + */ + public void setSample(int x, int y, int b, float s, DataBuffer data) { + setSample(x, y, b, (int) s, data); + } + + /** + * Sets a sample of the specified band for the specified pixel + * in the DataBuffer as double value. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the specified band. + * @param s the sample as double value. + * @param data the image data. + */ + public void setSample(int x, int y, int b, double s, DataBuffer data) { + setSample(x, y, b, (int) s, data); + } + + /** + * Creates a DataBuffer object which corresponds to the SampleModel. + * + * @return the DataBuffer object which corresponds to + * the SampleModel. + */ + public abstract DataBuffer createDataBuffer(); + + /** + * Gets the sample size in bits for the specified band. + * + * @param band the specified band. + * + * @return the sample size in bits for the specified band. + */ + public abstract int getSampleSize(int band); + + /** + * Gets an array of the sample size in bits for all bands. + * + * @return an array of the sample size in bits for all bands. + */ + public abstract int[] getSampleSize(); + + /** + * Gets the width of the image data of this SampleModel object. + * + * @return the width of the image data of this SampleModel object. + */ + public final int getWidth() { + return width; + } + + /** + * Gets the transfer type used to transfer pixels via + * the getDataElements and setDataElements methods. + * Transfer type value can be one of the predefined type + * from DataBuffer class or not. + * + * @return the transfer type. + */ + public int getTransferType() { + return dataType; + } + + /** + * Returns the number of data elements for pixel transfering + * via the getDataElements and setDataElements methods. + * + * @return the number of data elements for pixel transfering + * via the getDataElements and setDataElements methods. + */ + public abstract int getNumDataElements(); + + /** + * Gets the number of bands in the image data of this + * SampleModel object. + * + * @return the number of bands in the image data of this + * SampleModel object. + */ + public final int getNumBands() { + return numBands; + } + + /** + * Gets the height of the image data of this SampleModel object. + * + * @return the height of the image data of this SampleModel object. + */ + public final int getHeight() { + return height; + } + + /** + * Gets the data type of image data of this SampleModel object. + * + * @return the data type of image data of this SampleModel object. + */ + public final int getDataType() { + return dataType; + } + +} + diff --git a/awt/java/awt/image/ShortLookupTable.java b/awt/java/awt/image/ShortLookupTable.java new file mode 100644 index 0000000..77c9c45 --- /dev/null +++ b/awt/java/awt/image/ShortLookupTable.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + + +/** + * The ShortLookupTable class provides provides functionality for + * lookup operations, and is defined by an input short array for + * bands or components of image and an offset value. + * The offset value will be subtracted from the input values before + * indexing the input arrays. The output of a lookup operation is + * represented as an unsigned short array. + */ +public class ShortLookupTable extends LookupTable { + + /** The data. */ + private short data[][]; + + /** + * Instantiates a new ShortLookupTable with the specified offset value + * and the specified short array which represents lookup table for + * all bands. + * + * @param offset the offset value. + * @param data the data array. + */ + public ShortLookupTable(int offset, short[] data) { + super(offset, 1); + this.data = new short[1][data.length]; + // The data array stored as a reference + this.data[0] = data; + } + + /** + * Instantiates a new ShortLookupTable with the specified offset value + * and the specified short array of arrays which represents lookup table + * for each band. + * + * @param offset the offset value. + * @param data the data array of arrays for each band. + */ + public ShortLookupTable(int offset, short[][] data) { + super(offset, data.length); + this.data = new short[data.length][data[0].length]; + for (int i = 0; i < data.length; i++) { + // The data array for each band stored as a reference + this.data[i] = data[i]; + } + } + + /** + * Gets the lookup table of this ShortLookupTable object. If + * this ShortLookupTable object has one short array for all bands, + * the returned array length is one. + * + * @return the lookup table of this ShortLookupTable object. + */ + public final short[][] getTable() { + return data; + } + + /** + * Returns a short array which contains samples of the specified + * pixel which is translated with the lookup table of this + * ShortLookupTable object. The resulted array is stored to + * the dst array. + * + * @param src the source array. + * @param dst the destination array where the result can be stored. + * + * @return the short array of translated samples of a pixel. + */ + public short[] lookupPixel(short[] src, short[] dst) { + if (dst == null) { + dst = new short[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i]-offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i]-offset]; + } + } + + return dst; + } + + @Override + public int[] lookupPixel(int[] src, int[] dst) { + if (dst == null) { + dst = new int[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i]-offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i]-offset]; + } + } + + return dst; + } +} diff --git a/awt/java/awt/image/SinglePixelPackedSampleModel.java b/awt/java/awt/image/SinglePixelPackedSampleModel.java new file mode 100644 index 0000000..311395a --- /dev/null +++ b/awt/java/awt/image/SinglePixelPackedSampleModel.java @@ -0,0 +1,508 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The SinglePixelPackedSampleModel class represents pixel data + * where several samples combine to create a single pixel and + * are stored in a single data array element. This class + * supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data types. + */ +public class SinglePixelPackedSampleModel extends SampleModel { + + /** The bit masks. */ + private int bitMasks[]; + + /** The bit offsets. */ + private int bitOffsets[]; + + /** The bit sizes. */ + private int bitSizes[]; + + /** The scanline stride. */ + private int scanlineStride; + + /** The max bit size. */ + private int maxBitSize; + + /** + * Instantiates a new SinglePixelPackedSampleModel with the specified + * parameters. + * + * @param dataType the data type of samples. + * @param w the width of the image data. + * @param h the height of the image data. + * @param bitMasks the bit masks for all the bands. + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, + int bitMasks[]) { + this(dataType, w, h, w, bitMasks); + } + + /** + * Instantiates a new SinglePixelPackedSampleModel with the specified + * parameters. + * + * @param dataType the data type of the samples. + * @param w the width of the image data. + * @param h the height of the image data. + * @param scanlineStride The scanline stride of the image data. + * @param bitMasks the bit masks for all the bands. + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, + int scanlineStride, int bitMasks[]) { + + super(dataType, w, h, bitMasks.length); + + if (dataType != DataBuffer.TYPE_BYTE && + dataType != DataBuffer.TYPE_USHORT && + dataType != DataBuffer.TYPE_INT) { + // awt.61=Unsupported data type: {0} + throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$ + dataType)); + } + + this.scanlineStride = scanlineStride; + this.bitMasks = bitMasks.clone(); + this.bitOffsets = new int[this.numBands]; + this.bitSizes = new int[this.numBands]; + + this.maxBitSize = 0; + + for (int i = 0; i < this.numBands; i++) { + int offset = 0; + int size = 0; + int mask = bitMasks[i]; + + if (mask != 0) { + while ((mask & 1) == 0) { + mask >>>= 1; + offset++; + } + + while ((mask & 1) == 1) { + mask >>>= 1; + size++; + } + + if (mask != 0) { + // awt.62=Wrong mask : {0} + throw new IllegalArgumentException(Messages.getString( + "awt.62", bitMasks[i])); //$NON-NLS-1$ + } + } + + this.bitOffsets[i] = offset; + this.bitSizes[i] = size; + + if (this.maxBitSize < size) { + this.maxBitSize = size; + } + + } + + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[1]; + } else { + bdata = (byte[]) obj; + } + + bdata[0] = (byte) data.getElem(y * scanlineStride + x); + obj = bdata; + break; + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[1]; + } else { + sdata = (short[]) obj; + } + + sdata[0] = (short) data.getElem(y * scanlineStride + x); + obj = sdata; + break; + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[1]; + } else { + idata = (int[]) obj; + } + + idata[0] = data.getElem(y * scanlineStride + x); + obj = idata; + break; + } + return obj; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + data.setElem(y * scanlineStride + x, ((byte[]) obj)[0] & 0xff); + break; + case DataBuffer.TYPE_USHORT: + data.setElem(y * scanlineStride + x, ((short[]) obj)[0] & 0xffff); + break; + case DataBuffer.TYPE_INT: + data.setElem(y * scanlineStride + x, ((int[]) obj)[0]); + break; + } + } + + /** + * Compares this SinglePixelPackedSampleModel object with + * the specified object. + * + * @param o the Object to be compared. + * + * @return true, if this SinglePixelPackedSampleModel object is + * equal to the specified object, false otherwise. + */ + @Override + public boolean equals(Object o) { + if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) { + return false; + } + + SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel) o; + return this.width == model.width && + this.height == model.height && + this.numBands == model.numBands && + this.dataType == model.dataType && + Arrays.equals(this.bitMasks, model.bitMasks) && + Arrays.equals(this.bitOffsets, model.bitOffsets) && + Arrays.equals(this.bitSizes, model.bitSizes) && + this.scanlineStride == model.scanlineStride; + } + + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands.length > this.numBands) { + // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model + throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ + } + + int masks[] = new int[bands.length]; + for (int i = 0; i < bands.length; i++) { + masks[i] = this.bitMasks[bands[i]]; + } + return new SinglePixelPackedSampleModel(this.dataType, this.width, + this.height, this.scanlineStride, masks); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new SinglePixelPackedSampleModel(this.dataType, w, h, + this.bitMasks); + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixel[]; + if (iArray == null) { + pixel = new int[this.numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < this.numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < this.numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int sample = data.getElem(y * scanlineStride + x); + return ((sample & this.bitMasks[b]) >>> this.bitOffsets[b]); + } + + @Override + public int[] getPixels(int x, int y, int w, int h, int iArray[], + DataBuffer data) { + if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width) + || ((long) y + (long) h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int pixels[]; + + if (iArray == null) { + pixels = new int[w * h * this.numBands]; + } else { + pixels = iArray; + } + + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < this.numBands; n++) { + pixels[idx++] = getSample(j, i, n, data); + } + } + } + return pixels; + } + + @Override + public void setPixels(int x, int y, int w, int h, int iArray[], + DataBuffer data) { + if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width) + || ((long) y + (long) h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages + .getString("awt.63")); //$NON-NLS-1$ + } + + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < this.numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int tmp = data.getElem(y * scanlineStride + x); + tmp &= ~this.bitMasks[b]; + tmp |= (s << this.bitOffsets[b]) & this.bitMasks[b]; + data.setElem(y * scanlineStride + x, tmp); + } + + @Override + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], + DataBuffer data) { + if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width) + || ((long) y + (long) h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages + .getString("awt.63")); //$NON-NLS-1$ + } + + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int iArray[], + DataBuffer data) { + if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width) + || ((long) y + (long) h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(x + j, y + i, b, iArray[idx++], data); + } + } + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer data = null; + int size = (this.height - 1) * scanlineStride + width; + + switch (this.dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size); + break; + } + return data; + } + + /** + * Gets the offset of the specified pixel in the data array. + * + * @param x the X coordinate of the specified pixel. + * @param y the Y coordinate of the specified pixel. + * + * @return the offset of the specified pixel. + */ + public int getOffset(int x, int y) { + return (y * scanlineStride + x); + } + + @Override + public int getSampleSize(int band) { + return bitSizes[band]; + } + + @Override + public int[] getSampleSize() { + return bitSizes.clone(); + } + + /** + * Gets an array of the bit offsets of the data array elements. + * + * @return an array of the bit offsets. + */ + public int[] getBitOffsets() { + return bitOffsets.clone(); + } + + /** + * Gets an array of the bit masks for all bands. + * + * @return an array of the bit masks for all bands. + */ + public int[] getBitMasks() { + return bitMasks.clone(); + } + + /** + * Returns a hash code of this MultiPixelPackedSampleModel class. + * + * @return the hash code of this MultiPixelPackedSampleModel class. + */ + @Override + public int hashCode() { + int hash = 0; + int tmp = 0; + + hash = width; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= height; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= numBands; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataType; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + for (int element : bitMasks) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + for (int element : bitOffsets) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + for (int element : bitSizes) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + hash ^= scanlineStride; + return hash; + } + + /** + * Gets the scanline stride. + * + * @return the scanline stride + */ + public int getScanlineStride() { + return this.scanlineStride; + } + + @Override + public int getNumDataElements() { + return 1; + } + +} + diff --git a/awt/java/awt/image/TileObserver.java b/awt/java/awt/image/TileObserver.java new file mode 100644 index 0000000..39ded02 --- /dev/null +++ b/awt/java/awt/image/TileObserver.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + + +/** + * An asynchronous update interface for receiving notifications + * about tile information when tiles of a WritableRenderedImage + * become modifiable or unmodifiable. + */ +public interface TileObserver { + + /** + * This method is called when information about a tile + * update is available. + * + * @param source the source image. + * @param tileX the X index of the tile. + * @param tileY the Y index of the tile. + * @param willBeWritable parameter which indicates whether + * the tile will be grabbed for writing or be released. + */ + public void tileUpdate(WritableRenderedImage source, int tileX, int tileY, boolean willBeWritable); + +} + diff --git a/awt/java/awt/image/VolatileImage.java b/awt/java/awt/image/VolatileImage.java new file mode 100644 index 0000000..3b0cfb2 --- /dev/null +++ b/awt/java/awt/image/VolatileImage.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.ImageCapabilities; +import java.awt.Transparency; + +/** + * The VolatileImage abstract class represents an image which can lose + * its contents at any point. VolatileImage objects are device specific. + * This class provies methods for checking if operation of this image + * are compatible for the GraphicsConfiguration. + */ +public abstract class VolatileImage extends Image + // Volatile image implements Transparency since 1.5 + implements Transparency { + + /** + * The Constant IMAGE_INCOMPATIBLE indicates that this VolatileImage + * is not applicable for the GraphicsConfiguration object. + */ + public static final int IMAGE_INCOMPATIBLE = 2; + + /** + * The Constant IMAGE_OK indicates that VolatileImage is ready + * for using. + */ + public static final int IMAGE_OK = 0; + + /** + * The Constant IMAGE_RESTORED indicates that VolatileImage + * will be ready to use after restoring. + */ + public static final int IMAGE_RESTORED = 1; + + /** + * The transparency value of this image. + */ + protected int transparency = OPAQUE; + + /** + * Instantiates a new VolatileImage object. + */ + public VolatileImage() { + super(); + } + + /** + * Returns true if rendering data is lost during validating. + * This method should be called after rendering operation of image. + * + * @return true, if contents lost during validating, false otherwise. + */ + + public abstract boolean contentsLost(); + + /** + * Creates a Graphics2D used to draw in this VolatileImage. + * + * @return the Graphics2D object. + */ + public abstract Graphics2D createGraphics(); + + /** + * Gets the ImageCapabilities of this VolatileImage. + * + * @return the ImageCapabilities of this VolatileImage. + */ + public abstract ImageCapabilities getCapabilities(); + + /** + * Gets the height of this VolatileImage. + * + * @return the height of this VolatileImage. + */ + public abstract int getHeight(); + + /** + * Gets a BufferedImage representation of current VolatileImage that + * won't be affected by any changes to this VolatileImage. + * + * @return a BufferedImage representation of current VolatileImage. + */ + public abstract BufferedImage getSnapshot(); + + /** + * Gets the width of this VolatileImage. + * + * @return the width of this VolatileImage. + */ + public abstract int getWidth(); + + /** + * Validates the drawing surface of the image if the surface had been + * lost and if the spacified GraphicsConfiguration object is + * applicable to this image. + * + * @param gc GraphicsConfiguration object. + * + * @return one of the image status constants: IMAGE_OK, IMAGE_RESTORED or + * IMAGE_INCOMPATIBLE. + */ + public abstract int validate(GraphicsConfiguration gc); + + @Override + public void flush() { + } + + @Override + public Graphics getGraphics() { + return createGraphics(); + } + + @Override + public ImageProducer getSource() { + return getSnapshot().getSource(); + } + + public int getTransparency() { + return transparency; + } +} diff --git a/awt/java/awt/image/WritableRaster.java b/awt/java/awt/image/WritableRaster.java new file mode 100644 index 0000000..0893915 --- /dev/null +++ b/awt/java/awt/image/WritableRaster.java @@ -0,0 +1,516 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Point; +import java.awt.Rectangle; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The WritableRaster class provides functionality for + * writing samples and pixel capabilities to the Raster. + */ +public class WritableRaster extends Raster { + + /** + * Instantiates a new WritableRaster object with the specified + * SampleModel, DataBuffer, rectangular region and parent + * WritableRaster. + * + * @param sampleModel the specified SampleModel. + * @param dataBuffer the specified DataBuffer. + * @param aRegion the rectangular region which defines the new image bounds. + * @param sampleModelTranslate this point defines the translation point + * from the SampleModel to the new WritableRaster coordinates. + * @param parent the parent of this WritableRaster. + */ + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, + Rectangle aRegion, Point sampleModelTranslate, + WritableRaster parent) { + super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent); + } + + /** + * Instantiates a new WritableRaster object with the specified + * SampleModel which defines a layout of this WritableRaster and + * DataBuffer objects which defines the image data. + * + * @param sampleModel the specified SampleModel. + * @param dataBuffer the specified DataBuffer. + * @param origin the point of origin. + */ + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, + Point origin) { + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, + sampleModel.width, sampleModel.height), origin, null); + } + + /** + * Instantiates a new WritableRaster with the specified SampleModel. + * + * @param sampleModel the specified SampleModel. + * @param origin the origin. + */ + protected WritableRaster(SampleModel sampleModel, Point origin) { + this(sampleModel, sampleModel.createDataBuffer(), new Rectangle( + origin.x, origin.y, sampleModel.width, sampleModel.height), + origin, null); + } + + /** + * Sets the data for a single pixel from an input Object which + * represents an array of primitive types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param inData the input data. + */ + public void setDataElements(int x, int y, Object inData) { + sampleModel.setDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, inData, dataBuffer); + } + + /** + * Sets the data elements which represent pixel data to the specified + * rectangle area as a primitive array. The following image data types + * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, + * or DataBuffer.TYPE_DOUBLE. + * + * @param x the X coordinate of the rectangle of pixels. + * @param y the Y coordinate of the rectangle of pixels. + * @param w the width of the rectangle of pixels. + * @param h the height of the rectangle of pixels. + * @param inData the array of primitive type data to be set to the + * specified area. + */ + public void setDataElements(int x, int y, int w, int h, Object inData) { + sampleModel.setDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, inData, dataBuffer); + } + + /** + * Creates the child of this WritableRaster by sharing the specified + * rectangular area in this WritableRaster. + * The parentX, parentY, width and height parameters specify rectangular + * area to be shared. + * + * @param parentX the X coordinate of the upper left corner of + * the shared rectangle with respect to this WritableRaster' coordinates. + * @param parentY the Y coordinate of the upper left corner of + * the shared rectangle with respect to this WritableRaster' coordinates. + * @param w the width of the child area. + * @param h the height of the child area. + * @param childMinX the X coordinate of child area mapped to the parentX + * coordinate. + * @param childMinY the Y coordinate of child area mapped to the parentY + * coordinate. + * @param bandList the array of band indicies. + * + * @return the child WritableRaster. + */ + public WritableRaster createWritableChild(int parentX, int parentY, int w, + int h, int childMinX, int childMinY, int bandList[]) { + if (w <= 0 || h <= 0) { + // awt.244=Width or Height of child Raster is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.244")); //$NON-NLS-1$ + } + + if (parentX < this.minX || parentX + w > this.minX + this.width) { + // awt.245=parentX disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.245")); //$NON-NLS-1$ + } + + if (parentY < this.minY || parentY + h > this.minY + this.height) { + // awt.246=parentY disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.246")); //$NON-NLS-1$ + } + + if ((long) parentX + w > Integer.MAX_VALUE) { + // awt.247=parentX + w results in integer overflow + throw new RasterFormatException(Messages.getString("awt.247")); //$NON-NLS-1$ + } + + if ((long) parentY + h > Integer.MAX_VALUE) { + // awt.248=parentY + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.248")); //$NON-NLS-1$ + } + + if ((long) childMinX + w > Integer.MAX_VALUE) { + // awt.249=childMinX + w results in integer overflow + throw new RasterFormatException(Messages.getString("awt.249")); //$NON-NLS-1$ + } + + if ((long) childMinY + h > Integer.MAX_VALUE) { + // awt.24A=childMinY + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.24A")); //$NON-NLS-1$ + } + + SampleModel childModel; + + if (bandList == null) { + childModel = sampleModel; + } else { + childModel = sampleModel.createSubsetSampleModel(bandList); + } + + int childTranslateX = childMinX - parentX; + int childTranslateY = childMinY - parentY; + + return new WritableRaster(childModel, dataBuffer, + new Rectangle(childMinX, childMinY, w, h), + new Point(childTranslateX + sampleModelTranslateX, + childTranslateY + sampleModelTranslateY), + this); + } + + /** + * Creates the translated child of this WritableRaster. + * New WritableRaster object is a reference to the this + * WritableRaster and with different location. + * + * @param childMinX the X coordinate of the new WritableRaster. + * @param childMinY the Y coordinate of the new WritableRaster. + * + * @return the WritableRaster. + */ + public WritableRaster createWritableTranslatedChild(int childMinX, + int childMinY) { + return createWritableChild(minX, minY, width, height, childMinX, + childMinY, null); + } + + /** + * Gets the parent WritableRaster for this WritableRaster object. + * + * @return the parent WritableRaster for this WritableRaster object. + */ + public WritableRaster getWritableParent() { + return (WritableRaster) parent; + } + + /** + * Sets pixels from the specified source Raster srcRaster to this + * WritableRaster. + * + * @param srcRaster the source Raster. + */ + public void setRect(Raster srcRaster) { + setRect(0, 0, srcRaster); + } + + /** + * Sets pixels from the specified source Raster srcRaster to this + * WritableRaster. Each pixel with (x, y) coordinates from the source + * Raster is copied to pixel with (x+dx, y+dy) coordinates in this + * WritableRaster. The pixels with (x+dx, y+dy) coordinates which + * are out the bounds of this raster are ignored. + * + * @param dx the distance the pixel's X coordinate in the source + * Raster is translated when writtien to this WritableRaster. + * @param dy the distance the pixel's Y coordinate in the source + * Raster is translated when writtien to this WritableRaster. + * @param srcRaster the source Raster. + */ + public void setRect(int dx, int dy, Raster srcRaster) { + int w = srcRaster.getWidth(); + int h = srcRaster.getHeight(); + + int srcX = srcRaster.getMinX(); + int srcY = srcRaster.getMinY(); + + int dstX = srcX + dx; + int dstY = srcY + dy; + + if (dstX < this.minX) { + int minOffX = this.minX - dstX; + w -= minOffX; + dstX = this.minX; + srcX += minOffX; + } + + if (dstY < this.minY) { + int minOffY = this.minY - dstY; + h -= minOffY; + dstY = this.minY; + srcY += minOffY; + } + + if (dstX + w > this.minX + this.width) { + int maxOffX = (dstX + w) - (this.minX + this.width); + w -= maxOffX; + } + + if (dstY + h > this.minY + this.height) { + int maxOffY = (dstY + h) - (this.minY + this.height); + h -= maxOffY; + } + + if (w <= 0 || h <= 0) { + return; + } + + switch (sampleModel.getDataType()) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + int iPixelsLine[] = null; + for (int i = 0; i < h; i++) { + iPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, + iPixelsLine); + setPixels(dstX, dstY + i, w, 1, iPixelsLine); + } + break; + + case DataBuffer.TYPE_FLOAT: + float fPixelsLine[] = null; + for (int i = 0; i < h; i++) { + fPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, + fPixelsLine); + setPixels(dstX, dstY + i, w, 1, fPixelsLine); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dPixelsLine[] = null; + for (int i = 0; i < h; i++) { + dPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, + dPixelsLine); + setPixels(dstX, dstY + i, w, 1, dPixelsLine); + } + break; + } + } + + /** + * Sets the data for a rectangle of pixels from an input Raster to + * this WritableRaster. + * + * @param x the X coordinate of the point where the data of + * the input Raster is to be written. + * @param y the Y coordinate of the point where the data of + * the input Raster is to be written. + * @param inRaster the input Raster. + */ + public void setDataElements(int x, int y, Raster inRaster) { + int dstX = x + inRaster.getMinX(); + int dstY = y + inRaster.getMinY(); + + int w = inRaster.getWidth(); + int h = inRaster.getHeight(); + + if (dstX < this.minX || dstX + w > this.minX + this.width || + dstY < this.minY || dstY + h > this.minY + this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int srcX = inRaster.getMinX(); + int srcY = inRaster.getMinY(); + Object line = null; + + for (int i = 0; i < h; i++) { + line = inRaster.getDataElements(srcX, srcY + i, w, 1, line); + setDataElements(dstX, dstY + i, w, 1, line); + } + } + + /** + * Sets a int array of samples for the specified pixel + * in this WritableRaster. + * + * @param x the pixel's X coordinate. + * @param y the pixel's Y coordinate. + * @param iArray the int array of samples. + */ + public void setPixel(int x, int y, int iArray[]) { + sampleModel.setPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, iArray, dataBuffer); + } + + /** + * Sets a float array of samples for the specified pixel + * in this WritableRaster. + * + * @param x the pixel's X coordinate. + * @param y the pixel's Y coordinate. + * @param fArray the float array of samples. + */ + public void setPixel(int x, int y, float fArray[]) { + sampleModel.setPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, fArray, dataBuffer); + } + + /** + * Sets a double array of samples for the specified pixel + * in this WritableRaster. + * + * @param x the pixel's X coordinate. + * @param y the pixel's Y coordinate. + * @param dArray the double array of samples. + */ + public void setPixel(int x, int y, double dArray[]) { + sampleModel.setPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, dArray, dataBuffer); + } + + /** + * Sets a int array of samples for the specified rectangular area + * of pixels in this WritableRaster. + * + * @param x the X coordinate of rectangular area. + * @param y the Y coordinate of rectangular area. + * @param w the width of rectangular area. + * @param h the height of rectangular area. + * @param iArray the int array of samples. + */ + public void setPixels(int x, int y, int w, int h, int iArray[]) { + sampleModel.setPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, iArray, dataBuffer); + } + + /** + * Sets a float array of samples for the specified rectangular area + * of pixels in this WritableRaster. + * + * @param x the X coordinate of rectangular area. + * @param y the Y coordinate of rectangular area. + * @param w the width of rectangular area. + * @param h the height of rectangular area. + * @param fArray the float array of samples. + */ + public void setPixels(int x, int y, int w, int h, float fArray[]) { + sampleModel.setPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, fArray, dataBuffer); + } + + /** + * Sets a double array of samples for the specified rectangular area + * of pixels in this WritableRaster. + * + * @param x the X coordinate of rectangular area. + * @param y the Y coordinate of rectangular area. + * @param w the width of rectangular area. + * @param h the height of rectangular area. + * @param dArray the double array of samples. + */ + public void setPixels(int x, int y, int w, int h, double dArray[]) { + sampleModel.setPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, dArray, dataBuffer); + } + + /** + * Sets the samples for the specified band and the specified + * rectangular area of pixels with an int array of samples. + * + * @param x the X coordinate of the area of pixels. + * @param y the Y coordinate of the area of pixels. + * @param w the width of the area of pixels. + * @param h the height of the area of pixels. + * @param b the specified band. + * @param iArray the int array of samples. + + */ + public void setSamples(int x, int y, int w, int h, int b, int iArray[]) { + sampleModel.setSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, b, iArray, dataBuffer); + } + + /** + * Sets the samples for the specified band and the specified + * rectangular area of pixels with a float array of samples. + * + * @param x the X coordinate of the area of pixels. + * @param y the Y coordinate of the area of pixels. + * @param w the width of the area of pixels. + * @param h the height of the area of pixels. + * @param b the specified band. + * @param fArray the float array of samples. + */ + public void setSamples(int x, int y, int w, int h, int b, float fArray[]) { + sampleModel.setSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, b, fArray, dataBuffer); + } + + /** + * Sets the samples for the specified band and the specified + * rectangular area of pixels with a double array of samples. + * + * @param x the X coordinate of the area of pixels. + * @param y the Y coordinate of the area of pixels. + * @param w the width of the area of pixels. + * @param h the height of the area of pixels. + * @param b the specified band. + * @param dArray the double array of samples. + */ + public void setSamples(int x, int y, int w, int h, int b, double dArray[]) { + sampleModel.setSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, b, dArray, dataBuffer); + } + + /** + * Sets the sample for the specified band and the specified + * pixel with an int sample. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the specified band. + * @param s the sample to be set. + */ + public void setSample(int x, int y, int b, int s) { + sampleModel.setSample(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, s, dataBuffer); + } + + /** + * Sets the sample for the specified band and the specified + * pixel with a float sample. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the specified band. + * @param s the sample to be set. + */ + public void setSample(int x, int y, int b, float s) { + sampleModel.setSample(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, s, dataBuffer); + } + + /** + * Sets the sample for the specified band and the specified + * pixel with a int sample. + * + * @param x the X coordinate of the pixel. + * @param y the Y coordinate of the pixel. + * @param b the specified band. + * @param s the sample to be set. + */ + public void setSample(int x, int y, int b, double s) { + sampleModel.setSample(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, s, dataBuffer); + } + +} + diff --git a/awt/java/awt/image/WritableRenderedImage.java b/awt/java/awt/image/WritableRenderedImage.java new file mode 100644 index 0000000..ee1cb9e --- /dev/null +++ b/awt/java/awt/image/WritableRenderedImage.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Point; + +/** + * The WriteableRenderedImage interface is interface for objects which + * contains Raster data of one or several tiles. This interface provides + * notification mehanism for obtaining tile's writing status. + */ +public interface WritableRenderedImage extends RenderedImage { + + /** + * Gets and checks out the writable tile for writing. + * + * @param tileX the X index of the tile. + * @param tileY the Y index of the tile. + * + * @return the WritableRaster. + */ + public WritableRaster getWritableTile(int tileX, int tileY); + + /** + * Removes the registered TileObserver. + * + * @param to the TileObserver which is registered for this + * WritableRenderedImage. + */ + public void removeTileObserver(TileObserver to); + + /** + * Adds the specified TileObserver to this WritableRenderedImage. + * + * @param to the TileObserver object to be added. + */ + public void addTileObserver(TileObserver to); + + /** + * Sets this image to the contents of the specified Raster. + * + * @param r the specified Raster. + */ + public void setData(Raster r); + + /** + * Gets the array of points wich represent indices of tiles which + * are check out for writing. + * + * @return the array of Points. + */ + public Point[] getWritableTileIndices(); + + /** + * Checks if the specified tile is writable or not. + * + * @param tileX the X index of tile. + * @param tileY the Y index of tile. + * + * @return true, if the specified tile is writable, + * false otherwise. + */ + public boolean isTileWritable(int tileX, int tileY); + + /** + * Release the specified writable tile. This method removes the writer + * from the tile. + * + * @param tileX the X index of the tile. + * @param tileY the Y index of the tile. + */ + public void releaseWritableTile(int tileX, int tileY); + + /** + * Checks if there is a tile which is checked out for writing. + * + * @return true, if any tile is checked out for writing, false if there + * is no such tile. + */ + public boolean hasTileWriters(); + +} + diff --git a/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java new file mode 100644 index 0000000..3e96637 --- /dev/null +++ b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image.renderable; + +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; + +/** + * A factory for creating ContextualRenderedImage objects with utilities + * for manipulating the properties in the parameter block. + */ +public interface ContextualRenderedImageFactory extends RenderedImageFactory { + + /** + * Maps a render context to a parameter block and a renderable image. + * + * @param a0 the index + * @param a1 the RenderContext + * @param a2 the ParameterBlock + * @param a3 the RenderableImage + * + * @return the render context + */ + public RenderContext mapRenderContext(int a0, RenderContext a1, ParameterBlock a2, RenderableImage a3); + + /** + * Gets the value of the property from the parameter block. + * + * @param a0 the parameter block to examine to find the property + * @param a1 the name of the property + * + * @return the value of the property + */ + public Object getProperty(ParameterBlock a0, String a1); + + /** + * Creates the rendered image determined by the render context and + * parameter block. + * + * @param a0 the RenderContext + * @param a1 the ParameterBlock + * + * @return the rendered image + */ + public RenderedImage create(RenderContext a0, ParameterBlock a1); + + /** + * Gets the bounding rectangle from the parameter block. + * + * @param a0 the parameter block to read the bounds from + * + * @return the bounding rectangle + */ + public Rectangle2D getBounds2D(ParameterBlock a0); + + /** + * Gets the names of all of the supported properties. + * + * @return the property names + */ + public String[] getPropertyNames(); + + /** + * Checks if this image factory is dynamic. + * + * @return true, if this image factory is dynamic + */ + public boolean isDynamic(); + +} + diff --git a/awt/java/awt/image/renderable/ParameterBlock.java b/awt/java/awt/image/renderable/ParameterBlock.java new file mode 100644 index 0000000..1555f45 --- /dev/null +++ b/awt/java/awt/image/renderable/ParameterBlock.java @@ -0,0 +1,548 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image.renderable; + +import java.awt.image.RenderedImage; +import java.io.Serializable; +import java.util.Vector; + +/** + * The Class ParameterBlock groups an indexed set of parameter data + * with a set of renderable (source) images. The mapping between + * the indexed parameters and their property names is provided + * by a {@link ContextualRenderedImageFactory} + */ +public class ParameterBlock implements Cloneable, Serializable { + + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = -7577115551785240750L; + + /** The sources (renderable images). */ + protected Vector sources = new Vector(); + + /** The parameters. */ + protected Vector parameters = new Vector(); + + /** + * Instantiates a new parameter block. + * + * @param sources the vector of source images + * @param parameters the vector of parameters + */ + public ParameterBlock(Vector sources, Vector parameters) { + setSources(sources); + setParameters(parameters); + } + + /** + * Instantiates a new parameter block with no parameters. + * + * @param sources the vector of source images + */ + public ParameterBlock(Vector sources) { + setSources(sources); + } + + /** + * Instantiates a new parameter block with no image or parameter vectors. + */ + public ParameterBlock() {} + + /** + * Sets the source image at the specified index. + * + * @param source the source image + * @param index the index where the source will be placed + * + * @return this parameter block + */ + public ParameterBlock setSource(Object source, int index) { + if(sources.size() < index + 1){ + sources.setSize(index + 1); + } + sources.setElementAt(source, index); + return this; + } + + /** + * Sets the parameter value object at the specified index. + * + * @param obj the parameter value to place at the desired index + * @param index the index where the object is to be placed in the + * vector of parameters + * + * @return this parameter block + */ + public ParameterBlock set(Object obj, int index) { + if(parameters.size() < index + 1){ + parameters.setSize(index + 1); + } + parameters.setElementAt(obj, index); + return this; + } + + /** + * Adds a source to the vector of sources. + * + * @param source the source to add + * + * @return this parameter block + */ + public ParameterBlock addSource(Object source) { + sources.addElement(source); + return this; + } + + /** + * Adds the object to the vector of parameter values + * + * @param obj the obj to add + * + * @return this parameter block + */ + public ParameterBlock add(Object obj) { + parameters.addElement(obj); + return this; + } + + /** + * Sets the vector of sources, replacing the existing + * vector of sources, if any. + * + * @param sources the new sources + */ + public void setSources(Vector sources) { + this.sources = sources; + } + + /** + * Sets the vector of parameters, replacing the existing + * vector of parameters, if any. + * + * @param parameters the new parameters + */ + public void setParameters(Vector parameters) { + this.parameters = parameters; + } + + /** + * Gets the vector of sources. + * + * @return the sources + */ + public Vector getSources() { + return sources; + } + + /** + * Gets the vector of parameters. + * + * @return the parameters + */ + public Vector getParameters() { + return parameters; + } + + /** + * Gets the source at the specified index. + * + * @param index the index + * + * @return the source object found at the specified index + */ + public Object getSource(int index) { + return sources.elementAt(index); + } + + /** + * Gets the object parameter found at the specified index. + * + * @param index the index + * + * @return the parameter object found at the specified index + */ + public Object getObjectParameter(int index) { + return parameters.elementAt(index); + } + + /** + * Shallow clone (clones using the superclass clone method). + * + * @return the clone of this object + */ + public Object shallowClone() { + try{ + return super.clone(); + }catch(Exception e){ + return null; + } + } + + @SuppressWarnings("unchecked") + @Override + public Object clone() { + ParameterBlock replica; + try{ + replica = (ParameterBlock)super.clone(); + }catch(Exception e){ + return null; + } + if(sources != null){ + replica.setSources((Vector)(sources.clone())); + } + if(parameters != null){ + replica.setParameters((Vector)(parameters.clone())); + } + return replica; + } + + /** + * Gets an array of classes corresponding to all of the parameter + * values found in the array of parameters, in order. + * + * @return the parameter classes + */ + public Class[] getParamClasses() { + int count = parameters.size(); + Class paramClasses[] = new Class[count]; + + for(int i = 0; i < count; i++){ + paramClasses[i] = parameters.elementAt(i).getClass(); + } + return paramClasses; + } + + /** + * Gets the renderable source image found at the specified index + * in the source array. + * + * @param index the index + * + * @return the renderable source image + */ + public RenderableImage getRenderableSource(int index) { + return (RenderableImage)sources.elementAt(index); + } + + /** + * Wraps the short value in a Short and places it in the + * parameter block at the specified index. + * + * @param s the short value of the parameter + * @param index the index + * + * @return this parameter block + */ + public ParameterBlock set(short s, int index) { + return set(new Short(s), index); + } + + /** + * Wraps the short value in a Short and adds it to the + * parameter block. + * + * @param s the short value of the parameter + * + * @return this parameter block + */ + public ParameterBlock add(short s) { + return add(new Short(s)); + } + + /** + * Wraps the long value in a Long and places it in the + * parameter block at the specified index. + * + * @param l the long value of the parameter + * @param index the index + * + * @return this parameter block + */ + public ParameterBlock set(long l, int index) { + return set(new Long(l), index); + } + + /** + * Wraps the long value in a Long and adds it to the + * parameter block. + * + * @param l the long value of the parameter + * + * @return this parameter block + */ + public ParameterBlock add(long l) { + return add(new Long(l)); + } + + /** + * Wraps the int value in an Integer and places it in the + * parameter block at the specified index. + * + * @param i the int value of the parameter + * @param index the index + * + * @return this parameter block + */ + public ParameterBlock set(int i, int index) { + return set(new Integer(i), index); + } + + /** + * Wraps the int value in an Integer and adds it to the + * parameter block. + * + * @param i the int value of the parameter + * + * @return this parameter block + */ + public ParameterBlock add(int i) { + return add(new Integer(i)); + } + + /** + * Wraps the float value in a Float and places it in the + * parameter block at the specified index. + * + * @param f the float value of the parameter + * @param index the index + * + * @return this parameter block + */ + public ParameterBlock set(float f, int index) { + return set(new Float(f), index); + } + + /** + * Wraps the float value in a Float and adds it to the + * parameter block. + * + * @param f the float value of the parameter + * + * @return this parameter block + */ + public ParameterBlock add(float f) { + return add(new Float(f)); + } + + /** + * Wraps the double value in a Double and places it in the + * parameter block at the specified index. + * + * @param d the double value of the parameter + * @param index the index + * + * @return this parameter block + */ + public ParameterBlock set(double d, int index) { + return set(new Double(d), index); + } + + /** + * Wraps the double value in a Double and adds it to the + * parameter block. + * + * @param d the double value of the parameter + * + * @return this parameter block + */ + public ParameterBlock add(double d) { + return add(new Double(d)); + } + + /** + * Wraps the char value in a Character and places it in the + * parameter block at the specified index. + * + * @param c the char value of the parameter + * @param index the index + * + * @return this parameter block + */ + public ParameterBlock set(char c, int index) { + return set(new Character(c), index); + } + + /** + * Wraps the char value in a Character and adds it to the + * parameter block. + * + * @param c the char value of the parameter + * + * @return this parameter block + */ + public ParameterBlock add(char c) { + return add(new Character(c)); + } + + /** + * Wraps the byte value in a Byte and places it in the + * parameter block at the specified index. + * + * @param b the byte value of the parameter + * @param index the index + * + * @return this parameter block + */ + public ParameterBlock set(byte b, int index) { + return set(new Byte(b), index); + } + + /** + * Wraps the byte value in a Byte and adds it to the + * parameter block. + * + * @param b the byte value of the parameter + * + * @return the parameter block + */ + public ParameterBlock add(byte b) { + return add(new Byte(b)); + } + + /** + * Gets the RenderedImage at the specified index from the + * vector of source images. + * + * @param index the index + * + * @return the rendered image + */ + public RenderedImage getRenderedSource(int index) { + return (RenderedImage)sources.elementAt(index); + } + + /** + * Gets the short-valued parameter found at the desired index + * in the vector of parameter values. + * + * @param index the index + * + * @return the short parameter + */ + public short getShortParameter(int index) { + return ((Short)parameters.elementAt(index)).shortValue(); + } + + /** + * Gets the long-valued parameter found at the desired index + * in the vector of parameter values. + * + * @param index the index + * + * @return the long parameter + */ + public long getLongParameter(int index) { + return ((Long)parameters.elementAt(index)).longValue(); + } + + /** + * Gets the int-valued parameter found at the desired index + * in the vector of parameter values. + * + * @param index the index + * + * @return the int parameter + */ + public int getIntParameter(int index) { + return ((Integer)parameters.elementAt(index)).intValue(); + } + + /** + * Gets the float-valued parameter found at the desired index + * in the vector of parameter values. + * + * @param index the index + * + * @return the float parameter + */ + public float getFloatParameter(int index) { + return ((Float)parameters.elementAt(index)).floatValue(); + } + + /** + * Gets the double-valued parameter found at the desired index + * in the vector of parameter values. + * + * @param index the index + * + * @return the double parameter + */ + public double getDoubleParameter(int index) { + return ((Double)parameters.elementAt(index)).doubleValue(); + } + + /** + * Gets the char-valued parameter found at the desired index + * in the vector of parameter values. + * + * @param index the index + * + * @return the char parameter + */ + public char getCharParameter(int index) { + return ((Character)parameters.elementAt(index)).charValue(); + } + + /** + * Gets the byte-valued parameter found at the desired index + * in the vector of parameter values. + * + * @param index the index + * + * @return the byte parameter + */ + public byte getByteParameter(int index) { + return ((Byte)parameters.elementAt(index)).byteValue(); + } + + /** + * Clears the vector of sources. + */ + public void removeSources() { + sources.removeAllElements(); + } + + /** + * Clears the vector of parameters. + */ + public void removeParameters() { + parameters.removeAllElements(); + } + + /** + * Gets the number of elements in the vector of sources. + * + * @return the number of elements in the vector of sources + */ + public int getNumSources() { + return sources.size(); + } + + /** + * Gets the number of elements in the vector of parameters. + * + * @return the number of elements in the vector of parameters + */ + public int getNumParameters() { + return parameters.size(); + } +} diff --git a/awt/java/awt/image/renderable/RenderContext.java b/awt/java/awt/image/renderable/RenderContext.java new file mode 100644 index 0000000..3a3b93c --- /dev/null +++ b/awt/java/awt/image/renderable/RenderContext.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; + +/** + * The Class RenderContext stores data on how an image is to be + * rendered: the affine transform, the area of interest, and + * the rendering hints. + */ +public class RenderContext implements Cloneable { + + /** The affine transform. */ + AffineTransform transform; + + /** The area of interest. */ + Shape aoi; + + /** The rendering hints. */ + RenderingHints hints; + + /** + * Instantiates a new render context. + * + * @param usr2dev the affine transform + * @param aoi the area of interest + * @param hints the rendering hints + */ + public RenderContext(AffineTransform usr2dev, Shape aoi, RenderingHints hints) { + this.transform = (AffineTransform)usr2dev.clone(); + this.aoi = aoi; + this.hints = hints; + } + + /** + * Instantiates a new render context with no specified hints. + * + * @param usr2dev the affine transform + * @param aoi the area of interest + */ + public RenderContext(AffineTransform usr2dev, Shape aoi) { + this(usr2dev, aoi, null); + } + + /** + * Instantiates a new render context with no specified area of interest. + * + * @param usr2dev the affine transform + * @param hints the rendering hints + */ + public RenderContext(AffineTransform usr2dev, RenderingHints hints) { + this(usr2dev, null, hints); + } + + /** + * Instantiates a new render context with no rendering hints or + * area of interest. + * + * @param usr2dev the affine transform + */ + public RenderContext(AffineTransform usr2dev) { + this(usr2dev, null, null); + } + + @Override + public Object clone() { + return new RenderContext(transform, aoi, hints); + } + + /** + * Sets the affine transform for this render context. + * + * @param newTransform the new affine transform + */ + public void setTransform(AffineTransform newTransform) { + transform = (AffineTransform)newTransform.clone(); + } + + /** + * Concatenates the current transform with the specified transform + * (so they are applied with the specified transform acting first) + * and sets the resulting transform as the affine transform of + * this rendering context. + * + * @param modTransform the new transform which modifies the + * current transform + * + * @deprecated use {@link RenderContext#preConcatenateTransform(AffineTransform)} + */ + @Deprecated + public void preConcetenateTransform(AffineTransform modTransform) { + preConcatenateTransform(modTransform); + } + + /** + * Concatenates the current transform with the specified transform + * (so they are applied with the specified transform acting first) + * and sets the resulting transform as the affine transform of + * this rendering context. + * + * @param modTransform the new transform which modifies the + * current transform + */ + public void preConcatenateTransform(AffineTransform modTransform) { + transform.preConcatenate(modTransform); + } + + /** + * Concatenate the specified transform with the current transform. + * + * @param modTransform the new transform which modifies the + * current transform + * + * @deprecated use {@link RenderContext#concatenateTransform(AffineTransform)} + */ + @Deprecated + public void concetenateTransform(AffineTransform modTransform) { + concatenateTransform(modTransform); + } + + /** + * Concatenate the specified transform with the current transform. + * + * @param modTransform the new transform which modifies the + * current transform + */ + public void concatenateTransform(AffineTransform modTransform) { + transform.concatenate(modTransform); + } + + /** + * Gets the transform. + * + * @return the transform + */ + public AffineTransform getTransform() { + return (AffineTransform)transform.clone(); + } + + /** + * Sets the area of interest. + * + * @param newAoi the new area of interest + */ + public void setAreaOfInterest(Shape newAoi) { + aoi = newAoi; + } + + /** + * Gets the area of interest. + * + * @return the area of interest + */ + public Shape getAreaOfInterest() { + return aoi; + } + + /** + * Sets the rendering hints. + * + * @param hints the new rendering hints + */ + public void setRenderingHints(RenderingHints hints) { + this.hints = hints; + } + + /** + * Gets the rendering hints. + * + * @return the rendering hints + */ + public RenderingHints getRenderingHints() { + return hints; + } +} diff --git a/awt/java/awt/image/renderable/RenderableImage.java b/awt/java/awt/image/renderable/RenderableImage.java new file mode 100644 index 0000000..885dc06 --- /dev/null +++ b/awt/java/awt/image/renderable/RenderableImage.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; +import java.util.Vector; + +/** + * The Interface RenderableImage is implemented by an object that + * collects all of the image-specific data that defines a single image + * that could be rendered to different rendering targets. + */ +public interface RenderableImage { + + /** The Constant HINTS_OBSERVED indicates that the rendering + * hints are applied rather than ignored. */ + public static final String HINTS_OBSERVED = "HINTS_OBSERVED"; //$NON-NLS-1$ + + /** + * Gets the property from the RenderableImage's parameter block. + * + * @param name the name of the property to get. + * + * @return the value of the property + */ + public Object getProperty(String name); + + /** + * Creates the rendered image based on the information contained + * in the parameters and the render context. + * + * @param renderContext the render context giving rendering specifications + * such as transformations + * + * @return the rendered image + */ + public RenderedImage createRendering(RenderContext renderContext); + + /** + * Creates the scaled rendered image based on the information contained + * in the parameters and the render context. + * + * @param w the desired width after scaling or zero if the scaling + * should be proportional, based on the height + * @param h the desired height after scaling or zero if the scaling + * should be proportional, based on the width + * @param hints the rendering hints to use + * + * @return the rendered image + * + * @throws IllegalArgumentException if both the height and width are zero + */ + public RenderedImage createScaledRendering(int w, int h, RenderingHints hints); + + /** + * Gets the vector of sources from the parameter block. + * + * @return the sources + */ + public Vector getSources(); + + /** + * Gets the names of all of the supported properties in the current context. + * + * @return the property names + */ + public String[] getPropertyNames(); + + /** + * Creates the default rendering (using the identity transform + * and default render context). + * + * @return the rendered image + */ + public RenderedImage createDefaultRendering(); + + /** + * Checks if this context supports dynamic rendering. + * + * @return true, if this context supports dynamic rendering + */ + public boolean isDynamic(); + + /** + * Gets the width of the image. + * + * @return the width of the image + */ + public float getWidth(); + + /** + * Gets the y coordinate of the upper left corner. + * + * @return the y coordinate of the upper left corner + */ + public float getMinY(); + + /** + * Gets the x coordinate of the upper left corner. + * + * @return the x coordinate of the upper left corner + */ + public float getMinX(); + + /** + * Gets the height of the image. + * + * @return the height of the image + */ + public float getHeight(); + +} + diff --git a/awt/java/awt/image/renderable/RenderableImageOp.java b/awt/java/awt/image/renderable/RenderableImageOp.java new file mode 100644 index 0000000..993ba5f --- /dev/null +++ b/awt/java/awt/image/renderable/RenderableImageOp.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; +import java.util.Vector; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class RenderableImageOp is a basic implementation of RenderableImage, + * with methods to access the parameter data and perform rendering + * operations. + */ +public class RenderableImageOp implements RenderableImage { + + /** The CRIF. */ + ContextualRenderedImageFactory CRIF; + + /** The param block. */ + ParameterBlock paramBlock; + + /** The height. */ + float minX, minY, width, height; + + /** + * Instantiates a new renderable image op. + * + * @param CRIF the cRIF + * @param paramBlock the param block + */ + public RenderableImageOp(ContextualRenderedImageFactory CRIF, ParameterBlock paramBlock) { + this.CRIF = CRIF; + this.paramBlock = (ParameterBlock) paramBlock.clone(); + Rectangle2D r = CRIF.getBounds2D(paramBlock); + minX = (float) r.getMinX(); + minY = (float) r.getMinY(); + width = (float) r.getWidth(); + height = (float) r.getHeight(); + } + + public Object getProperty(String name) { + return CRIF.getProperty(paramBlock, name); + } + + /** + * Sets the parameter block. + * + * @param paramBlock the param block + * + * @return the parameter block + */ + public ParameterBlock setParameterBlock(ParameterBlock paramBlock) { + ParameterBlock oldParam = this.paramBlock; + this.paramBlock = (ParameterBlock) paramBlock.clone(); + return oldParam; + } + + public RenderedImage createRendering(RenderContext renderContext) { + + Vector sources = getSources(); + ParameterBlock rdParam = (ParameterBlock) paramBlock.clone(); + + if (sources != null) { + Vector rdSources = new Vector(); + int i = 0; + while (i < sources.size()) { + RenderContext newContext = CRIF.mapRenderContext(i, renderContext, paramBlock, + this); + RenderedImage rdim = sources.elementAt(i).createRendering(newContext); + + if (rdim != null) { + rdSources.addElement(rdim); + } + i++; + } + if (rdSources.size() > 0) { + rdParam.setSources(rdSources); + } + } + return CRIF.create(renderContext, rdParam); + } + + public RenderedImage createScaledRendering(int w, int h, RenderingHints hints) { + if(w == 0 && h == 0) { + // awt.60=Width and Height mustn't be equal zero both + throw new IllegalArgumentException(Messages.getString("awt.60")); //$NON-NLS-1$ + } + if(w == 0){ + w = Math.round(h*(getWidth()/getHeight())); + } + + if(h == 0){ + h = Math.round(w*(getHeight()/getWidth())); + } + + double sx = (double)w/getWidth(); + double sy = (double)h/getHeight(); + + AffineTransform at = AffineTransform.getScaleInstance(sx, sy); + RenderContext context = new RenderContext(at, hints); + return createRendering(context); + } + + public Vector getSources() { + if(paramBlock.getNumSources() == 0) { + return null; + } + Vector v = new Vector(); + int i = 0; + while(i < paramBlock.getNumSources()){ + Object o = paramBlock.getSource(i); + if(o instanceof RenderableImage){ + v.addElement((RenderableImage) o); + } + i++; + } + return v; + } + + public String[] getPropertyNames() { + return CRIF.getPropertyNames(); + } + + /** + * Gets the parameter block. + * + * @return the parameter block + */ + public ParameterBlock getParameterBlock() { + return paramBlock; + } + + public RenderedImage createDefaultRendering() { + AffineTransform at = new AffineTransform(); + RenderContext context = new RenderContext(at); + return createRendering(context); + } + + public boolean isDynamic() { + return CRIF.isDynamic(); + } + + public float getWidth() { + return width; + } + + public float getMinY() { + return minY; + } + + public float getMinX() { + return minX; + } + + public float getHeight() { + return height; + } + +} + diff --git a/awt/java/awt/image/renderable/RenderableImageProducer.java b/awt/java/awt/image/renderable/RenderableImageProducer.java new file mode 100644 index 0000000..7fda98c --- /dev/null +++ b/awt/java/awt/image/renderable/RenderableImageProducer.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image.renderable; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.util.Vector; + +/** + * The Class RenderableImageProducer provides the implementation for + * the image rendering. + */ +public class RenderableImageProducer implements ImageProducer, Runnable { + + /** The rbl. */ + RenderableImage rbl; + + /** The rc. */ + RenderContext rc; + + /** The consumers. */ + Vector consumers = new Vector(); + + /** + * Instantiates a new renderable image producer. + * + * @param rdblImage the rdbl image + * @param rc the rc + */ + public RenderableImageProducer(RenderableImage rdblImage, RenderContext rc) { + this.rbl = rdblImage; + this.rc = rc; + } + + /** + * Sets the render context. + * + * @param rc the new render context + */ + public synchronized void setRenderContext(RenderContext rc) { + this.rc = rc; + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + return consumers.contains(ic); + } + + public synchronized void startProduction(ImageConsumer ic) { + addConsumer(ic); + Thread t = new Thread(this, "RenderableImageProducer thread"); //$NON-NLS-1$ + t.start(); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) {} + + public synchronized void removeConsumer(ImageConsumer ic) { + if(ic != null) { + consumers.removeElement(ic); + } + } + + public synchronized void addConsumer(ImageConsumer ic) { + if(ic != null && !consumers.contains(ic)){ + consumers.addElement(ic); + } + } + + /** + * Creates the rendered image in a new thread. + */ + public void run() { + if(rbl == null) { + return; + } + + RenderedImage rd; + if(rc != null) { + rd = rbl.createRendering(rc); + } else { + rd = rbl.createDefaultRendering(); + } + + ColorModel cm = rd.getColorModel(); + if(cm == null) { + cm = ColorModel.getRGBdefault(); + } + + Raster r = rd.getData(); + int w = r.getWidth(); + int h = r.getHeight(); + + for (ImageConsumer c : consumers) { + c.setDimensions(w, h); + c.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | + ImageConsumer.COMPLETESCANLINES | + ImageConsumer.SINGLEFRAME | + ImageConsumer.SINGLEPASS); + } + + int scanLine[] = new int[w]; + int pixel[] = null; + + for(int y = 0; y < h; y++){ + for(int x = 0; x < w; x++){ + pixel = r.getPixel(x, y, pixel); + scanLine[x] = cm.getDataElement(pixel, 0); + } + + for (ImageConsumer c : consumers) { + c.setPixels(0, y, w, 1, cm, scanLine, 0, w); + } + } + + for (ImageConsumer c : consumers) { + c.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } + +} + diff --git a/awt/java/awt/image/renderable/RenderedImageFactory.java b/awt/java/awt/image/renderable/RenderedImageFactory.java new file mode 100644 index 0000000..345d82c --- /dev/null +++ b/awt/java/awt/image/renderable/RenderedImageFactory.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; + +/** + * A factory for creating RenderedImage objects based on parameters + * and rendering hints. + */ +public interface RenderedImageFactory { + + /** + * Creates the rendered image. + * + * @param a0 the ParameterBlock + * @param a1 the RenderingHints + * + * @return the rendered image + */ + public RenderedImage create(ParameterBlock a0, RenderingHints a1); + +} + -- cgit v1.1