diff options
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java')
-rwxr-xr-x | bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java | 7094 |
1 files changed, 3547 insertions, 3547 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java index e7587a4fe7..6d663d23b9 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java @@ -1,3551 +1,3551 @@ -package org.eclipse.swt.graphics;
-
-/*
+package org.eclipse.swt.graphics; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import java.io.*;
-import org.eclipse.swt.*;
-import org.eclipse.swt.internal.CloneableCompatibility;
-
-/**
- * Instances of this class are device-independent descriptions
- * of images. They are typically used as an intermediate format
- * between loading from or writing to streams and creating an
- * <code>Image</code>.
- * <p>
- * Note that the public fields <code>x</code>, <code>y</code>,
- * <code>disposalMethod</code> and <code>delayTime</code> are
- * typically only used when the image is in a set of images used
- * for animation.
- * </p>
- *
- * @see Image
- * @see ImageLoader
- */
-
-public final class ImageData implements CloneableCompatibility {
-
- /**
- * the width of the image, in pixels
- */
- public int width;
-
- /**
- * the height of the image, in pixels
- */
- public int height;
-
- /**
- * the color depth of the image, in bits per pixel
- * <p>
- * Note that a depth of 8 or less does not necessary
- * mean that the image is palette indexed, or
- * conversely that a depth greater than 8 means that
- * the image is direct color. Check the associated
- * PaletteData's isDirect field for such determinations.
- */
- public int depth;
-
- /**
- * the scanline padding
- * <p>
- * If one scanline of the image is not a multiple of
- * this number, it will be padded with zeros until it is.
- * </p>
- */
- public int scanlinePad;
-
- /**
- * the number of bytes per scanline
- * <p>
- * This is a multiple of the scanline padding.
- * </p>
- */
- public int bytesPerLine;
-
- /**
- * the pixel data of the image
- * <p>
- * Note that for 16 bit depth images the pixel data is stored
- * in least significant byte order; however, for 24bit and
- * 32bit depth images the pixel data is stored in most
- * significant byte order.
- * </p>
- */
- public byte[] data;
-
- /**
- * the color table for the image
- */
- public PaletteData palette;
-
- /**
- * the transparent pixel
- * <p>
- * Pixels with this value are transparent.
- * </p><p>
- * The default is -1 which means 'no transparent pixel'.
- * </p>
- */
- public int transparentPixel;
-
- /**
- * icon-specific field containing the data from the icon mask
- * <p>
- * This is a 1 bit bitmap stored with the most significant
- * bit first. The number of bytes per scanline is
- * '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'.
- * </p><p>
- * The default is null which means 'no transparency mask'.
- * </p>
- */
- public byte[] maskData;
-
- /**
- * icon-specific field containing the scanline pad of the mask
- * <p>
- * If one scanline of the transparency mask is not a
- * multiple of this number, it will be padded with zeros until
- * it is.
- * </p>
- */
- public int maskPad;
-
- /**
- * the alpha data of the image
- * <p>
- * Every pixel can have an <em>alpha blending</em> value that
- * varies from 0, meaning fully transparent, to 255 meaning
- * fully opaque. The number of bytes per scanline is
- * 'width'.
- * </p>
- */
- public byte[] alphaData;
-
- /**
- * the global alpha value to be used for every pixel
- * <p>
- * If this value is set, the <code>alphaData</code> field
- * is ignored and when the image is rendered each pixel
- * will be blended with the background an amount
- * proportional to this value.
- * </p><p>
- * The default is -1 which means 'no global alpha value'
- * </p>
- */
- public int alpha;
-
- /**
- * the type of file that the image was read in from,
- * expressed as one of the following values:
- * <dl>
- * <dt><code>IMAGE_BMP</code></dt>
- * <dd>Windows BMP file format, no compression</dd>
- * <dt><code>IMAGE_BMP_RLE</code></dt>
- * <dd>Windows BMP file format, RLE compression if appropriate</dd>
- * <dt><code>IMAGE_GIF</code></dt>
- * <dd>GIF file format</dd>
- * <dt><code>IMAGE_ICO</code></dt>
- * <dd>Windows ICO file format</dd>
- * <dt><code>IMAGE_JPEG</code></dt>
- * <dd>JPEG file format</dd>
- * <dt><code>IMAGE_PNG</code></dt>
- * <dd>PNG file format</dd>
- * </dl>
- */
- public int type;
-
- /**
- * the x coordinate of the top left corner of the image
- * within the logical screen (this field corresponds to
- * the GIF89a Image Left Position value)
- */
- public int x;
-
- /**
- * The y coordinate of the top left corner of the image
- * within the logical screen (this field corresponds to
- * the GIF89a Image Top Position value)
- */
- public int y;
-
- /**
- * a description of how to dispose of the current image
- * before displaying the next, expressed as one of the
- * following values:
- * <dl>
- * <dt><code>DM_UNSPECIFIED</code></dt>
- * <dd>disposal method not specified</dd>
- * <dt><code>DM_FILL_NONE</code></dt>
- * <dd>do nothing - leave the image in place</dd>
- * <dt><code>DM_FILL_BACKGROUND</code></dt>
- * <dd>fill with the background color</dd>
- * <dt><code>DM_FILL_PREVIOUS</code></dt>
- * <dd>restore the previous picture</dd>
- * </dl>
- * (this field corresponds to the GIF89a Disposal Method value)
- */
- public int disposalMethod;
-
- /**
- * the time to delay before displaying the next image
- * in an animation (this field corresponds to the GIF89a
- * Delay Time value)
- */
- public int delayTime;
-
- /**
- * Arbitrary channel width data to 8-bit conversion table
- */
- static final byte[][] ANY_TO_EIGHT = new byte[9][];
- static {
- for (int b = 0; b < 9; ++b) {
- byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b];
- if (b == 0) continue;
- int inc = 0;
- for (int bit = 0x10000; (bit >>= b) != 0;) inc |= bit;
- for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = (byte)(v >> 8);
- }
- }
- static final byte[] ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8];
-
- /**
- * Scaled 8x8 Bayer dither matrix
- */
- static final int[][] DITHER_MATRIX = {
- { 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 },
- { 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 },
- { 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 },
- { 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 },
- { 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 },
- { 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 },
- { 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 },
- { 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 }
- };
-
-/**
- * Constructs a new, empty ImageData with the given width, height,
- * depth and palette. The data will be initialized to an (all zero)
- * array of the appropriate size.
- *
- * @param width the width of the image
- * @param height the height of the image
- * @param depth the depth of the image
- * @param palette the palette of the image (must not be null)
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_INVALID_ARGUMENT - if the width or height is negative</li>
- * <li>ERROR_NULL_ARGUMENT - if the palette is null</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_UNSUPPORTED_DEPTH - if the depth argument is not one of 1, 2, 4, 8, 16, 24 or 32</li>
- * </ul>
- */
-public ImageData(int width, int height, int depth, PaletteData palette) {
- this(width, height, depth, palette,
- 4, null, 0, null,
- null, -1, -1, SWT.IMAGE_UNDEFINED,
- 0, 0, 0, 0);
-}
-
-/**
- * Constructs a new, empty ImageData with the given width, height,
- * depth, palette, scanlinePad and data.
- *
- * @param width the width of the image
- * @param height the height of the image
- * @param depth the depth of the image
- * @param palette the palette of the image
- * @param scanlinePad the padding of each line, in bytes
- * @param data the data of the image
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_INVALID_ARGUMENT - if the width or height is negative</li>
- * <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_UNSUPPORTED_DEPTH - if the depth argument is not one of 1, 2, 4, 8, 16, 24 or 32</li>
- * </ul>
- */
-public ImageData(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) {
- this(width, height, depth, palette,
- scanlinePad, checkData(data), 0, null,
- null, -1, -1, SWT.IMAGE_UNDEFINED,
- 0, 0, 0, 0);
-}
-
-/**
- * Constructs an <code>ImageData</code> loaded from the specified
- * input stream. Throws an error if an error occurs while loading
- * the image, or if the image has an unsupported type.
- * <p>
- * This constructor is provided for convenience when loading a single
- * image only. If the stream contains multiple images, only the first
- * one will be loaded. To load multiple images, use
- * <code>ImageLoader.load()</code>.
- * </p>
- *
- * @param stream the input stream to load the image from (must not be null)
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
- * <li>ERROR_IO - if an IO error occurs while reading data</li>
- * </ul>
- *
- * @see ImageLoader#load
- */
-public ImageData(InputStream stream) {
- ImageData[] data = new ImageLoader().load(stream);
- if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
- ImageData i = data[0];
- setAllFields(
- i.width,
- i.height,
- i.depth,
- i.scanlinePad,
- i.bytesPerLine,
- i.data,
- i.palette,
- i.transparentPixel,
- i.maskData,
- i.maskPad,
- i.alphaData,
- i.alpha,
- i.type,
- i.x,
- i.y,
- i.disposalMethod,
- i.delayTime);
-}
-
-/**
- * Constructs an <code>ImageData</code> loaded from a file with the
- * specified name. Throws an error if an error occurs loading the
- * image, or if the image has an unsupported type.
- * <p>
- * This constructor is provided for convenience when loading a single
- * image only. If the file contains multiple images, only the first
- * one will be loaded. To load multiple images, use
- * <code>ImageLoader.load()</code>.
- * </p>
- *
- * @param filename the name of the file to load the image from (must not be null)
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
- * <li>ERROR_IO if an IO error occurs while reading data</li>
- * </ul>
- */
-public ImageData(String filename) {
- ImageData[] data = new ImageLoader().load(filename);
- if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
- ImageData i = data[0];
- setAllFields(
- i.width,
- i.height,
- i.depth,
- i.scanlinePad,
- i.bytesPerLine,
- i.data,
- i.palette,
- i.transparentPixel,
- i.maskData,
- i.maskPad,
- i.alphaData,
- i.alpha,
- i.type,
- i.x,
- i.y,
- i.disposalMethod,
- i.delayTime);
-}
-
-/**
- * Prevents uninitialized instances from being created outside the package.
- */
-ImageData() {
-}
-
-/**
- * Constructs an image data by giving values for all non-computable fields.
- * <p>
- * This method is for internal use, and is not described further.
- * </p>
- */
-ImageData(
- int width, int height, int depth, PaletteData palette,
- int scanlinePad, byte[] data, int maskPad, byte[] maskData,
- byte[] alphaData, int alpha, int transparentPixel, int type,
- int x, int y, int disposalMethod, int delayTime)
-{
-
- if (palette == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (!(depth == 1 || depth == 2 || depth == 4 || depth == 8
- || depth == 16 || depth == 24 || depth == 32)) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- if (width <= 0 || height <= 0) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1))
- / scanlinePad * scanlinePad;
- setAllFields(
- width,
- height,
- depth,
- scanlinePad,
- bytesPerLine,
- data != null ? data : new byte[bytesPerLine * height],
- palette,
- transparentPixel,
- maskData,
- maskPad,
- alphaData,
- alpha,
- type,
- x,
- y,
- disposalMethod,
- delayTime);
-}
-
-/**
- * Initializes all fields in the receiver. This method must be called
- * by all public constructors to ensure that all fields are initialized
- * for a new ImageData object. If a new field is added to the class,
- * then it must be added to this method.
- * <p>
- * This method is for internal use, and is not described further.
- * </p>
- */
-void setAllFields(int width, int height, int depth, int scanlinePad,
- int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel,
- byte[] maskData, int maskPad, byte[] alphaData, int alpha,
- int type, int x, int y, int disposalMethod, int delayTime) {
-
- this.width = width;
- this.height = height;
- this.depth = depth;
- this.scanlinePad = scanlinePad;
- this.bytesPerLine = bytesPerLine;
- this.data = data;
- this.palette = palette;
- this.transparentPixel = transparentPixel;
- this.maskData = maskData;
- this.maskPad = maskPad;
- this.alphaData = alphaData;
- this.alpha = alpha;
- this.type = type;
- this.x = x;
- this.y = y;
- this.disposalMethod = disposalMethod;
- this.delayTime = delayTime;
-}
-
-/**
- * Invokes internal SWT functionality to create a new instance of
- * this class.
- * <p>
- * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
- * API for <code>ImageData</code>. It is marked public only so that it
- * can be shared within the packages provided by SWT. It is subject
- * to change without notice, and should never be called from
- * application code.
- * </p>
- * <p>
- * This method is for internal use, and is not described further.
- * </p>
- *
- * @private
- */
-public static ImageData internal_new(
- int width, int height, int depth, PaletteData palette,
- int scanlinePad, byte[] data, int maskPad, byte[] maskData,
- byte[] alphaData, int alpha, int transparentPixel, int type,
- int x, int y, int disposalMethod, int delayTime)
-{
- return new ImageData(
- width, height, depth, palette, scanlinePad, data, maskPad, maskData,
- alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime);
-}
-
-ImageData colorMaskImage(int pixel) {
- ImageData mask = new ImageData(width, height, 1, bwPalette(),
- Image.DEFAULT_SCANLINE_PAD, null, 0, null,
- null, -1, -1, SWT.IMAGE_UNDEFINED,
- 0, 0, 0, 0);
- int[] row = new int[width];
- for (int y = 0; y < height; y++) {
- getPixels(0, y, width, row, 0);
- for (int i = 0; i < width; i++) {
- if (pixel != -1 && row[i] == pixel) {
- row[i] = 0;
- } else {
- row[i] = 1;
- }
- }
- mask.setPixels(0, y, width, row, 0);
- }
- return mask;
-}
-
-static byte[] checkData(byte [] data) {
- if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- return data;
-}
-
-/**
- * Returns a new instance of the same class as the receiver,
- * whose slots have been filled in with <em>copies</em> of
- * the values in the slots of the receiver. That is, the
- * returned object is a <em>deep copy</em> of the receiver.
- *
- * @return a copy of the receiver.
- */
-public Object clone() {
- byte[] cloneData = new byte[data.length];
- System.arraycopy(data, 0, cloneData, 0, data.length);
- byte[] cloneMaskData = null;
- if (maskData != null) {
- cloneMaskData = new byte[maskData.length];
- System.arraycopy(maskData, 0, cloneMaskData, 0, maskData.length);
- }
- byte[] cloneAlphaData = null;
- if (alphaData != null) {
- cloneAlphaData = new byte[alphaData.length];
- System.arraycopy(alphaData, 0, cloneAlphaData, 0, alphaData.length);
- }
- return new ImageData(
- width,
- height,
- depth,
- palette,
- scanlinePad,
- cloneData,
- maskPad,
- cloneMaskData,
- cloneAlphaData,
- alpha,
- transparentPixel,
- type,
- x,
- y,
- disposalMethod,
- delayTime);
-}
-
-/**
- * Returns the alpha value at offset <code>x</code> in
- * scanline <code>y</code> in the receiver's alpha data.
- *
- * @param x the x coodinate of the pixel to get the alpha value of
- * @param y the y coordinate of the pixel to get the alpha value of
- * @return the alpha value at the given coordinates
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_INVALID_ARGUMENT - if either argument is out of range</li>
- * </ul>
- */
-public int getAlpha(int x, int y) {
- if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
-
- if (alphaData == null) return 255;
- return alphaData[y * width + x] & 0xFF;
-}
-
-/**
- * Returns <code>getWidth</code> alpha values starting at offset
- * <code>x</code> in scanline <code>y</code> in the receiver's alpha
- * data starting at <code>startIndex</code>.
- *
- * @param x the x position of the pixel to begin getting alpha values
- * @param y the y position of the pixel to begin getting alpha values
- * @param getWidth the width of the data to get
- * @param alphas the buffer in which to put the alpha values
- * @param startIndex the offset into the image to begin getting alpha values
- *
- * @exception IndexOutOfBoundsException if getWidth is too large
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
- * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
- * </ul>
- */
-public void getAlphas(int x, int y, int getWidth, byte[] alphas, int startIndex) {
- if (alphas == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- if (getWidth == 0) return;
-
- if (alphaData == null) {
- int endIndex = startIndex + getWidth;
- for (int i = startIndex; i < endIndex; i++) {
- alphas[i] = (byte)255;
- }
- return;
- }
- // may throw an IndexOutOfBoundsException
- System.arraycopy(alphaData, y * width + x, alphas, startIndex, getWidth);
-}
-
-/**
- * Returns the pixel value at offset <code>x</code> in
- * scanline <code>y</code> in the receiver's data.
- *
- * @param x the x position of the pixel to get
- * @param y the y position of the pixel to get
- * @return the pixel at the given coordinates
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_INVALID_ARGUMENT - if either argument is out of bounds</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
- * </ul>
- */
-public int getPixel(int x, int y) {
- if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- int index;
- int theByte;
- int mask;
- if (depth == 1) {
- index = (y * bytesPerLine) + (x >> 3);
- theByte = data[index] & 0xFF;
- mask = 1 << (7 - (x & 0x7));
- if ((theByte & mask) == 0) {
- return 0;
- } else {
- return 1;
- }
- }
- if (depth == 2) {
- index = (y * bytesPerLine) + (x >> 2);
- theByte = data[index] & 0xFF;
- int offset = 3 - (x % 4);
- mask = 3 << (offset * 2);
- return (theByte & mask) >> (offset * 2);
- }
- if (depth == 4) {
- index = (y * bytesPerLine) + (x >> 1);
- theByte = data[index] & 0xFF;
- if ((x & 0x1) == 0) {
- return theByte >> 4;
- } else {
- return theByte & 0x0F;
- }
- }
- if (depth == 8) {
- index = (y * bytesPerLine) + x ;
- return data[index] & 0xFF;
- }
- if (depth == 16) {
- index = (y * bytesPerLine) + (x * 2);
- return ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF);
- }
- if (depth == 24) {
- index = (y * bytesPerLine) + (x * 3);
- return ((data[index] & 0xFF) << 16) + ((data[index+1] & 0xFF) << 8) +
- (data[index+2] & 0xFF);
- }
- if (depth == 32) {
- index = (y * bytesPerLine) + (x * 4);
- return ((data[index] & 0xFF) << 24) + ((data[index+1] & 0xFF) << 16) +
- ((data[index+2] & 0xFF) << 8) + (data[index+3] & 0xFF);
- }
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
- return 0;
-}
-
-/**
- * Returns <code>getWidth</code> pixel values starting at offset
- * <code>x</code> in scanline <code>y</code> in the receiver's
- * data starting at <code>startIndex</code>.
- *
- * @param x the x position of the first pixel to get
- * @param y the y position of the first pixel to get
- * @param getWidth the width of the data to get
- * @param pixels the buffer in which to put the pixels
- * @param startIndex the offset into the byte array to begin storing pixels
- *
- * @exception IndexOutOfBoundsException if getWidth is too large
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
- * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4 or 8
- * (For higher depths, use the int[] version of this method.)</li>
- * </ul>
- */
-public void getPixels(int x, int y, int getWidth, byte[] pixels, int startIndex) {
- if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- if (getWidth == 0) return;
- int index;
- int theByte;
- int mask = 0;
- int n = getWidth;
- int i = startIndex;
- int srcX = x, srcY = y;
- if (depth == 1) {
- index = (y * bytesPerLine) + (x >> 3);
- theByte = data[index] & 0xFF;
- while (n > 1) {
- mask = 1 << (7 - (srcX & 0x7));
- if ((theByte & mask) == 0) {
- pixels[i] = 0;
- } else {
- pixels[i] = 1;
- }
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- if (n > 0) theByte = data[index] & 0xFF;
- srcX = 0;
- } else {
- if (mask == 1) {
- index++;
- if (n > 0) theByte = data[index] & 0xFF;
- }
- }
- }
- return;
- }
- if (depth == 2) {
- index = (y * bytesPerLine) + (x >> 2);
- theByte = data[index] & 0xFF;
- int offset;
- while (n > 0) {
- offset = 3 - (srcX % 4);
- mask = 3 << (offset * 2);
- pixels[i] = (byte)((theByte & mask) >> (offset * 2));
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- if (n > 0) theByte = data[index] & 0xFF;
- srcX = 0;
- } else {
- if (offset == 0) {
- index++;
- theByte = data[index] & 0xFF;
- }
- }
- }
- return;
- }
- if (depth == 4) {
- index = (y * bytesPerLine) + (x >> 1);
- if ((x & 0x1) == 1) {
- theByte = data[index] & 0xFF;
- pixels[i] = (byte)(theByte & 0x0F);
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index++;
- }
- }
- while (n > 1) {
- theByte = data[index] & 0xFF;
- pixels[i] = (byte)(theByte >> 4);
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- pixels[i] = (byte)(theByte & 0x0F);
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index++;
- }
- }
- }
- if (n > 0) {
- theByte = data[index] & 0xFF;
- pixels[i] = (byte)(theByte >> 4);
- }
- return;
- }
- if (depth == 8) {
- index = (y * bytesPerLine) + x;
- for (int j = 0; j < getWidth; j++) {
- pixels[i] = data[index];
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index++;
- }
- }
- return;
- }
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
-}
-
-/**
- * Returns <code>getWidth</code> pixel values starting at offset
- * <code>x</code> in scanline <code>y</code> in the receiver's
- * data starting at <code>startIndex</code>.
- *
- * @param x the x position of the first pixel to get
- * @param y the y position of the first pixel to get
- * @param getWidth the width of the data to get
- * @param pixels the buffer in which to put the pixels
- * @param startIndex the offset into the buffer to begin storing pixels
- *
- * @exception IndexOutOfBoundsException if getWidth is too large
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
- * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
- * </ul>
- */
-public void getPixels(int x, int y, int getWidth, int[] pixels, int startIndex) {
- if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- if (getWidth == 0) return;
- int index;
- int theByte;
- int mask;
- int n = getWidth;
- int i = startIndex;
- int srcX = x, srcY = y;
- if (depth == 1) {
- index = (y * bytesPerLine) + (x >> 3);
- theByte = data[index] & 0xFF;
- while (n > 0) {
- mask = 1 << (7 - (srcX & 0x7));
- if ((theByte & mask) == 0) {
- pixels[i] = 0;
- } else {
- pixels[i] = 1;
- }
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- if (n > 0) theByte = data[index] & 0xFF;
- srcX = 0;
- } else {
- if (mask == 1) {
- index++;
- if (n > 0) theByte = data[index] & 0xFF;
- }
- }
- }
- return;
- }
- if (depth == 2) {
- index = (y * bytesPerLine) + (x >> 2);
- theByte = data[index] & 0xFF;
- int offset;
- while (n > 0) {
- offset = 3 - (srcX % 4);
- mask = 3 << (offset * 2);
- pixels[i] = (byte)((theByte & mask) >> (offset * 2));
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- if (n > 0) theByte = data[index] & 0xFF;
- srcX = 0;
- } else {
- if (offset == 0) {
- index++;
- theByte = data[index] & 0xFF;
- }
- }
- }
- return;
- }
- if (depth == 4) {
- index = (y * bytesPerLine) + (x >> 1);
- if ((x & 0x1) == 1) {
- theByte = data[index] & 0xFF;
- pixels[i] = theByte & 0x0F;
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index++;
- }
- }
- while (n > 1) {
- theByte = data[index] & 0xFF;
- pixels[i] = theByte >> 4;
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- pixels[i] = theByte & 0x0F;
- i++;
- n--;
- srcX++;;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index++;
- }
- }
- }
- if (n > 0) {
- theByte = data[index] & 0xFF;
- pixels[i] = theByte >> 4;
- }
- return;
- }
- if (depth == 8) {
- index = (y * bytesPerLine) + x;
- for (int j = 0; j < getWidth; j++) {
- pixels[i] = data[index] & 0xFF;
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index++;
- }
- }
- return;
- }
- if (depth == 16) {
- index = (y * bytesPerLine) + (x * 2);
- for (int j = 0; j < getWidth; j++) {
- pixels[i] = ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF);
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index += 2;
- }
- }
- return;
- }
- if (depth == 24) {
- index = (y * bytesPerLine) + (x * 3);
- for (int j = 0; j < getWidth; j++) {
- pixels[i] = ((data[index] & 0xFF) << 16) | ((data[index+1] & 0xFF) << 8)
- | (data[index+2] & 0xFF);
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index += 3;
- }
- }
- return;
- }
- if (depth == 32) {
- index = (y * bytesPerLine) + (x * 4);
- i = startIndex;
- for (int j = 0; j < getWidth; j++) {
- pixels[i] = ((data[index] & 0xFF) << 24) | ((data[index+1] & 0xFF) << 16)
- | ((data[index+2] & 0xFF) << 8) | (data[index+3] & 0xFF);
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index += 4;
- }
- }
- return;
- }
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
-}
-
-/**
- * Returns an array of <code>RGB</code>s which comprise the
- * indexed color table of the receiver, or null if the receiver
- * has a direct color model.
- *
- * @return the RGB values for the image or null if direct color
- *
- * @see PaletteData#getRGBs
- */
-public RGB[] getRGBs() {
- return palette.getRGBs();
-}
-
-/**
- * Returns an <code>ImageData</code> which specifies the
- * transparency mask information for the receiver, or null if the
- * receiver has no transparency and is not an icon.
- *
- * @return the transparency mask or null if none exists
- */
-public ImageData getTransparencyMask() {
- if (getTransparencyType() == SWT.TRANSPARENCY_MASK) {
- return new ImageData(width, height, 1, bwPalette(), maskPad, maskData);
- } else {
- return colorMaskImage(transparentPixel);
- }
-}
-
-/**
- * Returns the image transparency type.
- *
- * @return the receiver's transparency type
- */
-public int getTransparencyType() {
- if (maskData != null) return SWT.TRANSPARENCY_MASK;
- if (transparentPixel != -1) return SWT.TRANSPARENCY_PIXEL;
- if (alphaData != null) return SWT.TRANSPARENCY_ALPHA;
- return SWT.TRANSPARENCY_NONE;
-}
-
-/**
- * Returns the byte order of the receiver.
- *
- * @return MSB_FIRST or LSB_FIRST
- */
-int getByteOrder() {
- return depth != 16 ? MSB_FIRST : LSB_FIRST;
-}
-
-/**
- * Returns a copy of the receiver which has been stretched or
- * shrunk to the specified size. If either the width or height
- * is negative, the resulting image will be inverted in the
- * associated axis.
- *
- * @param width the width of the new ImageData
- * @param height the height of the new ImageData
- * @return a scaled copy of the image
- */
-public ImageData scaledTo(int width, int height) {
- /* Create a destination image with no data */
- final boolean flipX = (width < 0);
- if (flipX) width = - width;
- final boolean flipY = (height < 0);
- if (flipY) height = - height;
-
- ImageData dest = new ImageData(
- width, height, depth, palette,
- scanlinePad, null, 0, null,
- null, -1, transparentPixel, type,
- x, y, disposalMethod, delayTime);
-
- /* Scale the image contents */
- if (palette.isDirect) blit(BLIT_SRC,
- this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, 0, 0, 0,
- ALPHA_OPAQUE, null, 0, 0, 0,
- dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, 0, 0, 0,
- flipX, flipY);
- else blit(BLIT_SRC,
- this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, null, null, null,
- ALPHA_OPAQUE, null, 0, 0, 0,
- dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, null, null, null,
- flipX, flipY);
-
- /* Scale the image mask or alpha */
- if (maskData != null) {
- dest.maskPad = this.maskPad;
- int destBpl = (dest.width + 7) / 8;
- destBpl = (destBpl + (dest.maskPad - 1)) / dest.maskPad * dest.maskPad;
- dest.maskData = new byte[destBpl * dest.height];
- int srcBpl = (this.width + 7) / 8;
- srcBpl = (srcBpl + (this.maskPad - 1)) / this.maskPad * this.maskPad;
- blit(BLIT_SRC,
- this.maskData, 1, srcBpl, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
- ALPHA_OPAQUE, null, 0, 0, 0,
- dest.maskData, 1, destBpl, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
- flipX, flipY);
- } else if (alpha != -1) {
- dest.alpha = this.alpha;
- } else if (alphaData != null) {
- dest.alphaData = new byte[dest.width * dest.height];
- blit(BLIT_SRC,
- this.alphaData, 8, this.width, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
- ALPHA_OPAQUE, null, 0, 0, 0,
- dest.alphaData, 8, dest.width, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
- flipX, flipY);
- }
- return dest;
-}
-
-/**
- * Sets the alpha value at offset <code>x</code> in
- * scanline <code>y</code> in the receiver's alpha data.
- *
- * @param x the x coordinate of the alpha value to set
- * @param y the y coordinate of the alpha value to set
- * @param alpha the value to set the alpha to
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
- * </ul>
- */
-public void setAlpha(int x, int y, int alpha) {
- if (x >= width || y >= height || x < 0 || y < 0 || alpha < 0 || alpha > 255)
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
-
- if (alphaData == null) alphaData = new byte[width * height];
- alphaData[y * width + x] = (byte)alpha;
-}
-
-/**
- * Sets the alpha values starting at offset <code>x</code> in
- * scanline <code>y</code> in the receiver's alpha data to the
- * values from the array <code>alphas</code> starting at
- * <code>startIndex</code>.
- *
- * @param x the x coordinate of the pixel to being setting the alpha values
- * @param y the y coordinate of the pixel to being setting the alpha values
- * @param putWidth the width of the alpha values to set
- * @param alphas the alpha values to set
- * @param startIndex the index at which to begin setting
- *
- * @exception IndexOutOfBoundsException if putWidth is too large
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
- * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
- * </ul>
- */
-public void setAlphas(int x, int y, int putWidth, byte[] alphas, int startIndex) {
- if (alphas == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- if (putWidth == 0) return;
-
- if (alphaData == null) alphaData = new byte[width * height];
- // may throw an IndexOutOfBoundsException
- System.arraycopy(alphas, startIndex, alphaData, y * width + x, putWidth);
-}
-
-/**
- * Sets the pixel value at offset <code>x</code> in
- * scanline <code>y</code> in the receiver's data.
- *
- * @param x the x coordinate of the pixel to set
- * @param y the y coordinate of the pixel to set
- * @param pixelValue the value to set the pixel to
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
- * </ul>
- */
-public void setPixel(int x, int y, int pixelValue) {
- if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- int index;
- byte theByte;
- int mask;
- if (depth == 1) {
- index = (y * bytesPerLine) + (x >> 3);
- theByte = data[index];
- mask = 1 << (7 - (x & 0x7));
- if ((pixelValue & 0x1) == 1) {
- data[index] = (byte)(theByte | mask);
- } else {
- data[index] = (byte)(theByte & (mask ^ -1));
- }
- return;
- }
- if (depth == 2) {
- index = (y * bytesPerLine) + (x >> 2);
- theByte = data[index];
- int offset = 3 - (x % 4);
- mask = 0xFF ^ (3 << (offset * 2));
- data[index] = (byte)((data[index] & mask) | (pixelValue << (offset * 2)));
- return;
- }
- if (depth == 4) {
- index = (y * bytesPerLine) + (x >> 1);
- if ((x & 0x1) == 0) {
- data[index] = (byte)((data[index] & 0x0F) | ((pixelValue & 0x0F) << 4));
- } else {
- data[index] = (byte)((data[index] & 0xF0) | (pixelValue & 0x0F));
- }
- return;
- }
- if (depth == 8) {
- index = (y * bytesPerLine) + x ;
- data[index] = (byte)(pixelValue & 0xFF);
- return;
- }
- if (depth == 16) {
- index = (y * bytesPerLine) + (x * 2);
- data[index + 1] = (byte)((pixelValue >> 8) & 0xFF);
- data[index] = (byte)(pixelValue & 0xFF);
- return;
- }
- if (depth == 24) {
- index = (y * bytesPerLine) + (x * 3);
- data[index] = (byte)((pixelValue >> 16) & 0xFF);
- data[index + 1] = (byte)((pixelValue >> 8) & 0xFF);
- data[index + 2] = (byte)(pixelValue & 0xFF);
- return;
- }
- if (depth == 32) {
- index = (y * bytesPerLine) + (x * 4);
- data[index] = (byte)((pixelValue >> 24) & 0xFF);
- data[index + 1] = (byte)((pixelValue >> 16) & 0xFF);
- data[index + 2] = (byte)((pixelValue >> 8) & 0xFF);
- data[index + 3] = (byte)(pixelValue & 0xFF);
- return;
- }
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
-}
-
-/**
- * Sets the pixel values starting at offset <code>x</code> in
- * scanline <code>y</code> in the receiver's data to the
- * values from the array <code>pixels</code> starting at
- * <code>startIndex</code>.
- *
- * @param x the x position of the pixel to set
- * @param y the y position of the pixel to set
- * @param putWidth the width of the pixels to set
- * @param pixels the pixels to set
- * @param startIndex the index at which to begin setting
- *
- * @exception IndexOutOfBoundsException if putWidth is too large
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
- * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8
- * (For higher depths, use the int[] version of this method.)</li>
- * </ul>
- */
-public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) {
- if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- if (putWidth == 0) return;
- int index;
- int theByte;
- int mask;
- int n = putWidth;
- int i = startIndex;
- int srcX = x, srcY = y;
- if (depth == 1) {
- index = (y * bytesPerLine) + (x >> 3);
- while (n > 0) {
- mask = 1 << (7 - (srcX & 0x7));
- if ((pixels[i] & 0x1) == 1) {
- data[index] = (byte)((data[index] & 0xFF) | mask);
- } else {
- data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1));
- }
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- if (mask == 1) {
- index++;
- }
- }
- }
- return;
- }
- if (depth == 2) {
- byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F };
- index = (y * bytesPerLine) + (x >> 2);
- int offset = 3 - (x % 4);
- while (n > 0) {
- theByte = pixels[i] & 0x3;
- data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- offset = 0;
- srcX = 0;
- } else {
- if (offset == 0) {
- index++;
- offset = 3;
- } else {
- offset--;
- }
- }
- }
- return;
- }
- if (depth == 4) {
- index = (y * bytesPerLine) + (x >> 1);
- boolean high = (x & 0x1) == 0;
- while (n > 0) {
- theByte = pixels[i] & 0x0F;
- if (high) {
- data[index] = (byte)((data[index] & 0x0F) | (theByte << 4));
- } else {
- data[index] = (byte)((data[index] & 0xF0) | theByte);
- }
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- high = true;
- srcX = 0;
- } else {
- if (!high) index++;
- high = !high;
- }
- }
- return;
- }
- if (depth == 8) {
- index = (y * bytesPerLine) + x;
- for (int j = 0; j < putWidth; j++) {
- data[index] = (byte)(pixels[i] & 0xFF);
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index++;
- }
- }
- return;
- }
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
-}
-
-/**
- * Sets the pixel values starting at offset <code>x</code> in
- * scanline <code>y</code> in the receiver's data to the
- * values from the array <code>pixels</code> starting at
- * <code>startIndex</code>.
- *
- * @param x the x position of the pixel to set
- * @param y the y position of the pixel to set
- * @param putWidth the width of the pixels to set
- * @param pixels the pixels to set
- * @param startIndex the index at which to begin setting
- *
- * @exception IndexOutOfBoundsException if putWidth is too large
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
- * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
- * </ul>
- */
-public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) {
- if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
- if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- if (putWidth == 0) return;
- int index;
- int theByte;
- int mask;
- int n = putWidth;
- int i = startIndex;
- int pixel;
- int srcX = x, srcY = y;
- if (depth == 1) {
- index = (y * bytesPerLine) + (x >> 3);
- while (n > 0) {
- mask = 1 << (7 - (srcX & 0x7));
- if ((pixels[i] & 0x1) == 1) {
- data[index] = (byte)((data[index] & 0xFF) | mask);
- } else {
- data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1));
- }
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- if (mask == 1) {
- index++;
- }
- }
- }
- return;
- }
- if (depth == 2) {
- byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F };
- index = (y * bytesPerLine) + (x >> 2);
- int offset = 3 - (x % 4);
- while (n > 0) {
- theByte = pixels[i] & 0x3;
- data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- offset = 3;
- srcX = 0;
- } else {
- if (offset == 0) {
- index++;
- offset = 3;
- } else {
- offset--;
- }
- }
- }
- return;
- }
- if (depth == 4) {
- index = (y * bytesPerLine) + (x >> 1);
- boolean high = (x & 0x1) == 0;
- while (n > 0) {
- theByte = pixels[i] & 0x0F;
- if (high) {
- data[index] = (byte)((data[index] & 0x0F) | (theByte << 4));
- } else {
- data[index] = (byte)((data[index] & 0xF0) | theByte);
- }
- i++;
- n--;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- high = true;
- srcX = 0;
- } else {
- if (!high) index++;
- high = !high;
- }
- }
- return;
- }
- if (depth == 8) {
- index = (y * bytesPerLine) + x;
- for (int j = 0; j < putWidth; j++) {
- data[index] = (byte)(pixels[i] & 0xFF);
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index++;
- }
- }
- return;
-
- }
- if (depth == 16) {
- index = (y * bytesPerLine) + (x * 2);
- for (int j = 0; j < putWidth; j++) {
- pixel = pixels[i];
- data[index] = (byte)(pixel & 0xFF);
- data[index + 1] = (byte)((pixel >> 8) & 0xFF);
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index += 2;
- }
- }
- return;
- }
- if (depth == 24) {
- index = (y * bytesPerLine) + (x * 3);
- for (int j = 0; j < putWidth; j++) {
- pixel = pixels[i];
- data[index] = (byte)((pixel >> 16) & 0xFF);
- data[index + 1] = (byte)((pixel >> 8) & 0xFF);
- data[index + 2] = (byte)(pixel & 0xFF);
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index += 3;
- }
- }
- return;
- }
- if (depth == 32) {
- index = (y * bytesPerLine) + (x * 4);
- for (int j = 0; j < putWidth; j++) {
- pixel = pixels[i];
- data[index] = (byte)((pixel >> 24) & 0xFF);
- data[index + 1] = (byte)((pixel >> 16) & 0xFF);
- data[index + 2] = (byte)((pixel >> 8) & 0xFF);
- data[index + 3] = (byte)(pixel & 0xFF);
- i++;
- srcX++;
- if (srcX >= width) {
- srcY++;
- index = srcY * bytesPerLine;
- srcX = 0;
- } else {
- index += 4;
- }
- }
- return;
- }
- SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
-}
-
-/**
- * Returns a palette with 2 colors: black & white.
- */
-static PaletteData bwPalette() {
- return new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255, 255, 255)});
-}
-
-/**
- * Gets the offset of the most significant bit for
- * the given mask.
- */
-static int getMSBOffset(int mask) {
- for (int i = 31; i >= 0; i--) {
- if (((mask >> i) & 0x1) != 0) return i + 1;
- }
- return 0;
-}
-
-/**
- * Finds the closest match.
- */
-static int closestMatch(int depth, byte red, byte green, byte blue, int redMask, int greenMask, int blueMask, byte[] reds, byte[] greens, byte[] blues) {
- if (depth > 8) {
- int rshift = 32 - getMSBOffset(redMask);
- int gshift = 32 - getMSBOffset(greenMask);
- int bshift = 32 - getMSBOffset(blueMask);
- return (((red << 24) >>> rshift) & redMask) |
- (((green << 24) >>> gshift) & greenMask) |
- (((blue << 24) >>> bshift) & blueMask);
- }
- int r, g, b;
- int minDistance = 0x7fffffff;
- int nearestPixel = 0;
- int n = reds.length;
- for (int j = 0; j < n; j++) {
- r = (reds[j] & 0xFF) - (red & 0xFF);
- g = (greens[j] & 0xFF) - (green & 0xFF);
- b = (blues[j] & 0xFF) - (blue & 0xFF);
- int distance = r*r + g*g + b*b;
- if (distance < minDistance) {
- nearestPixel = j;
- if (distance == 0) break;
- minDistance = distance;
- }
- }
- return nearestPixel;
-}
-
-/**
- * Blit operation bits to be OR'ed together to specify the desired operation.
- */
-static final int
- BLIT_SRC = 1, // copy source directly, else applies logic operations
- BLIT_ALPHA = 2, // enable alpha blending
- BLIT_DITHER = 4; // enable dithering in low color modes
-
-/**
- * Alpha mode, values 0 - 255 specify global alpha level
- */
-static final int
- ALPHA_OPAQUE = 255, // Fully opaque (ignores any alpha data)
- ALPHA_TRANSPARENT = 0, // Fully transparent (ignores any alpha data)
- ALPHA_CHANNEL_SEPARATE = -1, // Use alpha channel from separate alphaData
- ALPHA_CHANNEL_SOURCE = -2, // Use alpha channel embedded in sourceData
- ALPHA_MASK_UNPACKED = -3, // Use transparency mask formed by bytes in alphaData (non-zero is opaque)
- ALPHA_MASK_PACKED = -4, // Use transparency mask formed by packed bits in alphaData
- ALPHA_MASK_INDEX = -5, // Consider source palette indices transparent if in alphaData array
- ALPHA_MASK_RGB = -6; // Consider source RGBs transparent if in RGB888 format alphaData array
-
-/**
- * Byte and bit order constants.
- */
-static final int LSB_FIRST = 0;
-static final int MSB_FIRST = 1;
-
-/**
- * Data types (internal)
- */
-private static final int
- // direct / true color formats with arbitrary masks & shifts
- TYPE_GENERIC_8 = 0,
- TYPE_GENERIC_16_MSB = 1,
- TYPE_GENERIC_16_LSB = 2,
- TYPE_GENERIC_24 = 3,
- TYPE_GENERIC_32_MSB = 4,
- TYPE_GENERIC_32_LSB = 5,
- // palette indexed color formats
- TYPE_INDEX_8 = 6,
- TYPE_INDEX_4 = 7,
- TYPE_INDEX_2 = 8,
- TYPE_INDEX_1_MSB = 9,
- TYPE_INDEX_1_LSB = 10;
-
-/**
- * Blits a direct palette image into a direct palette image.
- * <p>
- * Note: When the source and destination depth, order and masks
- * are pairwise equal and the blitter operation is BLIT_SRC,
- * the masks are ignored. Hence when not changing the image
- * data format, 0 may be specified for the masks.
- * </p>
- *
- * @param op the blitter operation: a combination of BLIT_xxx flags
- * (see BLIT_xxx constants)
- * @param srcData the source byte array containing image data
- * @param srcDepth the source depth: one of 8, 16, 24, 32
- * @param srcStride the source number of bytes per line
- * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
- * ignored if srcDepth is not 16 or 32
- * @param srcX the top-left x-coord of the source blit region
- * @param srcY the top-left y-coord of the source blit region
- * @param srcWidth the width of the source blit region
- * @param srcHeight the height of the source blit region
- * @param srcRedMask the source red channel mask
- * @param srcGreenMask the source green channel mask
- * @param srcBlueMask the source blue channel mask
- * @param alphaMode the alpha blending or mask mode, may be
- * an integer 0-255 for global alpha; ignored if BLIT_ALPHA
- * not specified in the blitter operations
- * (see ALPHA_MODE_xxx constants)
- * @param alphaData the alpha blending or mask data, varies depending
- * on the value of alphaMode and sometimes ignored
- * @param alphaStride the alpha data number of bytes per line
- * @param alphaX the top-left x-coord of the alpha blit region
- * @param alphaY the top-left y-coord of the alpha blit region
- * @param destData the destination byte array containing image data
- * @param destDepth the destination depth: one of 8, 16, 24, 32
- * @param destStride the destination number of bytes per line
- * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
- * ignored if destDepth is not 16 or 32
- * @param destX the top-left x-coord of the destination blit region
- * @param destY the top-left y-coord of the destination blit region
- * @param destWidth the width of the destination blit region
- * @param destHeight the height of the destination blit region
- * @param destRedMask the destination red channel mask
- * @param destGreenMask the destination green channel mask
- * @param destBlueMask the destination blue channel mask
- * @param flipX if true the resulting image is flipped along the vertical axis
- * @param flipY if true the resulting image is flipped along the horizontal axis
- */
-static void blit(int op,
- byte[] srcData, int srcDepth, int srcStride, int srcOrder,
- int srcX, int srcY, int srcWidth, int srcHeight,
- int srcRedMask, int srcGreenMask, int srcBlueMask,
- int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
- byte[] destData, int destDepth, int destStride, int destOrder,
- int destX, int destY, int destWidth, int destHeight,
- int destRedMask, int destGreenMask, int destBlueMask,
- boolean flipX, boolean flipY) {
- if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
-
- // these should be supplied as params later
- final int srcAlphaMask = 0, destAlphaMask = 0;
-
- /*** Prepare scaling data ***/
- final int dwm1 = destWidth - 1;
- final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
- final int dhm1 = destHeight - 1;
- final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
-
- /*** Prepare source-related data ***/
- final int sbpp, stype;
- switch (srcDepth) {
- case 8:
- sbpp = 1;
- stype = TYPE_GENERIC_8;
- break;
- case 16:
- sbpp = 2;
- stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
- break;
- case 24:
- sbpp = 3;
- stype = TYPE_GENERIC_24;
- break;
- case 32:
- sbpp = 4;
- stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
- break;
- default:
- //throw new IllegalArgumentException("Invalid source type");
- return;
- }
- int spr = srcY * srcStride + srcX * sbpp;
-
- /*** Prepare destination-related data ***/
- final int dbpp, dtype;
- switch (destDepth) {
- case 8:
- dbpp = 1;
- dtype = TYPE_GENERIC_8;
- break;
- case 16:
- dbpp = 2;
- dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
- break;
- case 24:
- dbpp = 3;
- dtype = TYPE_GENERIC_24;
- break;
- case 32:
- dbpp = 4;
- dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
- break;
- default:
- //throw new IllegalArgumentException("Invalid destination type");
- return;
- }
- int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp;
- final int dprxi = (flipX) ? -dbpp : dbpp;
- final int dpryi = (flipY) ? -destStride : destStride;
-
- /*** Prepare special processing data ***/
- int apr;
- if ((op & BLIT_ALPHA) != 0) {
- switch (alphaMode) {
- case ALPHA_MASK_UNPACKED:
- case ALPHA_CHANNEL_SEPARATE:
- if (alphaData == null) alphaMode = 0x10000;
- apr = alphaY * alphaStride + alphaX;
- break;
- case ALPHA_MASK_PACKED:
- if (alphaData == null) alphaMode = 0x10000;
- alphaStride <<= 3;
- apr = alphaY * alphaStride + alphaX;
- break;
- case ALPHA_MASK_INDEX:
- //throw new IllegalArgumentException("Invalid alpha type");
- return;
- case ALPHA_MASK_RGB:
- if (alphaData == null) alphaMode = 0x10000;
- apr = 0;
- break;
- default:
- alphaMode = (alphaMode << 16) / 255; // prescale
- case ALPHA_CHANNEL_SOURCE:
- apr = 0;
- break;
- }
- } else {
- alphaMode = 0x10000;
- apr = 0;
- }
-
- /*** Blit ***/
- int dp = dpr;
- int sp = spr;
- if ((alphaMode == 0x10000) && (stype == dtype) &&
- (srcRedMask == destRedMask) && (srcGreenMask == destGreenMask) &&
- (srcBlueMask == destBlueMask) && (srcAlphaMask == destAlphaMask)) {
- /*** Fast blit (straight copy) ***/
- switch (sbpp) {
- case 1:
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
- destData[dp] = srcData[sp];
- sp += (sfx >>> 16);
- }
- }
- break;
- case 2:
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
- destData[dp] = srcData[sp];
- destData[dp + 1] = srcData[sp + 1];
- sp += (sfx >>> 16) * 2;
- }
- }
- break;
- case 3:
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
- destData[dp] = srcData[sp];
- destData[dp + 1] = srcData[sp + 1];
- destData[dp + 2] = srcData[sp + 2];
- sp += (sfx >>> 16) * 3;
- }
- }
- break;
- case 4:
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
- destData[dp] = srcData[sp];
- destData[dp + 1] = srcData[sp + 1];
- destData[dp + 2] = srcData[sp + 2];
- destData[dp + 3] = srcData[sp + 3];
- sp += (sfx >>> 16) * 4;
- }
- }
- break;
- }
- return;
- }
- /*** Comprehensive blit (apply transformations) ***/
- final int srcRedShift = getChannelShift(srcRedMask);
- final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)];
- final int srcGreenShift = getChannelShift(srcGreenMask);
- final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)];
- final int srcBlueShift = getChannelShift(srcBlueMask);
- final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)];
- final int srcAlphaShift = getChannelShift(srcAlphaMask);
- final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)];
-
- final int destRedShift = getChannelShift(destRedMask);
- final int destRedWidth = getChannelWidth(destRedMask, destRedShift);
- final byte[] destReds = ANY_TO_EIGHT[destRedWidth];
- final int destRedPreShift = 8 - destRedWidth;
- final int destGreenShift = getChannelShift(destGreenMask);
- final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift);
- final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth];
- final int destGreenPreShift = 8 - destGreenWidth;
- final int destBlueShift = getChannelShift(destBlueMask);
- final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift);
- final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth];
- final int destBluePreShift = 8 - destBlueWidth;
- final int destAlphaShift = getChannelShift(destAlphaMask);
- final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift);
- final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth];
- final int destAlphaPreShift = 8 - destAlphaWidth;
-
- int ap = apr, alpha = alphaMode;
- int r = 0, g = 0, b = 0, a = 0;
- int rq = 0, gq = 0, bq = 0, aq = 0;
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
- sp = spr += (sfy >>> 16) * srcStride,
- ap = apr += (sfy >>> 16) * alphaStride,
- sfy = (sfy & 0xffff) + sfyi,
- dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
- dp += dprxi,
- sfx = (sfx & 0xffff) + sfxi) {
- /*** READ NEXT PIXEL ***/
- switch (stype) {
- case TYPE_GENERIC_8: {
- final int data = srcData[sp] & 0xff;
- sp += (sfx >>> 16);
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_16_MSB: {
- final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff);
- sp += (sfx >>> 16) * 2;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_16_LSB: {
- final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff);
- sp += (sfx >>> 16) * 2;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_24: {
- final int data = (( ((srcData[sp] & 0xff) << 8) |
- (srcData[sp + 1] & 0xff)) << 8) |
- (srcData[sp + 2] & 0xff);
- sp += (sfx >>> 16) * 3;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_32_MSB: {
- final int data = (( (( ((srcData[sp] & 0xff) << 8) |
- (srcData[sp + 1] & 0xff)) << 8) |
- (srcData[sp + 2] & 0xff)) << 8) |
- (srcData[sp + 3] & 0xff);
- sp += (sfx >>> 16) * 4;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_32_LSB: {
- final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) |
- (srcData[sp + 2] & 0xff)) << 8) |
- (srcData[sp + 1] & 0xff)) << 8) |
- (srcData[sp] & 0xff);
- sp += (sfx >>> 16) * 4;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- }
-
- /*** DO SPECIAL PROCESSING IF REQUIRED ***/
- switch (alphaMode) {
- case ALPHA_CHANNEL_SEPARATE:
- alpha = ((alphaData[ap] & 0xff) << 16) / 255;
- ap += (sfx >> 16);
- break;
- case ALPHA_CHANNEL_SOURCE:
- alpha = (a << 16) / 255;
- break;
- case ALPHA_MASK_UNPACKED:
- alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_PACKED:
- alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_RGB:
- alpha = 0x10000;
- for (int i = 0; i < alphaData.length; i += 3) {
- if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) {
- alpha = 0x0000;
- break;
- }
- }
- break;
- }
- if (alpha != 0x10000) {
- if (alpha == 0x0000) continue;
- switch (dtype) {
- case TYPE_GENERIC_8: {
- final int data = destData[dp] & 0xff;
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_16_MSB: {
- final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_16_LSB: {
- final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_24: {
- final int data = (( ((destData[dp] & 0xff) << 8) |
- (destData[dp + 1] & 0xff)) << 8) |
- (destData[dp + 2] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_32_MSB: {
- final int data = (( (( ((destData[dp] & 0xff) << 8) |
- (destData[dp + 1] & 0xff)) << 8) |
- (destData[dp + 2] & 0xff)) << 8) |
- (destData[dp + 3] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_32_LSB: {
- final int data = (( (( ((destData[dp + 3] & 0xff) << 8) |
- (destData[dp + 2] & 0xff)) << 8) |
- (destData[dp + 1] & 0xff)) << 8) |
- (destData[dp] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- }
- // Perform alpha blending
- a = aq + ((a - aq) * alpha >> 16);
- r = rq + ((r - rq) * alpha >> 16);
- g = gq + ((g - gq) * alpha >> 16);
- b = bq + ((b - bq) * alpha >> 16);
- }
-
- /*** WRITE NEXT PIXEL ***/
- final int data =
- (r >>> destRedPreShift << destRedShift) |
- (g >>> destGreenPreShift << destGreenShift) |
- (b >>> destBluePreShift << destBlueShift) |
- (a >>> destAlphaPreShift << destAlphaShift);
- switch (dtype) {
- case TYPE_GENERIC_8: {
- destData[dp] = (byte) data;
- } break;
- case TYPE_GENERIC_16_MSB: {
- destData[dp] = (byte) (data >>> 8);
- destData[dp + 1] = (byte) (data & 0xff);
- } break;
- case TYPE_GENERIC_16_LSB: {
- destData[dp] = (byte) (data & 0xff);
- destData[dp + 1] = (byte) (data >>> 8);
- } break;
- case TYPE_GENERIC_24: {
- destData[dp] = (byte) (data >>> 16);
- destData[dp + 1] = (byte) (data >>> 8);
- destData[dp + 2] = (byte) (data & 0xff);
- } break;
- case TYPE_GENERIC_32_MSB: {
- destData[dp] = (byte) (data >>> 24);
- destData[dp + 1] = (byte) (data >>> 16);
- destData[dp + 2] = (byte) (data >>> 8);
- destData[dp + 3] = (byte) (data & 0xff);
- } break;
- case TYPE_GENERIC_32_LSB: {
- destData[dp] = (byte) (data & 0xff);
- destData[dp + 1] = (byte) (data >>> 8);
- destData[dp + 2] = (byte) (data >>> 16);
- destData[dp + 3] = (byte) (data >>> 24);
- } break;
- }
- }
- }
-}
-
-/**
- * Blits an index palette image into an index palette image.
- * <p>
- * Note: The source and destination red, green, and blue
- * arrays may be null if no alpha blending or dither is to be
- * performed.
- * </p>
- *
- * @param op the blitter operation: a combination of BLIT_xxx flags
- * (see BLIT_xxx constants)
- * @param srcData the source byte array containing image data
- * @param srcDepth the source depth: one of 1, 2, 4, 8
- * @param srcStride the source number of bytes per line
- * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
- * ignored if srcDepth is not 1
- * @param srcX the top-left x-coord of the source blit region
- * @param srcY the top-left y-coord of the source blit region
- * @param srcWidth the width of the source blit region
- * @param srcHeight the height of the source blit region
- * @param srcReds the source palette red component intensities
- * @param srcGreens the source palette green component intensities
- * @param srcBlues the source palette blue component intensities
- * @param alphaMode the alpha blending or mask mode, may be
- * an integer 0-255 for global alpha; ignored if BLIT_ALPHA
- * not specified in the blitter operations
- * (see ALPHA_MODE_xxx constants)
- * @param alphaData the alpha blending or mask data, varies depending
- * on the value of alphaMode and sometimes ignored
- * @param alphaStride the alpha data number of bytes per line
- * @param alphaX the top-left x-coord of the alpha blit region
- * @param alphaY the top-left y-coord of the alpha blit region
- * @param destData the destination byte array containing image data
- * @param destDepth the destination depth: one of 1, 2, 4, 8
- * @param destStride the destination number of bytes per line
- * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
- * ignored if destDepth is not 1
- * @param destX the top-left x-coord of the destination blit region
- * @param destY the top-left y-coord of the destination blit region
- * @param destWidth the width of the destination blit region
- * @param destHeight the height of the destination blit region
- * @param destReds the destination palette red component intensities
- * @param destGreens the destination palette green component intensities
- * @param destBlues the destination palette blue component intensities
- * @param flipX if true the resulting image is flipped along the vertical axis
- * @param flipY if true the resulting image is flipped along the horizontal axis
- */
-static void blit(int op,
- byte[] srcData, int srcDepth, int srcStride, int srcOrder,
- int srcX, int srcY, int srcWidth, int srcHeight,
- byte[] srcReds, byte[] srcGreens, byte[] srcBlues,
- int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
- byte[] destData, int destDepth, int destStride, int destOrder,
- int destX, int destY, int destWidth, int destHeight,
- byte[] destReds, byte[] destGreens, byte[] destBlues,
- boolean flipX, boolean flipY) {
- if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
-
- /*** Prepare scaling data ***/
- final int dwm1 = destWidth - 1;
- final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
- final int dhm1 = destHeight - 1;
- final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
-
- /*** Prepare source-related data ***/
- final int stype;
- switch (srcDepth) {
- case 8:
- stype = TYPE_INDEX_8;
- break;
- case 4:
- srcStride <<= 1;
- stype = TYPE_INDEX_4;
- break;
- case 2:
- srcStride <<= 2;
- stype = TYPE_INDEX_2;
- break;
- case 1:
- srcStride <<= 3;
- stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
- break;
- default:
- //throw new IllegalArgumentException("Invalid source type");
- return;
- }
- int spr = srcY * srcStride + srcX;
-
- /*** Prepare destination-related data ***/
- final int dtype;
- switch (destDepth) {
- case 8:
- dtype = TYPE_INDEX_8;
- break;
- case 4:
- destStride <<= 1;
- dtype = TYPE_INDEX_4;
- break;
- case 2:
- destStride <<= 2;
- dtype = TYPE_INDEX_2;
- break;
- case 1:
- destStride <<= 3;
- dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
- break;
- default:
- //throw new IllegalArgumentException("Invalid source type");
- return;
- }
- int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX);
- final int dprxi = (flipX) ? -1 : 1;
- final int dpryi = (flipY) ? -destStride : destStride;
-
- /*** Prepare special processing data ***/
- int apr;
- if ((op & BLIT_ALPHA) != 0) {
- switch (alphaMode) {
- case ALPHA_MASK_UNPACKED:
- case ALPHA_CHANNEL_SEPARATE:
- if (alphaData == null) alphaMode = 0x10000;
- apr = alphaY * alphaStride + alphaX;
- break;
- case ALPHA_MASK_PACKED:
- if (alphaData == null) alphaMode = 0x10000;
- alphaStride <<= 3;
- apr = alphaY * alphaStride + alphaX;
- break;
- case ALPHA_MASK_INDEX:
- case ALPHA_MASK_RGB:
- if (alphaData == null) alphaMode = 0x10000;
- apr = 0;
- break;
- default:
- alphaMode = (alphaMode << 16) / 255; // prescale
- case ALPHA_CHANNEL_SOURCE:
- apr = 0;
- break;
- }
- } else {
- alphaMode = 0x10000;
- apr = 0;
- }
- final boolean ditherEnabled = (op & BLIT_DITHER) != 0;
-
- /*** Blit ***/
- int dp = dpr;
- int sp = spr;
- int ap = apr;
- int destPaletteSize = 1 << destDepth;
- if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length;
- byte[] paletteMapping = null;
- boolean isExactPaletteMapping = true;
- switch (alphaMode) {
- case 0x10000:
- /*** If the palettes and formats are equivalent use a one-to-one mapping ***/
- if ((stype == dtype) &&
- (srcReds == destReds) && (srcGreens == destGreens) && (srcBlues == destBlues)) {
- paletteMapping = ONE_TO_ONE_MAPPING;
- break;
- /*** If palettes have not been supplied, supply a suitable mapping ***/
- } else if ((srcReds == null) || (destReds == null)) {
- if (srcDepth <= destDepth) {
- paletteMapping = ONE_TO_ONE_MAPPING;
- } else {
- paletteMapping = new byte[1 << srcDepth];
- int mask = (0xff << destDepth) >>> 8;
- for (int i = 0; i < paletteMapping.length; ++i) paletteMapping[i] = (byte)(i & mask);
- }
- break;
- }
- case ALPHA_MASK_UNPACKED:
- case ALPHA_MASK_PACKED:
- case ALPHA_MASK_INDEX:
- case ALPHA_MASK_RGB:
- /*** Generate a palette mapping ***/
- int srcPaletteSize = 1 << srcDepth;
- paletteMapping = new byte[srcPaletteSize];
- if ((srcReds != null) && (srcReds.length < srcPaletteSize)) srcPaletteSize = srcReds.length;
- for (int i = 0, r, g, b, index; i < srcPaletteSize; ++i) {
- r = srcReds[i] & 0xff;
- g = srcGreens[i] & 0xff;
- b = srcBlues[i] & 0xff;
- index = 0;
- int minDistance = 0x7fffffff;
- for (int j = 0, dr, dg, db, distance; j < destPaletteSize; ++j) {
- dr = (destReds[j] & 0xff) - r;
- dg = (destGreens[j] & 0xff) - g;
- db = (destBlues[j] & 0xff) - b;
- distance = dr * dr + dg * dg + db * db;
- if (distance < minDistance) {
- index = j;
- if (distance == 0) break;
- minDistance = distance;
- }
- }
- paletteMapping[i] = (byte)index;
- if (minDistance != 0) isExactPaletteMapping = false;
- }
- break;
- }
- if ((paletteMapping != null) && (isExactPaletteMapping || ! ditherEnabled)) {
- if ((stype == dtype) && (alphaMode == 0x10000)) {
- /*** Fast blit (copy w/ mapping) ***/
- switch (stype) {
- case TYPE_INDEX_8:
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
- destData[dp] = paletteMapping[srcData[sp] & 0xff];
- sp += (sfx >>> 16);
- }
- }
- break;
- case TYPE_INDEX_4:
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
- final int v;
- if ((sp & 1) != 0) v = paletteMapping[srcData[sp >> 1] & 0x0f];
- else v = (srcData[sp >> 1] >>> 4) & 0x0f;
- sp += (sfx >>> 16);
- if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | v);
- else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (v << 4));
- }
- }
- break;
- case TYPE_INDEX_2:
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
- final int index = paletteMapping[(srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03];
- sp += (sfx >>> 16);
- final int shift = 6 - (dp & 3) * 2;
- destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift));
- }
- }
- break;
- case TYPE_INDEX_1_MSB:
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
- final int index = paletteMapping[(srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01];
- sp += (sfx >>> 16);
- final int shift = 7 - (dp & 7);
- destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
- }
- }
- break;
- case TYPE_INDEX_1_LSB:
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
- final int index = paletteMapping[(srcData[sp >> 3] >>> (sp & 7)) & 0x01];
- sp += (sfx >>> 16);
- final int shift = dp & 7;
- destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
- }
- }
- break;
- }
- } else {
- /*** Convert between indexed modes using mapping and mask ***/
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
- sp = spr += (sfy >>> 16) * srcStride,
- sfy = (sfy & 0xffff) + sfyi,
- dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
- dp += dprxi,
- sfx = (sfx & 0xffff) + sfxi) {
- int index;
- /*** READ NEXT PIXEL ***/
- switch (stype) {
- case TYPE_INDEX_8:
- index = srcData[sp] & 0xff;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_4:
- if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f;
- else index = (srcData[sp >> 1] >>> 4) & 0x0f;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_2:
- index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_1_MSB:
- index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_1_LSB:
- index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
- sp += (sfx >>> 16);
- break;
- default:
- return;
- }
- /*** APPLY MASK ***/
- switch (alphaMode) {
- case ALPHA_MASK_UNPACKED: {
- final byte mask = alphaData[ap];
- ap += (sfx >> 16);
- if (mask == 0) continue;
- } break;
- case ALPHA_MASK_PACKED: {
- final int mask = alphaData[ap >> 3] & (1 << (ap & 7));
- ap += (sfx >> 16);
- if (mask == 0) continue;
- } break;
- case ALPHA_MASK_INDEX: {
- int i = 0;
- while (i < alphaData.length) {
- if (index == (alphaData[i] & 0xff)) break;
- }
- if (i < alphaData.length) continue;
- } break;
- case ALPHA_MASK_RGB: {
- final byte r = srcReds[index], g = srcGreens[index], b = srcBlues[index];
- int i = 0;
- while (i < alphaData.length) {
- if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) break;
- i += 3;
- }
- if (i < alphaData.length) continue;
- } break;
- }
- index = paletteMapping[index] & 0xff;
-
- /*** WRITE NEXT PIXEL ***/
- switch (dtype) {
- case TYPE_INDEX_8:
- destData[dp] = (byte) index;
- break;
- case TYPE_INDEX_4:
- if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | index);
- else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (index << 4));
- break;
- case TYPE_INDEX_2: {
- final int shift = 6 - (dp & 3) * 2;
- destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift));
- } break;
- case TYPE_INDEX_1_MSB: {
- final int shift = 7 - (dp & 7);
- destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
- } break;
- case TYPE_INDEX_1_LSB: {
- final int shift = dp & 7;
- destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
- } break;
- }
- }
- }
- }
- return;
- }
-
- /*** Comprehensive blit (apply transformations) ***/
- int alpha = alphaMode;
- int index = 0;
- int indexq = 0;
- int lastindex = 0, lastr = -1, lastg = -1, lastb = -1;
- final int[] rerr, gerr, berr;
- if (ditherEnabled) {
- rerr = new int[destWidth + 2];
- gerr = new int[destWidth + 2];
- berr = new int[destWidth + 2];
- } else {
- rerr = null; gerr = null; berr = null;
- }
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
- sp = spr += (sfy >>> 16) * srcStride,
- ap = apr += (sfy >>> 16) * alphaStride,
- sfy = (sfy & 0xffff) + sfyi,
- dp = dpr += dpryi) {
- int lrerr = 0, lgerr = 0, lberr = 0;
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
- dp += dprxi,
- sfx = (sfx & 0xffff) + sfxi) {
- /*** READ NEXT PIXEL ***/
- switch (stype) {
- case TYPE_INDEX_8:
- index = srcData[sp] & 0xff;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_4:
- if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f;
- else index = (srcData[sp >> 1] >>> 4) & 0x0f;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_2:
- index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_1_MSB:
- index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_1_LSB:
- index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
- sp += (sfx >>> 16);
- break;
- }
-
- /*** DO SPECIAL PROCESSING IF REQUIRED ***/
- int r = srcReds[index] & 0xff, g = srcGreens[index] & 0xff, b = srcBlues[index] & 0xff;
- switch (alphaMode) {
- case ALPHA_CHANNEL_SEPARATE:
- alpha = ((alphaData[ap] & 0xff) << 16) / 255;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_UNPACKED:
- alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_PACKED:
- alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices
- int i = 0;
- while (i < alphaData.length) {
- if (index == (alphaData[i] & 0xff)) break;
- }
- if (i < alphaData.length) continue;
- } break;
- case ALPHA_MASK_RGB: {
- int i = 0;
- while (i < alphaData.length) {
- if ((r == (alphaData[i] & 0xff)) &&
- (g == (alphaData[i + 1] & 0xff)) &&
- (b == (alphaData[i + 2] & 0xff))) break;
- i += 3;
- }
- if (i < alphaData.length) continue;
- } break;
- }
- if (alpha != 0x10000) {
- if (alpha == 0x0000) continue;
- switch (dtype) {
- case TYPE_INDEX_8:
- indexq = destData[dp] & 0xff;
- break;
- case TYPE_INDEX_4:
- if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f;
- else indexq = (destData[dp >> 1] >>> 4) & 0x0f;
- break;
- case TYPE_INDEX_2:
- indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03;
- break;
- case TYPE_INDEX_1_MSB:
- indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01;
- break;
- case TYPE_INDEX_1_LSB:
- indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01;
- break;
- }
- // Perform alpha blending
- final int rq = destReds[indexq] & 0xff;
- final int gq = destGreens[indexq] & 0xff;
- final int bq = destBlues[indexq] & 0xff;
- r = rq + ((r - rq) * alpha >> 16);
- g = gq + ((g - gq) * alpha >> 16);
- b = bq + ((b - bq) * alpha >> 16);
- }
-
- /*** MAP COLOR TO THE PALETTE ***/
- if (ditherEnabled) {
- // Floyd-Steinberg error diffusion
- r += rerr[dx] >> 4;
- if (r < 0) r = 0; else if (r > 255) r = 255;
- g += gerr[dx] >> 4;
- if (g < 0) g = 0; else if (g > 255) g = 255;
- b += berr[dx] >> 4;
- if (b < 0) b = 0; else if (b > 255) b = 255;
- rerr[dx] = lrerr;
- gerr[dx] = lgerr;
- berr[dx] = lberr;
- }
- if (r != lastr || g != lastg || b != lastb) {
- // moving the variable declarations out seems to make the JDK JIT happier...
- for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) {
- dr = (destReds[j] & 0xff) - r;
- dg = (destGreens[j] & 0xff) - g;
- db = (destBlues[j] & 0xff) - b;
- distance = dr * dr + dg * dg + db * db;
- if (distance < minDistance) {
- lastindex = j;
- if (distance == 0) break;
- minDistance = distance;
- }
- }
- lastr = r; lastg = g; lastb = b;
- }
- if (ditherEnabled) {
- // Floyd-Steinberg error diffusion, cont'd...
- final int dxm1 = dx - 1, dxp1 = dx + 1;
- int acc;
- rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr;
- rerr[dx] += acc += lrerr + lrerr;
- rerr[dxm1] += acc + lrerr + lrerr;
- gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr;
- gerr[dx] += acc += lgerr + lgerr;
- gerr[dxm1] += acc + lgerr + lgerr;
- berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr;
- berr[dx] += acc += lberr + lberr;
- berr[dxm1] += acc + lberr + lberr;
- }
-
- /*** WRITE NEXT PIXEL ***/
- switch (dtype) {
- case TYPE_INDEX_8:
- destData[dp] = (byte) lastindex;
- break;
- case TYPE_INDEX_4:
- if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex);
- else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4));
- break;
- case TYPE_INDEX_2: {
- final int shift = 6 - (dp & 3) * 2;
- destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift));
- } break;
- case TYPE_INDEX_1_MSB: {
- final int shift = 7 - (dp & 7);
- destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
- } break;
- case TYPE_INDEX_1_LSB: {
- final int shift = dp & 7;
- destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
- } break;
- }
- }
- }
-}
-
-/**
- * Blits an index palette image into a direct palette image.
- * <p>
- * Note: The source and destination masks and palettes must
- * always be fully specified.
- * </p>
- *
- * @param op the blitter operation: a combination of BLIT_xxx flags
- * (see BLIT_xxx constants)
- * @param srcData the source byte array containing image data
- * @param srcDepth the source depth: one of 1, 2, 4, 8
- * @param srcStride the source number of bytes per line
- * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
- * ignored if srcDepth is not 1
- * @param srcX the top-left x-coord of the source blit region
- * @param srcY the top-left y-coord of the source blit region
- * @param srcWidth the width of the source blit region
- * @param srcHeight the height of the source blit region
- * @param srcReds the source palette red component intensities
- * @param srcGreens the source palette green component intensities
- * @param srcBlues the source palette blue component intensities
- * @param alphaMode the alpha blending or mask mode, may be
- * an integer 0-255 for global alpha; ignored if BLIT_ALPHA
- * not specified in the blitter operations
- * (see ALPHA_MODE_xxx constants)
- * @param alphaData the alpha blending or mask data, varies depending
- * on the value of alphaMode and sometimes ignored
- * @param alphaStride the alpha data number of bytes per line
- * @param alphaX the top-left x-coord of the alpha blit region
- * @param alphaY the top-left y-coord of the alpha blit region
- * @param destData the destination byte array containing image data
- * @param destDepth the destination depth: one of 8, 16, 24, 32
- * @param destStride the destination number of bytes per line
- * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
- * ignored if destDepth is not 16 or 32
- * @param destX the top-left x-coord of the destination blit region
- * @param destY the top-left y-coord of the destination blit region
- * @param destWidth the width of the destination blit region
- * @param destHeight the height of the destination blit region
- * @param destRedMask the destination red channel mask
- * @param destGreenMask the destination green channel mask
- * @param destBlueMask the destination blue channel mask
- * @param flipX if true the resulting image is flipped along the vertical axis
- * @param flipY if true the resulting image is flipped along the horizontal axis
- */
-static void blit(int op,
- byte[] srcData, int srcDepth, int srcStride, int srcOrder,
- int srcX, int srcY, int srcWidth, int srcHeight,
- byte[] srcReds, byte[] srcGreens, byte[] srcBlues,
- int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
- byte[] destData, int destDepth, int destStride, int destOrder,
- int destX, int destY, int destWidth, int destHeight,
- int destRedMask, int destGreenMask, int destBlueMask,
- boolean flipX, boolean flipY) {
- if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
-
- // these should be supplied as params later
- final int destAlphaMask = 0;
-
- /*** Prepare scaling data ***/
- final int dwm1 = destWidth - 1;
- final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
- final int dhm1 = destHeight - 1;
- final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
-
- /*** Prepare source-related data ***/
- final int stype;
- switch (srcDepth) {
- case 8:
- stype = TYPE_INDEX_8;
- break;
- case 4:
- srcStride <<= 1;
- stype = TYPE_INDEX_4;
- break;
- case 2:
- srcStride <<= 2;
- stype = TYPE_INDEX_2;
- break;
- case 1:
- srcStride <<= 3;
- stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
- break;
- default:
- //throw new IllegalArgumentException("Invalid source type");
- return;
- }
- int spr = srcY * srcStride + srcX;
-
- /*** Prepare destination-related data ***/
- final int dbpp, dtype;
- switch (destDepth) {
- case 8:
- dbpp = 1;
- dtype = TYPE_GENERIC_8;
- break;
- case 16:
- dbpp = 2;
- dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
- break;
- case 24:
- dbpp = 3;
- dtype = TYPE_GENERIC_24;
- break;
- case 32:
- dbpp = 4;
- dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
- break;
- default:
- //throw new IllegalArgumentException("Invalid destination type");
- return;
- }
- int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp;
- final int dprxi = (flipX) ? -dbpp : dbpp;
- final int dpryi = (flipY) ? -destStride : destStride;
-
- /*** Prepare special processing data ***/
- int apr;
- if ((op & BLIT_ALPHA) != 0) {
- switch (alphaMode) {
- case ALPHA_MASK_UNPACKED:
- case ALPHA_CHANNEL_SEPARATE:
- if (alphaData == null) alphaMode = 0x10000;
- apr = alphaY * alphaStride + alphaX;
- break;
- case ALPHA_MASK_PACKED:
- if (alphaData == null) alphaMode = 0x10000;
- alphaStride <<= 3;
- apr = alphaY * alphaStride + alphaX;
- break;
- case ALPHA_MASK_INDEX:
- case ALPHA_MASK_RGB:
- if (alphaData == null) alphaMode = 0x10000;
- apr = 0;
- break;
- default:
- alphaMode = (alphaMode << 16) / 255; // prescale
- case ALPHA_CHANNEL_SOURCE:
- apr = 0;
- break;
- }
- } else {
- alphaMode = 0x10000;
- apr = 0;
- }
-
- /*** Comprehensive blit (apply transformations) ***/
- final int destRedShift = getChannelShift(destRedMask);
- final int destRedWidth = getChannelWidth(destRedMask, destRedShift);
- final byte[] destReds = ANY_TO_EIGHT[destRedWidth];
- final int destRedPreShift = 8 - destRedWidth;
- final int destGreenShift = getChannelShift(destGreenMask);
- final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift);
- final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth];
- final int destGreenPreShift = 8 - destGreenWidth;
- final int destBlueShift = getChannelShift(destBlueMask);
- final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift);
- final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth];
- final int destBluePreShift = 8 - destBlueWidth;
- final int destAlphaShift = getChannelShift(destAlphaMask);
- final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift);
- final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth];
- final int destAlphaPreShift = 8 - destAlphaWidth;
-
- int dp = dpr;
- int sp = spr;
- int ap = apr, alpha = alphaMode;
- int r = 0, g = 0, b = 0, a = 0, index = 0;
- int rq = 0, gq = 0, bq = 0, aq = 0;
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
- sp = spr += (sfy >>> 16) * srcStride,
- ap = apr += (sfy >>> 16) * alphaStride,
- sfy = (sfy & 0xffff) + sfyi,
- dp = dpr += dpryi) {
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
- dp += dprxi,
- sfx = (sfx & 0xffff) + sfxi) {
- /*** READ NEXT PIXEL ***/
- switch (stype) {
- case TYPE_INDEX_8:
- index = srcData[sp] & 0xff;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_4:
- if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f;
- else index = (srcData[sp >> 1] >>> 4) & 0x0f;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_2:
- index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_1_MSB:
- index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
- sp += (sfx >>> 16);
- break;
- case TYPE_INDEX_1_LSB:
- index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
- sp += (sfx >>> 16);
- break;
- }
-
- /*** DO SPECIAL PROCESSING IF REQUIRED ***/
- r = srcReds[index] & 0xff;
- g = srcGreens[index] & 0xff;
- b = srcBlues[index] & 0xff;
- switch (alphaMode) {
- case ALPHA_CHANNEL_SEPARATE:
- alpha = ((alphaData[ap] & 0xff) << 16) / 255;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_UNPACKED:
- alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_PACKED:
- alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices
- int i = 0;
- while (i < alphaData.length) {
- if (index == (alphaData[i] & 0xff)) break;
- }
- if (i < alphaData.length) continue;
- } break;
- case ALPHA_MASK_RGB: {
- int i = 0;
- while (i < alphaData.length) {
- if ((r == (alphaData[i] & 0xff)) &&
- (g == (alphaData[i + 1] & 0xff)) &&
- (b == (alphaData[i + 2] & 0xff))) break;
- i += 3;
- }
- if (i < alphaData.length) continue;
- } break;
- }
- if (alpha != 0x10000) {
- if (alpha == 0x0000) continue;
- switch (dtype) {
- case TYPE_GENERIC_8: {
- final int data = destData[dp] & 0xff;
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_16_MSB: {
- final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_16_LSB: {
- final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_24: {
- final int data = (( ((destData[dp] & 0xff) << 8) |
- (destData[dp + 1] & 0xff)) << 8) |
- (destData[dp + 2] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_32_MSB: {
- final int data = (( (( ((destData[dp] & 0xff) << 8) |
- (destData[dp + 1] & 0xff)) << 8) |
- (destData[dp + 2] & 0xff)) << 8) |
- (destData[dp + 3] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_32_LSB: {
- final int data = (( (( ((destData[dp + 3] & 0xff) << 8) |
- (destData[dp + 2] & 0xff)) << 8) |
- (destData[dp + 1] & 0xff)) << 8) |
- (destData[dp] & 0xff);
- rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
- gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
- bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
- aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
- } break;
- }
- // Perform alpha blending
- a = aq + ((a - aq) * alpha >> 16);
- r = rq + ((r - rq) * alpha >> 16);
- g = gq + ((g - gq) * alpha >> 16);
- b = bq + ((b - bq) * alpha >> 16);
- }
-
- /*** WRITE NEXT PIXEL ***/
- final int data =
- (r >>> destRedPreShift << destRedShift) |
- (g >>> destGreenPreShift << destGreenShift) |
- (b >>> destBluePreShift << destBlueShift) |
- (a >>> destAlphaPreShift << destAlphaShift);
- switch (dtype) {
- case TYPE_GENERIC_8: {
- destData[dp] = (byte) data;
- } break;
- case TYPE_GENERIC_16_MSB: {
- destData[dp] = (byte) (data >>> 8);
- destData[dp + 1] = (byte) (data & 0xff);
- } break;
- case TYPE_GENERIC_16_LSB: {
- destData[dp] = (byte) (data & 0xff);
- destData[dp + 1] = (byte) (data >>> 8);
- } break;
- case TYPE_GENERIC_24: {
- destData[dp] = (byte) (data >>> 16);
- destData[dp + 1] = (byte) (data >>> 8);
- destData[dp + 2] = (byte) (data & 0xff);
- } break;
- case TYPE_GENERIC_32_MSB: {
- destData[dp] = (byte) (data >>> 24);
- destData[dp + 1] = (byte) (data >>> 16);
- destData[dp + 2] = (byte) (data >>> 8);
- destData[dp + 3] = (byte) (data & 0xff);
- } break;
- case TYPE_GENERIC_32_LSB: {
- destData[dp] = (byte) (data & 0xff);
- destData[dp + 1] = (byte) (data >>> 8);
- destData[dp + 2] = (byte) (data >>> 16);
- destData[dp + 3] = (byte) (data >>> 24);
- } break;
- }
- }
- }
-}
-
-/**
- * Blits a direct palette image into an index palette image.
- * <p>
- * Note: The source and destination masks and palettes must
- * always be fully specified.
- * </p>
- *
- * @param op the blitter operation: a combination of BLIT_xxx flags
- * (see BLIT_xxx constants)
- * @param srcData the source byte array containing image data
- * @param srcDepth the source depth: one of 8, 16, 24, 32
- * @param srcStride the source number of bytes per line
- * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
- * ignored if srcDepth is not 16 or 32
- * @param srcX the top-left x-coord of the source blit region
- * @param srcY the top-left y-coord of the source blit region
- * @param srcWidth the width of the source blit region
- * @param srcHeight the height of the source blit region
- * @param srcRedMask the source red channel mask
- * @param srcGreenMask the source green channel mask
- * @param srcBlueMask the source blue channel mask
- * @param alphaMode the alpha blending or mask mode, may be
- * an integer 0-255 for global alpha; ignored if BLIT_ALPHA
- * not specified in the blitter operations
- * (see ALPHA_MODE_xxx constants)
- * @param alphaData the alpha blending or mask data, varies depending
- * on the value of alphaMode and sometimes ignored
- * @param alphaStride the alpha data number of bytes per line
- * @param alphaX the top-left x-coord of the alpha blit region
- * @param alphaY the top-left y-coord of the alpha blit region
- * @param destData the destination byte array containing image data
- * @param destDepth the destination depth: one of 1, 2, 4, 8
- * @param destStride the destination number of bytes per line
- * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
- * ignored if destDepth is not 1
- * @param destX the top-left x-coord of the destination blit region
- * @param destY the top-left y-coord of the destination blit region
- * @param destWidth the width of the destination blit region
- * @param destHeight the height of the destination blit region
- * @param destReds the destination palette red component intensities
- * @param destGreens the destination palette green component intensities
- * @param destBlues the destination palette blue component intensities
- * @param flipX if true the resulting image is flipped along the vertical axis
- * @param flipY if true the resulting image is flipped along the horizontal axis
- */
-static void blit(int op,
- byte[] srcData, int srcDepth, int srcStride, int srcOrder,
- int srcX, int srcY, int srcWidth, int srcHeight,
- int srcRedMask, int srcGreenMask, int srcBlueMask,
- int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
- byte[] destData, int destDepth, int destStride, int destOrder,
- int destX, int destY, int destWidth, int destHeight,
- byte[] destReds, byte[] destGreens, byte[] destBlues,
- boolean flipX, boolean flipY) {
- if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
-
- // these should be supplied as params later
- final int srcAlphaMask = 0;
-
- /*** Prepare scaling data ***/
- final int dwm1 = destWidth - 1;
- final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
- final int dhm1 = destHeight - 1;
- final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
-
- /*** Prepare source-related data ***/
- final int sbpp, stype;
- switch (srcDepth) {
- case 8:
- sbpp = 1;
- stype = TYPE_GENERIC_8;
- break;
- case 16:
- sbpp = 2;
- stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
- break;
- case 24:
- sbpp = 3;
- stype = TYPE_GENERIC_24;
- break;
- case 32:
- sbpp = 4;
- stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
- break;
- default:
- //throw new IllegalArgumentException("Invalid source type");
- return;
- }
- int spr = srcY * srcStride + srcX * sbpp;
-
- /*** Prepare destination-related data ***/
- final int dtype;
- switch (destDepth) {
- case 8:
- dtype = TYPE_INDEX_8;
- break;
- case 4:
- destStride <<= 1;
- dtype = TYPE_INDEX_4;
- break;
- case 2:
- destStride <<= 2;
- dtype = TYPE_INDEX_2;
- break;
- case 1:
- destStride <<= 3;
- dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
- break;
- default:
- //throw new IllegalArgumentException("Invalid source type");
- return;
- }
- int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX);
- final int dprxi = (flipX) ? -1 : 1;
- final int dpryi = (flipY) ? -destStride : destStride;
-
- /*** Prepare special processing data ***/
- int apr;
- if ((op & BLIT_ALPHA) != 0) {
- switch (alphaMode) {
- case ALPHA_MASK_UNPACKED:
- case ALPHA_CHANNEL_SEPARATE:
- if (alphaData == null) alphaMode = 0x10000;
- apr = alphaY * alphaStride + alphaX;
- break;
- case ALPHA_MASK_PACKED:
- if (alphaData == null) alphaMode = 0x10000;
- alphaStride <<= 3;
- apr = alphaY * alphaStride + alphaX;
- break;
- case ALPHA_MASK_INDEX:
- //throw new IllegalArgumentException("Invalid alpha type");
- return;
- case ALPHA_MASK_RGB:
- if (alphaData == null) alphaMode = 0x10000;
- apr = 0;
- break;
- default:
- alphaMode = (alphaMode << 16) / 255; // prescale
- case ALPHA_CHANNEL_SOURCE:
- apr = 0;
- break;
- }
- } else {
- alphaMode = 0x10000;
- apr = 0;
- }
- final boolean ditherEnabled = (op & BLIT_DITHER) != 0;
-
- /*** Comprehensive blit (apply transformations) ***/
- final int srcRedShift = getChannelShift(srcRedMask);
- final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)];
- final int srcGreenShift = getChannelShift(srcGreenMask);
- final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)];
- final int srcBlueShift = getChannelShift(srcBlueMask);
- final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)];
- final int srcAlphaShift = getChannelShift(srcAlphaMask);
- final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)];
-
- int dp = dpr;
- int sp = spr;
- int ap = apr, alpha = alphaMode;
- int r = 0, g = 0, b = 0, a = 0;
- int indexq = 0;
- int lastindex = 0, lastr = -1, lastg = -1, lastb = -1;
- final int[] rerr, gerr, berr;
- int destPaletteSize = 1 << destDepth;
- if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length;
- if (ditherEnabled) {
- rerr = new int[destWidth + 2];
- gerr = new int[destWidth + 2];
- berr = new int[destWidth + 2];
- } else {
- rerr = null; gerr = null; berr = null;
- }
- for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
- sp = spr += (sfy >>> 16) * srcStride,
- ap = apr += (sfy >>> 16) * alphaStride,
- sfy = (sfy & 0xffff) + sfyi,
- dp = dpr += dpryi) {
- int lrerr = 0, lgerr = 0, lberr = 0;
- for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
- dp += dprxi,
- sfx = (sfx & 0xffff) + sfxi) {
- /*** READ NEXT PIXEL ***/
- switch (stype) {
- case TYPE_GENERIC_8: {
- final int data = srcData[sp] & 0xff;
- sp += (sfx >>> 16);
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_16_MSB: {
- final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff);
- sp += (sfx >>> 16) * 2;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_16_LSB: {
- final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff);
- sp += (sfx >>> 16) * 2;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_24: {
- final int data = (( ((srcData[sp] & 0xff) << 8) |
- (srcData[sp + 1] & 0xff)) << 8) |
- (srcData[sp + 2] & 0xff);
- sp += (sfx >>> 16) * 3;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_32_MSB: {
- final int data = (( (( ((srcData[sp] & 0xff) << 8) |
- (srcData[sp + 1] & 0xff)) << 8) |
- (srcData[sp + 2] & 0xff)) << 8) |
- (srcData[sp + 3] & 0xff);
- sp += (sfx >>> 16) * 4;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- case TYPE_GENERIC_32_LSB: {
- final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) |
- (srcData[sp + 2] & 0xff)) << 8) |
- (srcData[sp + 1] & 0xff)) << 8) |
- (srcData[sp] & 0xff);
- sp += (sfx >>> 16) * 4;
- r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
- g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
- b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
- a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
- } break;
- }
-
- /*** DO SPECIAL PROCESSING IF REQUIRED ***/
- switch (alphaMode) {
- case ALPHA_CHANNEL_SEPARATE:
- alpha = ((alphaData[ap] & 0xff) << 16) / 255;
- ap += (sfx >> 16);
- break;
- case ALPHA_CHANNEL_SOURCE:
- alpha = (a << 16) / 255;
- break;
- case ALPHA_MASK_UNPACKED:
- alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_PACKED:
- alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
- ap += (sfx >> 16);
- break;
- case ALPHA_MASK_RGB:
- alpha = 0x10000;
- for (int i = 0; i < alphaData.length; i += 3) {
- if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) {
- alpha = 0x0000;
- break;
- }
- }
- break;
- }
- if (alpha != 0x10000) {
- if (alpha == 0x0000) continue;
- switch (dtype) {
- case TYPE_INDEX_8:
- indexq = destData[dp] & 0xff;
- break;
- case TYPE_INDEX_4:
- if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f;
- else indexq = (destData[dp >> 1] >>> 4) & 0x0f;
- break;
- case TYPE_INDEX_2:
- indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03;
- break;
- case TYPE_INDEX_1_MSB:
- indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01;
- break;
- case TYPE_INDEX_1_LSB:
- indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01;
- break;
- }
- // Perform alpha blending
- final int rq = destReds[indexq] & 0xff;
- final int gq = destGreens[indexq] & 0xff;
- final int bq = destBlues[indexq] & 0xff;
- r = rq + ((r - rq) * alpha >> 16);
- g = gq + ((g - gq) * alpha >> 16);
- b = bq + ((b - bq) * alpha >> 16);
- }
-
- /*** MAP COLOR TO THE PALETTE ***/
- if (ditherEnabled) {
- // Floyd-Steinberg error diffusion
- r += rerr[dx] >> 4;
- if (r < 0) r = 0; else if (r > 255) r = 255;
- g += gerr[dx] >> 4;
- if (g < 0) g = 0; else if (g > 255) g = 255;
- b += berr[dx] >> 4;
- if (b < 0) b = 0; else if (b > 255) b = 255;
- rerr[dx] = lrerr;
- gerr[dx] = lgerr;
- berr[dx] = lberr;
- }
- if (r != lastr || g != lastg || b != lastb) {
- // moving the variable declarations out seems to make the JDK JIT happier...
- for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) {
- dr = (destReds[j] & 0xff) - r;
- dg = (destGreens[j] & 0xff) - g;
- db = (destBlues[j] & 0xff) - b;
- distance = dr * dr + dg * dg + db * db;
- if (distance < minDistance) {
- lastindex = j;
- if (distance == 0) break;
- minDistance = distance;
- }
- }
- lastr = r; lastg = g; lastb = b;
- }
- if (ditherEnabled) {
- // Floyd-Steinberg error diffusion, cont'd...
- final int dxm1 = dx - 1, dxp1 = dx + 1;
- int acc;
- rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr;
- rerr[dx] += acc += lrerr + lrerr;
- rerr[dxm1] += acc + lrerr + lrerr;
- gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr;
- gerr[dx] += acc += lgerr + lgerr;
- gerr[dxm1] += acc + lgerr + lgerr;
- berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr;
- berr[dx] += acc += lberr + lberr;
- berr[dxm1] += acc + lberr + lberr;
- }
-
- /*** WRITE NEXT PIXEL ***/
- switch (dtype) {
- case TYPE_INDEX_8:
- destData[dp] = (byte) lastindex;
- break;
- case TYPE_INDEX_4:
- if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex);
- else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4));
- break;
- case TYPE_INDEX_2: {
- final int shift = 6 - (dp & 3) * 2;
- destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift));
- } break;
- case TYPE_INDEX_1_MSB: {
- final int shift = 7 - (dp & 7);
- destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
- } break;
- case TYPE_INDEX_1_LSB: {
- final int shift = dp & 7;
- destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
- } break;
- }
- }
- }
-}
-
-/**
- * Computes the required channel shift from a mask.
- */
-static int getChannelShift(int mask) {
- if (mask == 0) return 0;
- int i;
- for (i = 0; ((mask & 1) == 0) && (i < 32); ++i) {
- mask >>>= 1;
- }
- return i;
-}
-
-/**
- * Computes the required channel width (depth) from a mask.
- */
-static int getChannelWidth(int mask, int shift) {
- if (mask == 0) return 0;
- int i;
- mask >>>= shift;
- for (i = shift; ((mask & 1) != 0) && (i < 32); ++i) {
- mask >>>= 1;
- }
- return i - shift;
-}
-
-/**
- * Extracts a field from packed RGB data given a mask for that field.
- */
-static byte getChannelField(int data, int mask) {
- final int shift = getChannelShift(mask);
- return ANY_TO_EIGHT[getChannelWidth(mask, shift)][(data & mask) >>> shift];
-}
-
-/**
- * Creates an ImageData containing one band's worth of a gradient filled
- * block. If <code>vertical</code> is true, the band must be tiled
- * horizontally to fill a region, otherwise it must be tiled vertically.
- *
- * @param width the width of the region to be filled
- * @param height the height of the region to be filled
- * @param vertical if true sweeps from top to bottom, else
- * sweeps from left to right
- * @param fromRGB the color to start with
- * @param toRGB the color to end with
- * @param redBits the number of significant red bits, 0 for palette modes
- * @param greenBits the number of significant green bits, 0 for palette modes
- * @param blueBits the number of significant blue bits, 0 for palette modes
- * @return the new ImageData
- */
-static ImageData createGradientBand(
- int width, int height, boolean vertical,
- RGB fromRGB, RGB toRGB,
- int redBits, int greenBits, int blueBits) {
- /* Gradients are drawn as tiled bands */
- final int bandWidth, bandHeight, bitmapDepth;
- final byte[] bitmapData;
- final PaletteData paletteData;
- /* Select an algorithm depending on the depth of the screen */
- if (redBits != 0 && greenBits != 0 && blueBits != 0) {
- paletteData = new PaletteData(0x0000ff00, 0x00ff0000, 0xff000000);
- bitmapDepth = 32;
- if (redBits >= 8 && greenBits >= 8 && blueBits >= 8) {
- /* Precise color */
- final int steps;
- if (vertical) {
- bandWidth = 1;
- bandHeight = height;
- steps = bandHeight > 1 ? bandHeight - 1 : 1;
- } else {
- bandWidth = width;
- bandHeight = 1;
- steps = bandWidth > 1 ? bandWidth - 1 : 1;
- }
- final int bytesPerLine = bandWidth * 4;
- bitmapData = new byte[bandHeight * bytesPerLine];
- buildPreciseGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine);
- buildPreciseGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine);
- buildPreciseGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine);
- } else {
- /* Dithered color */
- final int steps;
- if (vertical) {
- bandWidth = (width < 8) ? width : 8;
- bandHeight = height;
- steps = bandHeight > 1 ? bandHeight - 1 : 1;
- } else {
- bandWidth = width;
- bandHeight = (height < 8) ? height : 8;
- steps = bandWidth > 1 ? bandWidth - 1 : 1;
- }
- final int bytesPerLine = bandWidth * 4;
- bitmapData = new byte[bandHeight * bytesPerLine];
- buildDitheredGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine, blueBits);
- buildDitheredGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine, greenBits);
- buildDitheredGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine, redBits);
- }
- } else {
- /* Dithered two tone */
- paletteData = new PaletteData(new RGB[] { fromRGB, toRGB });
- bitmapDepth = 8;
- final int blendi;
- if (vertical) {
- bandWidth = (width < 8) ? width : 8;
- bandHeight = height;
- blendi = (bandHeight > 1) ? 0x1040000 / (bandHeight - 1) + 1 : 1;
- } else {
- bandWidth = width;
- bandHeight = (height < 8) ? height : 8;
- blendi = (bandWidth > 1) ? 0x1040000 / (bandWidth - 1) + 1 : 1;
- }
- final int bytesPerLine = (bandWidth + 3) & -4;
- bitmapData = new byte[bandHeight * bytesPerLine];
- if (vertical) {
- for (int dy = 0, blend = 0, dp = 0; dy < bandHeight;
- ++dy, blend += blendi, dp += bytesPerLine) {
- for (int dx = 0; dx < bandWidth; ++dx) {
- bitmapData[dp + dx] = (blend + DITHER_MATRIX[dy & 7][dx]) <
- 0x1000000 ? (byte)0 : (byte)1;
- }
- }
- } else {
- for (int dx = 0, blend = 0; dx < bandWidth; ++dx, blend += blendi) {
- for (int dy = 0, dptr = dx; dy < bandHeight; ++dy, dptr += bytesPerLine) {
- bitmapData[dptr] = (blend + DITHER_MATRIX[dy][dx & 7]) <
- 0x1000000 ? (byte)0 : (byte)1;
- }
- }
- }
- }
- return new ImageData(bandWidth, bandHeight, bitmapDepth, paletteData, 4, bitmapData);
-}
-
-/*
- * Fill in gradated values for a color channel
- */
-static final void buildPreciseGradientChannel(int from, int to, int steps,
- int bandWidth, int bandHeight, boolean vertical,
- byte[] bitmapData, int dp, int bytesPerLine) {
- int val = from << 16;
- final int inc = ((to << 16) - val) / steps + 1;
- if (vertical) {
- for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
- bitmapData[dp] = (byte)(val >>> 16);
- val += inc;
- }
- } else {
- for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
- bitmapData[dp] = (byte)(val >>> 16);
- val += inc;
- }
- }
-}
-
-/*
- * Fill in dithered gradated values for a color channel
- */
-static final void buildDitheredGradientChannel(int from, int to, int steps,
- int bandWidth, int bandHeight, boolean vertical,
- byte[] bitmapData, int dp, int bytesPerLine, int bits) {
- final int mask = 0xff00 >>> bits;
- int val = from << 16;
- final int inc = ((to << 16) - val) / steps + 1;
- if (vertical) {
- for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
- for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) {
- final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits;
- int temp = val + thresh;
- if (temp > 0xffffff) bitmapData[dptr] = -1;
- else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
- }
- val += inc;
- }
- } else {
- for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
- for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) {
- final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits;
- int temp = val + thresh;
- if (temp > 0xffffff) bitmapData[dptr] = -1;
- else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
- }
- val += inc;
- }
- }
-}
-
-/**
- * Renders a gradient onto a GC.
- * <p>
- * This is a GC helper.
- * </p>
- *
- * @param gc the GC to render the gradient onto
- * @param device the device the GC belongs to
- * @param x the top-left x coordinate of the region to be filled
- * @param y the top-left y coordinate of the region to be filled
- * @param width the width of the region to be filled
- * @param height the height of the region to be filled
- * @param vertical if true sweeps from top to bottom, else
- * sweeps from left to right
- * @param fromRGB the color to start with
- * @param toRGB the color to end with
- * @param redBits the number of significant red bits, 0 for palette modes
- * @param greenBits the number of significant green bits, 0 for palette modes
- * @param blueBits the number of significant blue bits, 0 for palette modes
- */
-static void fillGradientRectangle(GC gc, Device device,
- int x, int y, int width, int height, boolean vertical,
- RGB fromRGB, RGB toRGB,
- int redBits, int greenBits, int blueBits) {
- /* Create the bitmap and tile it */
- ImageData band = createGradientBand(width, height, vertical,
- fromRGB, toRGB, redBits, greenBits, blueBits);
- Image image = new Image(device, band);
- if ((band.width == 1) || (band.height == 1)) {
- gc.drawImage(image, 0, 0, band.width, band.height, x, y, width, height);
- } else {
- if (vertical) {
- for (int dx = 0; dx < width; dx += band.width) {
- int blitWidth = width - dx;
- if (blitWidth > band.width) blitWidth = band.width;
- gc.drawImage(image, 0, 0, blitWidth, band.height, dx + x, y, blitWidth, band.height);
- }
- } else {
- for (int dy = 0; dy < height; dy += band.height) {
- int blitHeight = height - dy;
- if (blitHeight > band.height) blitHeight = band.height;
- gc.drawImage(image, 0, 0, band.width, blitHeight, x, dy + y, band.width, blitHeight);
- }
- }
- }
- image.dispose();
-}
-
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import java.io.*; +import org.eclipse.swt.*; +import org.eclipse.swt.internal.CloneableCompatibility; + +/** + * Instances of this class are device-independent descriptions + * of images. They are typically used as an intermediate format + * between loading from or writing to streams and creating an + * <code>Image</code>. + * <p> + * Note that the public fields <code>x</code>, <code>y</code>, + * <code>disposalMethod</code> and <code>delayTime</code> are + * typically only used when the image is in a set of images used + * for animation. + * </p> + * + * @see Image + * @see ImageLoader + */ + +public final class ImageData implements CloneableCompatibility { + + /** + * the width of the image, in pixels + */ + public int width; + + /** + * the height of the image, in pixels + */ + public int height; + + /** + * the color depth of the image, in bits per pixel + * <p> + * Note that a depth of 8 or less does not necessary + * mean that the image is palette indexed, or + * conversely that a depth greater than 8 means that + * the image is direct color. Check the associated + * PaletteData's isDirect field for such determinations. + */ + public int depth; + + /** + * the scanline padding + * <p> + * If one scanline of the image is not a multiple of + * this number, it will be padded with zeros until it is. + * </p> + */ + public int scanlinePad; + + /** + * the number of bytes per scanline + * <p> + * This is a multiple of the scanline padding. + * </p> + */ + public int bytesPerLine; + + /** + * the pixel data of the image + * <p> + * Note that for 16 bit depth images the pixel data is stored + * in least significant byte order; however, for 24bit and + * 32bit depth images the pixel data is stored in most + * significant byte order. + * </p> + */ + public byte[] data; + + /** + * the color table for the image + */ + public PaletteData palette; + + /** + * the transparent pixel + * <p> + * Pixels with this value are transparent. + * </p><p> + * The default is -1 which means 'no transparent pixel'. + * </p> + */ + public int transparentPixel; + + /** + * icon-specific field containing the data from the icon mask + * <p> + * This is a 1 bit bitmap stored with the most significant + * bit first. The number of bytes per scanline is + * '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'. + * </p><p> + * The default is null which means 'no transparency mask'. + * </p> + */ + public byte[] maskData; + + /** + * icon-specific field containing the scanline pad of the mask + * <p> + * If one scanline of the transparency mask is not a + * multiple of this number, it will be padded with zeros until + * it is. + * </p> + */ + public int maskPad; + + /** + * the alpha data of the image + * <p> + * Every pixel can have an <em>alpha blending</em> value that + * varies from 0, meaning fully transparent, to 255 meaning + * fully opaque. The number of bytes per scanline is + * 'width'. + * </p> + */ + public byte[] alphaData; + + /** + * the global alpha value to be used for every pixel + * <p> + * If this value is set, the <code>alphaData</code> field + * is ignored and when the image is rendered each pixel + * will be blended with the background an amount + * proportional to this value. + * </p><p> + * The default is -1 which means 'no global alpha value' + * </p> + */ + public int alpha; + + /** + * the type of file that the image was read in from, + * expressed as one of the following values: + * <dl> + * <dt><code>IMAGE_BMP</code></dt> + * <dd>Windows BMP file format, no compression</dd> + * <dt><code>IMAGE_BMP_RLE</code></dt> + * <dd>Windows BMP file format, RLE compression if appropriate</dd> + * <dt><code>IMAGE_GIF</code></dt> + * <dd>GIF file format</dd> + * <dt><code>IMAGE_ICO</code></dt> + * <dd>Windows ICO file format</dd> + * <dt><code>IMAGE_JPEG</code></dt> + * <dd>JPEG file format</dd> + * <dt><code>IMAGE_PNG</code></dt> + * <dd>PNG file format</dd> + * </dl> + */ + public int type; + + /** + * the x coordinate of the top left corner of the image + * within the logical screen (this field corresponds to + * the GIF89a Image Left Position value) + */ + public int x; + + /** + * The y coordinate of the top left corner of the image + * within the logical screen (this field corresponds to + * the GIF89a Image Top Position value) + */ + public int y; + + /** + * a description of how to dispose of the current image + * before displaying the next, expressed as one of the + * following values: + * <dl> + * <dt><code>DM_UNSPECIFIED</code></dt> + * <dd>disposal method not specified</dd> + * <dt><code>DM_FILL_NONE</code></dt> + * <dd>do nothing - leave the image in place</dd> + * <dt><code>DM_FILL_BACKGROUND</code></dt> + * <dd>fill with the background color</dd> + * <dt><code>DM_FILL_PREVIOUS</code></dt> + * <dd>restore the previous picture</dd> + * </dl> + * (this field corresponds to the GIF89a Disposal Method value) + */ + public int disposalMethod; + + /** + * the time to delay before displaying the next image + * in an animation (this field corresponds to the GIF89a + * Delay Time value) + */ + public int delayTime; + + /** + * Arbitrary channel width data to 8-bit conversion table + */ + static final byte[][] ANY_TO_EIGHT = new byte[9][]; + static { + for (int b = 0; b < 9; ++b) { + byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b]; + if (b == 0) continue; + int inc = 0; + for (int bit = 0x10000; (bit >>= b) != 0;) inc |= bit; + for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = (byte)(v >> 8); + } + } + static final byte[] ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8]; + + /** + * Scaled 8x8 Bayer dither matrix + */ + static final int[][] DITHER_MATRIX = { + { 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 }, + { 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 }, + { 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 }, + { 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 }, + { 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 }, + { 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 }, + { 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 }, + { 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 } + }; + +/** + * Constructs a new, empty ImageData with the given width, height, + * depth and palette. The data will be initialized to an (all zero) + * array of the appropriate size. + * + * @param width the width of the image + * @param height the height of the image + * @param depth the depth of the image + * @param palette the palette of the image (must not be null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the width or height is negative</li> + * <li>ERROR_NULL_ARGUMENT - if the palette is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_UNSUPPORTED_DEPTH - if the depth argument is not one of 1, 2, 4, 8, 16, 24 or 32</li> + * </ul> + */ +public ImageData(int width, int height, int depth, PaletteData palette) { + this(width, height, depth, palette, + 4, null, 0, null, + null, -1, -1, SWT.IMAGE_UNDEFINED, + 0, 0, 0, 0); +} + +/** + * Constructs a new, empty ImageData with the given width, height, + * depth, palette, scanlinePad and data. + * + * @param width the width of the image + * @param height the height of the image + * @param depth the depth of the image + * @param palette the palette of the image + * @param scanlinePad the padding of each line, in bytes + * @param data the data of the image + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the width or height is negative</li> + * <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_UNSUPPORTED_DEPTH - if the depth argument is not one of 1, 2, 4, 8, 16, 24 or 32</li> + * </ul> + */ +public ImageData(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) { + this(width, height, depth, palette, + scanlinePad, checkData(data), 0, null, + null, -1, -1, SWT.IMAGE_UNDEFINED, + 0, 0, 0, 0); +} + +/** + * Constructs an <code>ImageData</code> loaded from the specified + * input stream. Throws an error if an error occurs while loading + * the image, or if the image has an unsupported type. + * <p> + * This constructor is provided for convenience when loading a single + * image only. If the stream contains multiple images, only the first + * one will be loaded. To load multiple images, use + * <code>ImageLoader.load()</code>. + * </p> + * + * @param stream the input stream to load the image from (must not be null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the stream is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li> + * <li>ERROR_IO - if an IO error occurs while reading data</li> + * </ul> + * + * @see ImageLoader#load + */ +public ImageData(InputStream stream) { + ImageData[] data = new ImageLoader().load(stream); + if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE); + ImageData i = data[0]; + setAllFields( + i.width, + i.height, + i.depth, + i.scanlinePad, + i.bytesPerLine, + i.data, + i.palette, + i.transparentPixel, + i.maskData, + i.maskPad, + i.alphaData, + i.alpha, + i.type, + i.x, + i.y, + i.disposalMethod, + i.delayTime); +} + +/** + * Constructs an <code>ImageData</code> loaded from a file with the + * specified name. Throws an error if an error occurs loading the + * image, or if the image has an unsupported type. + * <p> + * This constructor is provided for convenience when loading a single + * image only. If the file contains multiple images, only the first + * one will be loaded. To load multiple images, use + * <code>ImageLoader.load()</code>. + * </p> + * + * @param filename the name of the file to load the image from (must not be null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the file name is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li> + * <li>ERROR_IO if an IO error occurs while reading data</li> + * </ul> + */ +public ImageData(String filename) { + ImageData[] data = new ImageLoader().load(filename); + if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE); + ImageData i = data[0]; + setAllFields( + i.width, + i.height, + i.depth, + i.scanlinePad, + i.bytesPerLine, + i.data, + i.palette, + i.transparentPixel, + i.maskData, + i.maskPad, + i.alphaData, + i.alpha, + i.type, + i.x, + i.y, + i.disposalMethod, + i.delayTime); +} + +/** + * Prevents uninitialized instances from being created outside the package. + */ +ImageData() { +} + +/** + * Constructs an image data by giving values for all non-computable fields. + * <p> + * This method is for internal use, and is not described further. + * </p> + */ +ImageData( + int width, int height, int depth, PaletteData palette, + int scanlinePad, byte[] data, int maskPad, byte[] maskData, + byte[] alphaData, int alpha, int transparentPixel, int type, + int x, int y, int disposalMethod, int delayTime) +{ + + if (palette == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (!(depth == 1 || depth == 2 || depth == 4 || depth == 8 + || depth == 16 || depth == 24 || depth == 32)) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (width <= 0 || height <= 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1)) + / scanlinePad * scanlinePad; + setAllFields( + width, + height, + depth, + scanlinePad, + bytesPerLine, + data != null ? data : new byte[bytesPerLine * height], + palette, + transparentPixel, + maskData, + maskPad, + alphaData, + alpha, + type, + x, + y, + disposalMethod, + delayTime); +} + +/** + * Initializes all fields in the receiver. This method must be called + * by all public constructors to ensure that all fields are initialized + * for a new ImageData object. If a new field is added to the class, + * then it must be added to this method. + * <p> + * This method is for internal use, and is not described further. + * </p> + */ +void setAllFields(int width, int height, int depth, int scanlinePad, + int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel, + byte[] maskData, int maskPad, byte[] alphaData, int alpha, + int type, int x, int y, int disposalMethod, int delayTime) { + + this.width = width; + this.height = height; + this.depth = depth; + this.scanlinePad = scanlinePad; + this.bytesPerLine = bytesPerLine; + this.data = data; + this.palette = palette; + this.transparentPixel = transparentPixel; + this.maskData = maskData; + this.maskPad = maskPad; + this.alphaData = alphaData; + this.alpha = alpha; + this.type = type; + this.x = x; + this.y = y; + this.disposalMethod = disposalMethod; + this.delayTime = delayTime; +} + +/** + * Invokes internal SWT functionality to create a new instance of + * this class. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>ImageData</code>. It is marked public only so that it + * can be shared within the packages provided by SWT. It is subject + * to change without notice, and should never be called from + * application code. + * </p> + * <p> + * This method is for internal use, and is not described further. + * </p> + * + * @private + */ +public static ImageData internal_new( + int width, int height, int depth, PaletteData palette, + int scanlinePad, byte[] data, int maskPad, byte[] maskData, + byte[] alphaData, int alpha, int transparentPixel, int type, + int x, int y, int disposalMethod, int delayTime) +{ + return new ImageData( + width, height, depth, palette, scanlinePad, data, maskPad, maskData, + alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime); +} + +ImageData colorMaskImage(int pixel) { + ImageData mask = new ImageData(width, height, 1, bwPalette(), + Image.DEFAULT_SCANLINE_PAD, null, 0, null, + null, -1, -1, SWT.IMAGE_UNDEFINED, + 0, 0, 0, 0); + int[] row = new int[width]; + for (int y = 0; y < height; y++) { + getPixels(0, y, width, row, 0); + for (int i = 0; i < width; i++) { + if (pixel != -1 && row[i] == pixel) { + row[i] = 0; + } else { + row[i] = 1; + } + } + mask.setPixels(0, y, width, row, 0); + } + return mask; +} + +static byte[] checkData(byte [] data) { + if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + return data; +} + +/** + * Returns a new instance of the same class as the receiver, + * whose slots have been filled in with <em>copies</em> of + * the values in the slots of the receiver. That is, the + * returned object is a <em>deep copy</em> of the receiver. + * + * @return a copy of the receiver. + */ +public Object clone() { + byte[] cloneData = new byte[data.length]; + System.arraycopy(data, 0, cloneData, 0, data.length); + byte[] cloneMaskData = null; + if (maskData != null) { + cloneMaskData = new byte[maskData.length]; + System.arraycopy(maskData, 0, cloneMaskData, 0, maskData.length); + } + byte[] cloneAlphaData = null; + if (alphaData != null) { + cloneAlphaData = new byte[alphaData.length]; + System.arraycopy(alphaData, 0, cloneAlphaData, 0, alphaData.length); + } + return new ImageData( + width, + height, + depth, + palette, + scanlinePad, + cloneData, + maskPad, + cloneMaskData, + cloneAlphaData, + alpha, + transparentPixel, + type, + x, + y, + disposalMethod, + delayTime); +} + +/** + * Returns the alpha value at offset <code>x</code> in + * scanline <code>y</code> in the receiver's alpha data. + * + * @param x the x coodinate of the pixel to get the alpha value of + * @param y the y coordinate of the pixel to get the alpha value of + * @return the alpha value at the given coordinates + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if either argument is out of range</li> + * </ul> + */ +public int getAlpha(int x, int y) { + if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + if (alphaData == null) return 255; + return alphaData[y * width + x] & 0xFF; +} + +/** + * Returns <code>getWidth</code> alpha values starting at offset + * <code>x</code> in scanline <code>y</code> in the receiver's alpha + * data starting at <code>startIndex</code>. + * + * @param x the x position of the pixel to begin getting alpha values + * @param y the y position of the pixel to begin getting alpha values + * @param getWidth the width of the data to get + * @param alphas the buffer in which to put the alpha values + * @param startIndex the offset into the image to begin getting alpha values + * + * @exception IndexOutOfBoundsException if getWidth is too large + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> + * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> + * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li> + * </ul> + */ +public void getAlphas(int x, int y, int getWidth, byte[] alphas, int startIndex) { + if (alphas == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (getWidth == 0) return; + + if (alphaData == null) { + int endIndex = startIndex + getWidth; + for (int i = startIndex; i < endIndex; i++) { + alphas[i] = (byte)255; + } + return; + } + // may throw an IndexOutOfBoundsException + System.arraycopy(alphaData, y * width + x, alphas, startIndex, getWidth); +} + +/** + * Returns the pixel value at offset <code>x</code> in + * scanline <code>y</code> in the receiver's data. + * + * @param x the x position of the pixel to get + * @param y the y position of the pixel to get + * @return the pixel at the given coordinates + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if either argument is out of bounds</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li> + * </ul> + */ +public int getPixel(int x, int y) { + if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int index; + int theByte; + int mask; + if (depth == 1) { + index = (y * bytesPerLine) + (x >> 3); + theByte = data[index] & 0xFF; + mask = 1 << (7 - (x & 0x7)); + if ((theByte & mask) == 0) { + return 0; + } else { + return 1; + } + } + if (depth == 2) { + index = (y * bytesPerLine) + (x >> 2); + theByte = data[index] & 0xFF; + int offset = 3 - (x % 4); + mask = 3 << (offset * 2); + return (theByte & mask) >> (offset * 2); + } + if (depth == 4) { + index = (y * bytesPerLine) + (x >> 1); + theByte = data[index] & 0xFF; + if ((x & 0x1) == 0) { + return theByte >> 4; + } else { + return theByte & 0x0F; + } + } + if (depth == 8) { + index = (y * bytesPerLine) + x ; + return data[index] & 0xFF; + } + if (depth == 16) { + index = (y * bytesPerLine) + (x * 2); + return ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF); + } + if (depth == 24) { + index = (y * bytesPerLine) + (x * 3); + return ((data[index] & 0xFF) << 16) + ((data[index+1] & 0xFF) << 8) + + (data[index+2] & 0xFF); + } + if (depth == 32) { + index = (y * bytesPerLine) + (x * 4); + return ((data[index] & 0xFF) << 24) + ((data[index+1] & 0xFF) << 16) + + ((data[index+2] & 0xFF) << 8) + (data[index+3] & 0xFF); + } + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); + return 0; +} + +/** + * Returns <code>getWidth</code> pixel values starting at offset + * <code>x</code> in scanline <code>y</code> in the receiver's + * data starting at <code>startIndex</code>. + * + * @param x the x position of the first pixel to get + * @param y the y position of the first pixel to get + * @param getWidth the width of the data to get + * @param pixels the buffer in which to put the pixels + * @param startIndex the offset into the byte array to begin storing pixels + * + * @exception IndexOutOfBoundsException if getWidth is too large + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> + * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> + * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4 or 8 + * (For higher depths, use the int[] version of this method.)</li> + * </ul> + */ +public void getPixels(int x, int y, int getWidth, byte[] pixels, int startIndex) { + if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (getWidth == 0) return; + int index; + int theByte; + int mask = 0; + int n = getWidth; + int i = startIndex; + int srcX = x, srcY = y; + if (depth == 1) { + index = (y * bytesPerLine) + (x >> 3); + theByte = data[index] & 0xFF; + while (n > 1) { + mask = 1 << (7 - (srcX & 0x7)); + if ((theByte & mask) == 0) { + pixels[i] = 0; + } else { + pixels[i] = 1; + } + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + if (n > 0) theByte = data[index] & 0xFF; + srcX = 0; + } else { + if (mask == 1) { + index++; + if (n > 0) theByte = data[index] & 0xFF; + } + } + } + return; + } + if (depth == 2) { + index = (y * bytesPerLine) + (x >> 2); + theByte = data[index] & 0xFF; + int offset; + while (n > 0) { + offset = 3 - (srcX % 4); + mask = 3 << (offset * 2); + pixels[i] = (byte)((theByte & mask) >> (offset * 2)); + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + if (n > 0) theByte = data[index] & 0xFF; + srcX = 0; + } else { + if (offset == 0) { + index++; + theByte = data[index] & 0xFF; + } + } + } + return; + } + if (depth == 4) { + index = (y * bytesPerLine) + (x >> 1); + if ((x & 0x1) == 1) { + theByte = data[index] & 0xFF; + pixels[i] = (byte)(theByte & 0x0F); + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index++; + } + } + while (n > 1) { + theByte = data[index] & 0xFF; + pixels[i] = (byte)(theByte >> 4); + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + pixels[i] = (byte)(theByte & 0x0F); + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index++; + } + } + } + if (n > 0) { + theByte = data[index] & 0xFF; + pixels[i] = (byte)(theByte >> 4); + } + return; + } + if (depth == 8) { + index = (y * bytesPerLine) + x; + for (int j = 0; j < getWidth; j++) { + pixels[i] = data[index]; + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index++; + } + } + return; + } + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); +} + +/** + * Returns <code>getWidth</code> pixel values starting at offset + * <code>x</code> in scanline <code>y</code> in the receiver's + * data starting at <code>startIndex</code>. + * + * @param x the x position of the first pixel to get + * @param y the y position of the first pixel to get + * @param getWidth the width of the data to get + * @param pixels the buffer in which to put the pixels + * @param startIndex the offset into the buffer to begin storing pixels + * + * @exception IndexOutOfBoundsException if getWidth is too large + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> + * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> + * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li> + * </ul> + */ +public void getPixels(int x, int y, int getWidth, int[] pixels, int startIndex) { + if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (getWidth == 0) return; + int index; + int theByte; + int mask; + int n = getWidth; + int i = startIndex; + int srcX = x, srcY = y; + if (depth == 1) { + index = (y * bytesPerLine) + (x >> 3); + theByte = data[index] & 0xFF; + while (n > 0) { + mask = 1 << (7 - (srcX & 0x7)); + if ((theByte & mask) == 0) { + pixels[i] = 0; + } else { + pixels[i] = 1; + } + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + if (n > 0) theByte = data[index] & 0xFF; + srcX = 0; + } else { + if (mask == 1) { + index++; + if (n > 0) theByte = data[index] & 0xFF; + } + } + } + return; + } + if (depth == 2) { + index = (y * bytesPerLine) + (x >> 2); + theByte = data[index] & 0xFF; + int offset; + while (n > 0) { + offset = 3 - (srcX % 4); + mask = 3 << (offset * 2); + pixels[i] = (byte)((theByte & mask) >> (offset * 2)); + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + if (n > 0) theByte = data[index] & 0xFF; + srcX = 0; + } else { + if (offset == 0) { + index++; + theByte = data[index] & 0xFF; + } + } + } + return; + } + if (depth == 4) { + index = (y * bytesPerLine) + (x >> 1); + if ((x & 0x1) == 1) { + theByte = data[index] & 0xFF; + pixels[i] = theByte & 0x0F; + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index++; + } + } + while (n > 1) { + theByte = data[index] & 0xFF; + pixels[i] = theByte >> 4; + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + pixels[i] = theByte & 0x0F; + i++; + n--; + srcX++;; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index++; + } + } + } + if (n > 0) { + theByte = data[index] & 0xFF; + pixels[i] = theByte >> 4; + } + return; + } + if (depth == 8) { + index = (y * bytesPerLine) + x; + for (int j = 0; j < getWidth; j++) { + pixels[i] = data[index] & 0xFF; + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index++; + } + } + return; + } + if (depth == 16) { + index = (y * bytesPerLine) + (x * 2); + for (int j = 0; j < getWidth; j++) { + pixels[i] = ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF); + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index += 2; + } + } + return; + } + if (depth == 24) { + index = (y * bytesPerLine) + (x * 3); + for (int j = 0; j < getWidth; j++) { + pixels[i] = ((data[index] & 0xFF) << 16) | ((data[index+1] & 0xFF) << 8) + | (data[index+2] & 0xFF); + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index += 3; + } + } + return; + } + if (depth == 32) { + index = (y * bytesPerLine) + (x * 4); + i = startIndex; + for (int j = 0; j < getWidth; j++) { + pixels[i] = ((data[index] & 0xFF) << 24) | ((data[index+1] & 0xFF) << 16) + | ((data[index+2] & 0xFF) << 8) | (data[index+3] & 0xFF); + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index += 4; + } + } + return; + } + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); +} + +/** + * Returns an array of <code>RGB</code>s which comprise the + * indexed color table of the receiver, or null if the receiver + * has a direct color model. + * + * @return the RGB values for the image or null if direct color + * + * @see PaletteData#getRGBs + */ +public RGB[] getRGBs() { + return palette.getRGBs(); +} + +/** + * Returns an <code>ImageData</code> which specifies the + * transparency mask information for the receiver, or null if the + * receiver has no transparency and is not an icon. + * + * @return the transparency mask or null if none exists + */ +public ImageData getTransparencyMask() { + if (getTransparencyType() == SWT.TRANSPARENCY_MASK) { + return new ImageData(width, height, 1, bwPalette(), maskPad, maskData); + } else { + return colorMaskImage(transparentPixel); + } +} + +/** + * Returns the image transparency type. + * + * @return the receiver's transparency type + */ +public int getTransparencyType() { + if (maskData != null) return SWT.TRANSPARENCY_MASK; + if (transparentPixel != -1) return SWT.TRANSPARENCY_PIXEL; + if (alphaData != null) return SWT.TRANSPARENCY_ALPHA; + return SWT.TRANSPARENCY_NONE; +} + +/** + * Returns the byte order of the receiver. + * + * @return MSB_FIRST or LSB_FIRST + */ +int getByteOrder() { + return depth != 16 ? MSB_FIRST : LSB_FIRST; +} + +/** + * Returns a copy of the receiver which has been stretched or + * shrunk to the specified size. If either the width or height + * is negative, the resulting image will be inverted in the + * associated axis. + * + * @param width the width of the new ImageData + * @param height the height of the new ImageData + * @return a scaled copy of the image + */ +public ImageData scaledTo(int width, int height) { + /* Create a destination image with no data */ + final boolean flipX = (width < 0); + if (flipX) width = - width; + final boolean flipY = (height < 0); + if (flipY) height = - height; + + ImageData dest = new ImageData( + width, height, depth, palette, + scanlinePad, null, 0, null, + null, -1, transparentPixel, type, + x, y, disposalMethod, delayTime); + + /* Scale the image contents */ + if (palette.isDirect) blit(BLIT_SRC, + this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, 0, 0, 0, + ALPHA_OPAQUE, null, 0, 0, 0, + dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, 0, 0, 0, + flipX, flipY); + else blit(BLIT_SRC, + this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, null, null, null, + ALPHA_OPAQUE, null, 0, 0, 0, + dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, null, null, null, + flipX, flipY); + + /* Scale the image mask or alpha */ + if (maskData != null) { + dest.maskPad = this.maskPad; + int destBpl = (dest.width + 7) / 8; + destBpl = (destBpl + (dest.maskPad - 1)) / dest.maskPad * dest.maskPad; + dest.maskData = new byte[destBpl * dest.height]; + int srcBpl = (this.width + 7) / 8; + srcBpl = (srcBpl + (this.maskPad - 1)) / this.maskPad * this.maskPad; + blit(BLIT_SRC, + this.maskData, 1, srcBpl, MSB_FIRST, 0, 0, this.width, this.height, null, null, null, + ALPHA_OPAQUE, null, 0, 0, 0, + dest.maskData, 1, destBpl, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null, + flipX, flipY); + } else if (alpha != -1) { + dest.alpha = this.alpha; + } else if (alphaData != null) { + dest.alphaData = new byte[dest.width * dest.height]; + blit(BLIT_SRC, + this.alphaData, 8, this.width, MSB_FIRST, 0, 0, this.width, this.height, null, null, null, + ALPHA_OPAQUE, null, 0, 0, 0, + dest.alphaData, 8, dest.width, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null, + flipX, flipY); + } + return dest; +} + +/** + * Sets the alpha value at offset <code>x</code> in + * scanline <code>y</code> in the receiver's alpha data. + * + * @param x the x coordinate of the alpha value to set + * @param y the y coordinate of the alpha value to set + * @param alpha the value to set the alpha to + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> + * </ul> + */ +public void setAlpha(int x, int y, int alpha) { + if (x >= width || y >= height || x < 0 || y < 0 || alpha < 0 || alpha > 255) + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + if (alphaData == null) alphaData = new byte[width * height]; + alphaData[y * width + x] = (byte)alpha; +} + +/** + * Sets the alpha values starting at offset <code>x</code> in + * scanline <code>y</code> in the receiver's alpha data to the + * values from the array <code>alphas</code> starting at + * <code>startIndex</code>. + * + * @param x the x coordinate of the pixel to being setting the alpha values + * @param y the y coordinate of the pixel to being setting the alpha values + * @param putWidth the width of the alpha values to set + * @param alphas the alpha values to set + * @param startIndex the index at which to begin setting + * + * @exception IndexOutOfBoundsException if putWidth is too large + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> + * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> + * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li> + * </ul> + */ +public void setAlphas(int x, int y, int putWidth, byte[] alphas, int startIndex) { + if (alphas == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (putWidth == 0) return; + + if (alphaData == null) alphaData = new byte[width * height]; + // may throw an IndexOutOfBoundsException + System.arraycopy(alphas, startIndex, alphaData, y * width + x, putWidth); +} + +/** + * Sets the pixel value at offset <code>x</code> in + * scanline <code>y</code> in the receiver's data. + * + * @param x the x coordinate of the pixel to set + * @param y the y coordinate of the pixel to set + * @param pixelValue the value to set the pixel to + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li> + * </ul> + */ +public void setPixel(int x, int y, int pixelValue) { + if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int index; + byte theByte; + int mask; + if (depth == 1) { + index = (y * bytesPerLine) + (x >> 3); + theByte = data[index]; + mask = 1 << (7 - (x & 0x7)); + if ((pixelValue & 0x1) == 1) { + data[index] = (byte)(theByte | mask); + } else { + data[index] = (byte)(theByte & (mask ^ -1)); + } + return; + } + if (depth == 2) { + index = (y * bytesPerLine) + (x >> 2); + theByte = data[index]; + int offset = 3 - (x % 4); + mask = 0xFF ^ (3 << (offset * 2)); + data[index] = (byte)((data[index] & mask) | (pixelValue << (offset * 2))); + return; + } + if (depth == 4) { + index = (y * bytesPerLine) + (x >> 1); + if ((x & 0x1) == 0) { + data[index] = (byte)((data[index] & 0x0F) | ((pixelValue & 0x0F) << 4)); + } else { + data[index] = (byte)((data[index] & 0xF0) | (pixelValue & 0x0F)); + } + return; + } + if (depth == 8) { + index = (y * bytesPerLine) + x ; + data[index] = (byte)(pixelValue & 0xFF); + return; + } + if (depth == 16) { + index = (y * bytesPerLine) + (x * 2); + data[index + 1] = (byte)((pixelValue >> 8) & 0xFF); + data[index] = (byte)(pixelValue & 0xFF); + return; + } + if (depth == 24) { + index = (y * bytesPerLine) + (x * 3); + data[index] = (byte)((pixelValue >> 16) & 0xFF); + data[index + 1] = (byte)((pixelValue >> 8) & 0xFF); + data[index + 2] = (byte)(pixelValue & 0xFF); + return; + } + if (depth == 32) { + index = (y * bytesPerLine) + (x * 4); + data[index] = (byte)((pixelValue >> 24) & 0xFF); + data[index + 1] = (byte)((pixelValue >> 16) & 0xFF); + data[index + 2] = (byte)((pixelValue >> 8) & 0xFF); + data[index + 3] = (byte)(pixelValue & 0xFF); + return; + } + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); +} + +/** + * Sets the pixel values starting at offset <code>x</code> in + * scanline <code>y</code> in the receiver's data to the + * values from the array <code>pixels</code> starting at + * <code>startIndex</code>. + * + * @param x the x position of the pixel to set + * @param y the y position of the pixel to set + * @param putWidth the width of the pixels to set + * @param pixels the pixels to set + * @param startIndex the index at which to begin setting + * + * @exception IndexOutOfBoundsException if putWidth is too large + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> + * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> + * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8 + * (For higher depths, use the int[] version of this method.)</li> + * </ul> + */ +public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) { + if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (putWidth == 0) return; + int index; + int theByte; + int mask; + int n = putWidth; + int i = startIndex; + int srcX = x, srcY = y; + if (depth == 1) { + index = (y * bytesPerLine) + (x >> 3); + while (n > 0) { + mask = 1 << (7 - (srcX & 0x7)); + if ((pixels[i] & 0x1) == 1) { + data[index] = (byte)((data[index] & 0xFF) | mask); + } else { + data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1)); + } + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + if (mask == 1) { + index++; + } + } + } + return; + } + if (depth == 2) { + byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F }; + index = (y * bytesPerLine) + (x >> 2); + int offset = 3 - (x % 4); + while (n > 0) { + theByte = pixels[i] & 0x3; + data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2))); + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + offset = 0; + srcX = 0; + } else { + if (offset == 0) { + index++; + offset = 3; + } else { + offset--; + } + } + } + return; + } + if (depth == 4) { + index = (y * bytesPerLine) + (x >> 1); + boolean high = (x & 0x1) == 0; + while (n > 0) { + theByte = pixels[i] & 0x0F; + if (high) { + data[index] = (byte)((data[index] & 0x0F) | (theByte << 4)); + } else { + data[index] = (byte)((data[index] & 0xF0) | theByte); + } + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + high = true; + srcX = 0; + } else { + if (!high) index++; + high = !high; + } + } + return; + } + if (depth == 8) { + index = (y * bytesPerLine) + x; + for (int j = 0; j < putWidth; j++) { + data[index] = (byte)(pixels[i] & 0xFF); + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index++; + } + } + return; + } + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); +} + +/** + * Sets the pixel values starting at offset <code>x</code> in + * scanline <code>y</code> in the receiver's data to the + * values from the array <code>pixels</code> starting at + * <code>startIndex</code>. + * + * @param x the x position of the pixel to set + * @param y the y position of the pixel to set + * @param putWidth the width of the pixels to set + * @param pixels the pixels to set + * @param startIndex the index at which to begin setting + * + * @exception IndexOutOfBoundsException if putWidth is too large + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> + * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> + * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li> + * </ul> + */ +public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) { + if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (putWidth == 0) return; + int index; + int theByte; + int mask; + int n = putWidth; + int i = startIndex; + int pixel; + int srcX = x, srcY = y; + if (depth == 1) { + index = (y * bytesPerLine) + (x >> 3); + while (n > 0) { + mask = 1 << (7 - (srcX & 0x7)); + if ((pixels[i] & 0x1) == 1) { + data[index] = (byte)((data[index] & 0xFF) | mask); + } else { + data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1)); + } + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + if (mask == 1) { + index++; + } + } + } + return; + } + if (depth == 2) { + byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F }; + index = (y * bytesPerLine) + (x >> 2); + int offset = 3 - (x % 4); + while (n > 0) { + theByte = pixels[i] & 0x3; + data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2))); + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + offset = 3; + srcX = 0; + } else { + if (offset == 0) { + index++; + offset = 3; + } else { + offset--; + } + } + } + return; + } + if (depth == 4) { + index = (y * bytesPerLine) + (x >> 1); + boolean high = (x & 0x1) == 0; + while (n > 0) { + theByte = pixels[i] & 0x0F; + if (high) { + data[index] = (byte)((data[index] & 0x0F) | (theByte << 4)); + } else { + data[index] = (byte)((data[index] & 0xF0) | theByte); + } + i++; + n--; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + high = true; + srcX = 0; + } else { + if (!high) index++; + high = !high; + } + } + return; + } + if (depth == 8) { + index = (y * bytesPerLine) + x; + for (int j = 0; j < putWidth; j++) { + data[index] = (byte)(pixels[i] & 0xFF); + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index++; + } + } + return; + + } + if (depth == 16) { + index = (y * bytesPerLine) + (x * 2); + for (int j = 0; j < putWidth; j++) { + pixel = pixels[i]; + data[index] = (byte)(pixel & 0xFF); + data[index + 1] = (byte)((pixel >> 8) & 0xFF); + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index += 2; + } + } + return; + } + if (depth == 24) { + index = (y * bytesPerLine) + (x * 3); + for (int j = 0; j < putWidth; j++) { + pixel = pixels[i]; + data[index] = (byte)((pixel >> 16) & 0xFF); + data[index + 1] = (byte)((pixel >> 8) & 0xFF); + data[index + 2] = (byte)(pixel & 0xFF); + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index += 3; + } + } + return; + } + if (depth == 32) { + index = (y * bytesPerLine) + (x * 4); + for (int j = 0; j < putWidth; j++) { + pixel = pixels[i]; + data[index] = (byte)((pixel >> 24) & 0xFF); + data[index + 1] = (byte)((pixel >> 16) & 0xFF); + data[index + 2] = (byte)((pixel >> 8) & 0xFF); + data[index + 3] = (byte)(pixel & 0xFF); + i++; + srcX++; + if (srcX >= width) { + srcY++; + index = srcY * bytesPerLine; + srcX = 0; + } else { + index += 4; + } + } + return; + } + SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); +} + +/** + * Returns a palette with 2 colors: black & white. + */ +static PaletteData bwPalette() { + return new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255, 255, 255)}); +} + +/** + * Gets the offset of the most significant bit for + * the given mask. + */ +static int getMSBOffset(int mask) { + for (int i = 31; i >= 0; i--) { + if (((mask >> i) & 0x1) != 0) return i + 1; + } + return 0; +} + +/** + * Finds the closest match. + */ +static int closestMatch(int depth, byte red, byte green, byte blue, int redMask, int greenMask, int blueMask, byte[] reds, byte[] greens, byte[] blues) { + if (depth > 8) { + int rshift = 32 - getMSBOffset(redMask); + int gshift = 32 - getMSBOffset(greenMask); + int bshift = 32 - getMSBOffset(blueMask); + return (((red << 24) >>> rshift) & redMask) | + (((green << 24) >>> gshift) & greenMask) | + (((blue << 24) >>> bshift) & blueMask); + } + int r, g, b; + int minDistance = 0x7fffffff; + int nearestPixel = 0; + int n = reds.length; + for (int j = 0; j < n; j++) { + r = (reds[j] & 0xFF) - (red & 0xFF); + g = (greens[j] & 0xFF) - (green & 0xFF); + b = (blues[j] & 0xFF) - (blue & 0xFF); + int distance = r*r + g*g + b*b; + if (distance < minDistance) { + nearestPixel = j; + if (distance == 0) break; + minDistance = distance; + } + } + return nearestPixel; +} + +/** + * Blit operation bits to be OR'ed together to specify the desired operation. + */ +static final int + BLIT_SRC = 1, // copy source directly, else applies logic operations + BLIT_ALPHA = 2, // enable alpha blending + BLIT_DITHER = 4; // enable dithering in low color modes + +/** + * Alpha mode, values 0 - 255 specify global alpha level + */ +static final int + ALPHA_OPAQUE = 255, // Fully opaque (ignores any alpha data) + ALPHA_TRANSPARENT = 0, // Fully transparent (ignores any alpha data) + ALPHA_CHANNEL_SEPARATE = -1, // Use alpha channel from separate alphaData + ALPHA_CHANNEL_SOURCE = -2, // Use alpha channel embedded in sourceData + ALPHA_MASK_UNPACKED = -3, // Use transparency mask formed by bytes in alphaData (non-zero is opaque) + ALPHA_MASK_PACKED = -4, // Use transparency mask formed by packed bits in alphaData + ALPHA_MASK_INDEX = -5, // Consider source palette indices transparent if in alphaData array + ALPHA_MASK_RGB = -6; // Consider source RGBs transparent if in RGB888 format alphaData array + +/** + * Byte and bit order constants. + */ +static final int LSB_FIRST = 0; +static final int MSB_FIRST = 1; + +/** + * Data types (internal) + */ +private static final int + // direct / true color formats with arbitrary masks & shifts + TYPE_GENERIC_8 = 0, + TYPE_GENERIC_16_MSB = 1, + TYPE_GENERIC_16_LSB = 2, + TYPE_GENERIC_24 = 3, + TYPE_GENERIC_32_MSB = 4, + TYPE_GENERIC_32_LSB = 5, + // palette indexed color formats + TYPE_INDEX_8 = 6, + TYPE_INDEX_4 = 7, + TYPE_INDEX_2 = 8, + TYPE_INDEX_1_MSB = 9, + TYPE_INDEX_1_LSB = 10; + +/** + * Blits a direct palette image into a direct palette image. + * <p> + * Note: When the source and destination depth, order and masks + * are pairwise equal and the blitter operation is BLIT_SRC, + * the masks are ignored. Hence when not changing the image + * data format, 0 may be specified for the masks. + * </p> + * + * @param op the blitter operation: a combination of BLIT_xxx flags + * (see BLIT_xxx constants) + * @param srcData the source byte array containing image data + * @param srcDepth the source depth: one of 8, 16, 24, 32 + * @param srcStride the source number of bytes per line + * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if srcDepth is not 16 or 32 + * @param srcX the top-left x-coord of the source blit region + * @param srcY the top-left y-coord of the source blit region + * @param srcWidth the width of the source blit region + * @param srcHeight the height of the source blit region + * @param srcRedMask the source red channel mask + * @param srcGreenMask the source green channel mask + * @param srcBlueMask the source blue channel mask + * @param alphaMode the alpha blending or mask mode, may be + * an integer 0-255 for global alpha; ignored if BLIT_ALPHA + * not specified in the blitter operations + * (see ALPHA_MODE_xxx constants) + * @param alphaData the alpha blending or mask data, varies depending + * on the value of alphaMode and sometimes ignored + * @param alphaStride the alpha data number of bytes per line + * @param alphaX the top-left x-coord of the alpha blit region + * @param alphaY the top-left y-coord of the alpha blit region + * @param destData the destination byte array containing image data + * @param destDepth the destination depth: one of 8, 16, 24, 32 + * @param destStride the destination number of bytes per line + * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if destDepth is not 16 or 32 + * @param destX the top-left x-coord of the destination blit region + * @param destY the top-left y-coord of the destination blit region + * @param destWidth the width of the destination blit region + * @param destHeight the height of the destination blit region + * @param destRedMask the destination red channel mask + * @param destGreenMask the destination green channel mask + * @param destBlueMask the destination blue channel mask + * @param flipX if true the resulting image is flipped along the vertical axis + * @param flipY if true the resulting image is flipped along the horizontal axis + */ +static void blit(int op, + byte[] srcData, int srcDepth, int srcStride, int srcOrder, + int srcX, int srcY, int srcWidth, int srcHeight, + int srcRedMask, int srcGreenMask, int srcBlueMask, + int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY, + byte[] destData, int destDepth, int destStride, int destOrder, + int destX, int destY, int destWidth, int destHeight, + int destRedMask, int destGreenMask, int destBlueMask, + boolean flipX, boolean flipY) { + if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return; + + // these should be supplied as params later + final int srcAlphaMask = 0, destAlphaMask = 0; + + /*** Prepare scaling data ***/ + final int dwm1 = destWidth - 1; + final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0; + final int dhm1 = destHeight - 1; + final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0; + + /*** Prepare source-related data ***/ + final int sbpp, stype; + switch (srcDepth) { + case 8: + sbpp = 1; + stype = TYPE_GENERIC_8; + break; + case 16: + sbpp = 2; + stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB; + break; + case 24: + sbpp = 3; + stype = TYPE_GENERIC_24; + break; + case 32: + sbpp = 4; + stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int spr = srcY * srcStride + srcX * sbpp; + + /*** Prepare destination-related data ***/ + final int dbpp, dtype; + switch (destDepth) { + case 8: + dbpp = 1; + dtype = TYPE_GENERIC_8; + break; + case 16: + dbpp = 2; + dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB; + break; + case 24: + dbpp = 3; + dtype = TYPE_GENERIC_24; + break; + case 32: + dbpp = 4; + dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid destination type"); + return; + } + int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp; + final int dprxi = (flipX) ? -dbpp : dbpp; + final int dpryi = (flipY) ? -destStride : destStride; + + /*** Prepare special processing data ***/ + int apr; + if ((op & BLIT_ALPHA) != 0) { + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: + case ALPHA_CHANNEL_SEPARATE: + if (alphaData == null) alphaMode = 0x10000; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_PACKED: + if (alphaData == null) alphaMode = 0x10000; + alphaStride <<= 3; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_INDEX: + //throw new IllegalArgumentException("Invalid alpha type"); + return; + case ALPHA_MASK_RGB: + if (alphaData == null) alphaMode = 0x10000; + apr = 0; + break; + default: + alphaMode = (alphaMode << 16) / 255; // prescale + case ALPHA_CHANNEL_SOURCE: + apr = 0; + break; + } + } else { + alphaMode = 0x10000; + apr = 0; + } + + /*** Blit ***/ + int dp = dpr; + int sp = spr; + if ((alphaMode == 0x10000) && (stype == dtype) && + (srcRedMask == destRedMask) && (srcGreenMask == destGreenMask) && + (srcBlueMask == destBlueMask) && (srcAlphaMask == destAlphaMask)) { + /*** Fast blit (straight copy) ***/ + switch (sbpp) { + case 1: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = srcData[sp]; + sp += (sfx >>> 16); + } + } + break; + case 2: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = srcData[sp]; + destData[dp + 1] = srcData[sp + 1]; + sp += (sfx >>> 16) * 2; + } + } + break; + case 3: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = srcData[sp]; + destData[dp + 1] = srcData[sp + 1]; + destData[dp + 2] = srcData[sp + 2]; + sp += (sfx >>> 16) * 3; + } + } + break; + case 4: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = srcData[sp]; + destData[dp + 1] = srcData[sp + 1]; + destData[dp + 2] = srcData[sp + 2]; + destData[dp + 3] = srcData[sp + 3]; + sp += (sfx >>> 16) * 4; + } + } + break; + } + return; + } + /*** Comprehensive blit (apply transformations) ***/ + final int srcRedShift = getChannelShift(srcRedMask); + final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)]; + final int srcGreenShift = getChannelShift(srcGreenMask); + final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)]; + final int srcBlueShift = getChannelShift(srcBlueMask); + final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)]; + final int srcAlphaShift = getChannelShift(srcAlphaMask); + final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)]; + + final int destRedShift = getChannelShift(destRedMask); + final int destRedWidth = getChannelWidth(destRedMask, destRedShift); + final byte[] destReds = ANY_TO_EIGHT[destRedWidth]; + final int destRedPreShift = 8 - destRedWidth; + final int destGreenShift = getChannelShift(destGreenMask); + final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift); + final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth]; + final int destGreenPreShift = 8 - destGreenWidth; + final int destBlueShift = getChannelShift(destBlueMask); + final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift); + final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth]; + final int destBluePreShift = 8 - destBlueWidth; + final int destAlphaShift = getChannelShift(destAlphaMask); + final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift); + final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth]; + final int destAlphaPreShift = 8 - destAlphaWidth; + + int ap = apr, alpha = alphaMode; + int r = 0, g = 0, b = 0, a = 0; + int rq = 0, gq = 0, bq = 0, aq = 0; + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + ap = apr += (sfy >>> 16) * alphaStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_GENERIC_8: { + final int data = srcData[sp] & 0xff; + sp += (sfx >>> 16); + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_MSB: { + final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff); + sp += (sfx >>> 16) * 2; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_LSB: { + final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff); + sp += (sfx >>> 16) * 2; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_24: { + final int data = (( ((srcData[sp] & 0xff) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp + 2] & 0xff); + sp += (sfx >>> 16) * 3; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_MSB: { + final int data = (( (( ((srcData[sp] & 0xff) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp + 2] & 0xff)) << 8) | + (srcData[sp + 3] & 0xff); + sp += (sfx >>> 16) * 4; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_LSB: { + final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) | + (srcData[sp + 2] & 0xff)) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp] & 0xff); + sp += (sfx >>> 16) * 4; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + } + + /*** DO SPECIAL PROCESSING IF REQUIRED ***/ + switch (alphaMode) { + case ALPHA_CHANNEL_SEPARATE: + alpha = ((alphaData[ap] & 0xff) << 16) / 255; + ap += (sfx >> 16); + break; + case ALPHA_CHANNEL_SOURCE: + alpha = (a << 16) / 255; + break; + case ALPHA_MASK_UNPACKED: + alpha = (alphaData[ap] != 0) ? 0x10000 : 0; + ap += (sfx >> 16); + break; + case ALPHA_MASK_PACKED: + alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000; + ap += (sfx >> 16); + break; + case ALPHA_MASK_RGB: + alpha = 0x10000; + for (int i = 0; i < alphaData.length; i += 3) { + if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) { + alpha = 0x0000; + break; + } + } + break; + } + if (alpha != 0x10000) { + if (alpha == 0x0000) continue; + switch (dtype) { + case TYPE_GENERIC_8: { + final int data = destData[dp] & 0xff; + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_MSB: { + final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_LSB: { + final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_24: { + final int data = (( ((destData[dp] & 0xff) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp + 2] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_MSB: { + final int data = (( (( ((destData[dp] & 0xff) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp + 2] & 0xff)) << 8) | + (destData[dp + 3] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_LSB: { + final int data = (( (( ((destData[dp + 3] & 0xff) << 8) | + (destData[dp + 2] & 0xff)) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + } + // Perform alpha blending + a = aq + ((a - aq) * alpha >> 16); + r = rq + ((r - rq) * alpha >> 16); + g = gq + ((g - gq) * alpha >> 16); + b = bq + ((b - bq) * alpha >> 16); + } + + /*** WRITE NEXT PIXEL ***/ + final int data = + (r >>> destRedPreShift << destRedShift) | + (g >>> destGreenPreShift << destGreenShift) | + (b >>> destBluePreShift << destBlueShift) | + (a >>> destAlphaPreShift << destAlphaShift); + switch (dtype) { + case TYPE_GENERIC_8: { + destData[dp] = (byte) data; + } break; + case TYPE_GENERIC_16_MSB: { + destData[dp] = (byte) (data >>> 8); + destData[dp + 1] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_16_LSB: { + destData[dp] = (byte) (data & 0xff); + destData[dp + 1] = (byte) (data >>> 8); + } break; + case TYPE_GENERIC_24: { + destData[dp] = (byte) (data >>> 16); + destData[dp + 1] = (byte) (data >>> 8); + destData[dp + 2] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_32_MSB: { + destData[dp] = (byte) (data >>> 24); + destData[dp + 1] = (byte) (data >>> 16); + destData[dp + 2] = (byte) (data >>> 8); + destData[dp + 3] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_32_LSB: { + destData[dp] = (byte) (data & 0xff); + destData[dp + 1] = (byte) (data >>> 8); + destData[dp + 2] = (byte) (data >>> 16); + destData[dp + 3] = (byte) (data >>> 24); + } break; + } + } + } +} + +/** + * Blits an index palette image into an index palette image. + * <p> + * Note: The source and destination red, green, and blue + * arrays may be null if no alpha blending or dither is to be + * performed. + * </p> + * + * @param op the blitter operation: a combination of BLIT_xxx flags + * (see BLIT_xxx constants) + * @param srcData the source byte array containing image data + * @param srcDepth the source depth: one of 1, 2, 4, 8 + * @param srcStride the source number of bytes per line + * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if srcDepth is not 1 + * @param srcX the top-left x-coord of the source blit region + * @param srcY the top-left y-coord of the source blit region + * @param srcWidth the width of the source blit region + * @param srcHeight the height of the source blit region + * @param srcReds the source palette red component intensities + * @param srcGreens the source palette green component intensities + * @param srcBlues the source palette blue component intensities + * @param alphaMode the alpha blending or mask mode, may be + * an integer 0-255 for global alpha; ignored if BLIT_ALPHA + * not specified in the blitter operations + * (see ALPHA_MODE_xxx constants) + * @param alphaData the alpha blending or mask data, varies depending + * on the value of alphaMode and sometimes ignored + * @param alphaStride the alpha data number of bytes per line + * @param alphaX the top-left x-coord of the alpha blit region + * @param alphaY the top-left y-coord of the alpha blit region + * @param destData the destination byte array containing image data + * @param destDepth the destination depth: one of 1, 2, 4, 8 + * @param destStride the destination number of bytes per line + * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if destDepth is not 1 + * @param destX the top-left x-coord of the destination blit region + * @param destY the top-left y-coord of the destination blit region + * @param destWidth the width of the destination blit region + * @param destHeight the height of the destination blit region + * @param destReds the destination palette red component intensities + * @param destGreens the destination palette green component intensities + * @param destBlues the destination palette blue component intensities + * @param flipX if true the resulting image is flipped along the vertical axis + * @param flipY if true the resulting image is flipped along the horizontal axis + */ +static void blit(int op, + byte[] srcData, int srcDepth, int srcStride, int srcOrder, + int srcX, int srcY, int srcWidth, int srcHeight, + byte[] srcReds, byte[] srcGreens, byte[] srcBlues, + int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY, + byte[] destData, int destDepth, int destStride, int destOrder, + int destX, int destY, int destWidth, int destHeight, + byte[] destReds, byte[] destGreens, byte[] destBlues, + boolean flipX, boolean flipY) { + if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return; + + /*** Prepare scaling data ***/ + final int dwm1 = destWidth - 1; + final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0; + final int dhm1 = destHeight - 1; + final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0; + + /*** Prepare source-related data ***/ + final int stype; + switch (srcDepth) { + case 8: + stype = TYPE_INDEX_8; + break; + case 4: + srcStride <<= 1; + stype = TYPE_INDEX_4; + break; + case 2: + srcStride <<= 2; + stype = TYPE_INDEX_2; + break; + case 1: + srcStride <<= 3; + stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int spr = srcY * srcStride + srcX; + + /*** Prepare destination-related data ***/ + final int dtype; + switch (destDepth) { + case 8: + dtype = TYPE_INDEX_8; + break; + case 4: + destStride <<= 1; + dtype = TYPE_INDEX_4; + break; + case 2: + destStride <<= 2; + dtype = TYPE_INDEX_2; + break; + case 1: + destStride <<= 3; + dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX); + final int dprxi = (flipX) ? -1 : 1; + final int dpryi = (flipY) ? -destStride : destStride; + + /*** Prepare special processing data ***/ + int apr; + if ((op & BLIT_ALPHA) != 0) { + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: + case ALPHA_CHANNEL_SEPARATE: + if (alphaData == null) alphaMode = 0x10000; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_PACKED: + if (alphaData == null) alphaMode = 0x10000; + alphaStride <<= 3; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_INDEX: + case ALPHA_MASK_RGB: + if (alphaData == null) alphaMode = 0x10000; + apr = 0; + break; + default: + alphaMode = (alphaMode << 16) / 255; // prescale + case ALPHA_CHANNEL_SOURCE: + apr = 0; + break; + } + } else { + alphaMode = 0x10000; + apr = 0; + } + final boolean ditherEnabled = (op & BLIT_DITHER) != 0; + + /*** Blit ***/ + int dp = dpr; + int sp = spr; + int ap = apr; + int destPaletteSize = 1 << destDepth; + if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length; + byte[] paletteMapping = null; + boolean isExactPaletteMapping = true; + switch (alphaMode) { + case 0x10000: + /*** If the palettes and formats are equivalent use a one-to-one mapping ***/ + if ((stype == dtype) && + (srcReds == destReds) && (srcGreens == destGreens) && (srcBlues == destBlues)) { + paletteMapping = ONE_TO_ONE_MAPPING; + break; + /*** If palettes have not been supplied, supply a suitable mapping ***/ + } else if ((srcReds == null) || (destReds == null)) { + if (srcDepth <= destDepth) { + paletteMapping = ONE_TO_ONE_MAPPING; + } else { + paletteMapping = new byte[1 << srcDepth]; + int mask = (0xff << destDepth) >>> 8; + for (int i = 0; i < paletteMapping.length; ++i) paletteMapping[i] = (byte)(i & mask); + } + break; + } + case ALPHA_MASK_UNPACKED: + case ALPHA_MASK_PACKED: + case ALPHA_MASK_INDEX: + case ALPHA_MASK_RGB: + /*** Generate a palette mapping ***/ + int srcPaletteSize = 1 << srcDepth; + paletteMapping = new byte[srcPaletteSize]; + if ((srcReds != null) && (srcReds.length < srcPaletteSize)) srcPaletteSize = srcReds.length; + for (int i = 0, r, g, b, index; i < srcPaletteSize; ++i) { + r = srcReds[i] & 0xff; + g = srcGreens[i] & 0xff; + b = srcBlues[i] & 0xff; + index = 0; + int minDistance = 0x7fffffff; + for (int j = 0, dr, dg, db, distance; j < destPaletteSize; ++j) { + dr = (destReds[j] & 0xff) - r; + dg = (destGreens[j] & 0xff) - g; + db = (destBlues[j] & 0xff) - b; + distance = dr * dr + dg * dg + db * db; + if (distance < minDistance) { + index = j; + if (distance == 0) break; + minDistance = distance; + } + } + paletteMapping[i] = (byte)index; + if (minDistance != 0) isExactPaletteMapping = false; + } + break; + } + if ((paletteMapping != null) && (isExactPaletteMapping || ! ditherEnabled)) { + if ((stype == dtype) && (alphaMode == 0x10000)) { + /*** Fast blit (copy w/ mapping) ***/ + switch (stype) { + case TYPE_INDEX_8: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + destData[dp] = paletteMapping[srcData[sp] & 0xff]; + sp += (sfx >>> 16); + } + } + break; + case TYPE_INDEX_4: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + final int v; + if ((sp & 1) != 0) v = paletteMapping[srcData[sp >> 1] & 0x0f]; + else v = (srcData[sp >> 1] >>> 4) & 0x0f; + sp += (sfx >>> 16); + if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | v); + else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (v << 4)); + } + } + break; + case TYPE_INDEX_2: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + final int index = paletteMapping[(srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03]; + sp += (sfx >>> 16); + final int shift = 6 - (dp & 3) * 2; + destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift)); + } + } + break; + case TYPE_INDEX_1_MSB: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + final int index = paletteMapping[(srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01]; + sp += (sfx >>> 16); + final int shift = 7 - (dp & 7); + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift)); + } + } + break; + case TYPE_INDEX_1_LSB: + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) { + final int index = paletteMapping[(srcData[sp >> 3] >>> (sp & 7)) & 0x01]; + sp += (sfx >>> 16); + final int shift = dp & 7; + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift)); + } + } + break; + } + } else { + /*** Convert between indexed modes using mapping and mask ***/ + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + int index; + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_INDEX_8: + index = srcData[sp] & 0xff; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_4: + if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f; + else index = (srcData[sp >> 1] >>> 4) & 0x0f; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_2: + index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_MSB: + index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_LSB: + index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01; + sp += (sfx >>> 16); + break; + default: + return; + } + /*** APPLY MASK ***/ + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: { + final byte mask = alphaData[ap]; + ap += (sfx >> 16); + if (mask == 0) continue; + } break; + case ALPHA_MASK_PACKED: { + final int mask = alphaData[ap >> 3] & (1 << (ap & 7)); + ap += (sfx >> 16); + if (mask == 0) continue; + } break; + case ALPHA_MASK_INDEX: { + int i = 0; + while (i < alphaData.length) { + if (index == (alphaData[i] & 0xff)) break; + } + if (i < alphaData.length) continue; + } break; + case ALPHA_MASK_RGB: { + final byte r = srcReds[index], g = srcGreens[index], b = srcBlues[index]; + int i = 0; + while (i < alphaData.length) { + if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) break; + i += 3; + } + if (i < alphaData.length) continue; + } break; + } + index = paletteMapping[index] & 0xff; + + /*** WRITE NEXT PIXEL ***/ + switch (dtype) { + case TYPE_INDEX_8: + destData[dp] = (byte) index; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | index); + else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (index << 4)); + break; + case TYPE_INDEX_2: { + final int shift = 6 - (dp & 3) * 2; + destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift)); + } break; + case TYPE_INDEX_1_MSB: { + final int shift = 7 - (dp & 7); + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift)); + } break; + case TYPE_INDEX_1_LSB: { + final int shift = dp & 7; + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift)); + } break; + } + } + } + } + return; + } + + /*** Comprehensive blit (apply transformations) ***/ + int alpha = alphaMode; + int index = 0; + int indexq = 0; + int lastindex = 0, lastr = -1, lastg = -1, lastb = -1; + final int[] rerr, gerr, berr; + if (ditherEnabled) { + rerr = new int[destWidth + 2]; + gerr = new int[destWidth + 2]; + berr = new int[destWidth + 2]; + } else { + rerr = null; gerr = null; berr = null; + } + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + ap = apr += (sfy >>> 16) * alphaStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + int lrerr = 0, lgerr = 0, lberr = 0; + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_INDEX_8: + index = srcData[sp] & 0xff; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_4: + if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f; + else index = (srcData[sp >> 1] >>> 4) & 0x0f; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_2: + index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_MSB: + index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_LSB: + index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01; + sp += (sfx >>> 16); + break; + } + + /*** DO SPECIAL PROCESSING IF REQUIRED ***/ + int r = srcReds[index] & 0xff, g = srcGreens[index] & 0xff, b = srcBlues[index] & 0xff; + switch (alphaMode) { + case ALPHA_CHANNEL_SEPARATE: + alpha = ((alphaData[ap] & 0xff) << 16) / 255; + ap += (sfx >> 16); + break; + case ALPHA_MASK_UNPACKED: + alpha = (alphaData[ap] != 0) ? 0x10000 : 0; + ap += (sfx >> 16); + break; + case ALPHA_MASK_PACKED: + alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000; + ap += (sfx >> 16); + break; + case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices + int i = 0; + while (i < alphaData.length) { + if (index == (alphaData[i] & 0xff)) break; + } + if (i < alphaData.length) continue; + } break; + case ALPHA_MASK_RGB: { + int i = 0; + while (i < alphaData.length) { + if ((r == (alphaData[i] & 0xff)) && + (g == (alphaData[i + 1] & 0xff)) && + (b == (alphaData[i + 2] & 0xff))) break; + i += 3; + } + if (i < alphaData.length) continue; + } break; + } + if (alpha != 0x10000) { + if (alpha == 0x0000) continue; + switch (dtype) { + case TYPE_INDEX_8: + indexq = destData[dp] & 0xff; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f; + else indexq = (destData[dp >> 1] >>> 4) & 0x0f; + break; + case TYPE_INDEX_2: + indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03; + break; + case TYPE_INDEX_1_MSB: + indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01; + break; + case TYPE_INDEX_1_LSB: + indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01; + break; + } + // Perform alpha blending + final int rq = destReds[indexq] & 0xff; + final int gq = destGreens[indexq] & 0xff; + final int bq = destBlues[indexq] & 0xff; + r = rq + ((r - rq) * alpha >> 16); + g = gq + ((g - gq) * alpha >> 16); + b = bq + ((b - bq) * alpha >> 16); + } + + /*** MAP COLOR TO THE PALETTE ***/ + if (ditherEnabled) { + // Floyd-Steinberg error diffusion + r += rerr[dx] >> 4; + if (r < 0) r = 0; else if (r > 255) r = 255; + g += gerr[dx] >> 4; + if (g < 0) g = 0; else if (g > 255) g = 255; + b += berr[dx] >> 4; + if (b < 0) b = 0; else if (b > 255) b = 255; + rerr[dx] = lrerr; + gerr[dx] = lgerr; + berr[dx] = lberr; + } + if (r != lastr || g != lastg || b != lastb) { + // moving the variable declarations out seems to make the JDK JIT happier... + for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) { + dr = (destReds[j] & 0xff) - r; + dg = (destGreens[j] & 0xff) - g; + db = (destBlues[j] & 0xff) - b; + distance = dr * dr + dg * dg + db * db; + if (distance < minDistance) { + lastindex = j; + if (distance == 0) break; + minDistance = distance; + } + } + lastr = r; lastg = g; lastb = b; + } + if (ditherEnabled) { + // Floyd-Steinberg error diffusion, cont'd... + final int dxm1 = dx - 1, dxp1 = dx + 1; + int acc; + rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr; + rerr[dx] += acc += lrerr + lrerr; + rerr[dxm1] += acc + lrerr + lrerr; + gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr; + gerr[dx] += acc += lgerr + lgerr; + gerr[dxm1] += acc + lgerr + lgerr; + berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr; + berr[dx] += acc += lberr + lberr; + berr[dxm1] += acc + lberr + lberr; + } + + /*** WRITE NEXT PIXEL ***/ + switch (dtype) { + case TYPE_INDEX_8: + destData[dp] = (byte) lastindex; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex); + else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4)); + break; + case TYPE_INDEX_2: { + final int shift = 6 - (dp & 3) * 2; + destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift)); + } break; + case TYPE_INDEX_1_MSB: { + final int shift = 7 - (dp & 7); + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift)); + } break; + case TYPE_INDEX_1_LSB: { + final int shift = dp & 7; + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift)); + } break; + } + } + } +} + +/** + * Blits an index palette image into a direct palette image. + * <p> + * Note: The source and destination masks and palettes must + * always be fully specified. + * </p> + * + * @param op the blitter operation: a combination of BLIT_xxx flags + * (see BLIT_xxx constants) + * @param srcData the source byte array containing image data + * @param srcDepth the source depth: one of 1, 2, 4, 8 + * @param srcStride the source number of bytes per line + * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if srcDepth is not 1 + * @param srcX the top-left x-coord of the source blit region + * @param srcY the top-left y-coord of the source blit region + * @param srcWidth the width of the source blit region + * @param srcHeight the height of the source blit region + * @param srcReds the source palette red component intensities + * @param srcGreens the source palette green component intensities + * @param srcBlues the source palette blue component intensities + * @param alphaMode the alpha blending or mask mode, may be + * an integer 0-255 for global alpha; ignored if BLIT_ALPHA + * not specified in the blitter operations + * (see ALPHA_MODE_xxx constants) + * @param alphaData the alpha blending or mask data, varies depending + * on the value of alphaMode and sometimes ignored + * @param alphaStride the alpha data number of bytes per line + * @param alphaX the top-left x-coord of the alpha blit region + * @param alphaY the top-left y-coord of the alpha blit region + * @param destData the destination byte array containing image data + * @param destDepth the destination depth: one of 8, 16, 24, 32 + * @param destStride the destination number of bytes per line + * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if destDepth is not 16 or 32 + * @param destX the top-left x-coord of the destination blit region + * @param destY the top-left y-coord of the destination blit region + * @param destWidth the width of the destination blit region + * @param destHeight the height of the destination blit region + * @param destRedMask the destination red channel mask + * @param destGreenMask the destination green channel mask + * @param destBlueMask the destination blue channel mask + * @param flipX if true the resulting image is flipped along the vertical axis + * @param flipY if true the resulting image is flipped along the horizontal axis + */ +static void blit(int op, + byte[] srcData, int srcDepth, int srcStride, int srcOrder, + int srcX, int srcY, int srcWidth, int srcHeight, + byte[] srcReds, byte[] srcGreens, byte[] srcBlues, + int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY, + byte[] destData, int destDepth, int destStride, int destOrder, + int destX, int destY, int destWidth, int destHeight, + int destRedMask, int destGreenMask, int destBlueMask, + boolean flipX, boolean flipY) { + if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return; + + // these should be supplied as params later + final int destAlphaMask = 0; + + /*** Prepare scaling data ***/ + final int dwm1 = destWidth - 1; + final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0; + final int dhm1 = destHeight - 1; + final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0; + + /*** Prepare source-related data ***/ + final int stype; + switch (srcDepth) { + case 8: + stype = TYPE_INDEX_8; + break; + case 4: + srcStride <<= 1; + stype = TYPE_INDEX_4; + break; + case 2: + srcStride <<= 2; + stype = TYPE_INDEX_2; + break; + case 1: + srcStride <<= 3; + stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int spr = srcY * srcStride + srcX; + + /*** Prepare destination-related data ***/ + final int dbpp, dtype; + switch (destDepth) { + case 8: + dbpp = 1; + dtype = TYPE_GENERIC_8; + break; + case 16: + dbpp = 2; + dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB; + break; + case 24: + dbpp = 3; + dtype = TYPE_GENERIC_24; + break; + case 32: + dbpp = 4; + dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid destination type"); + return; + } + int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp; + final int dprxi = (flipX) ? -dbpp : dbpp; + final int dpryi = (flipY) ? -destStride : destStride; + + /*** Prepare special processing data ***/ + int apr; + if ((op & BLIT_ALPHA) != 0) { + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: + case ALPHA_CHANNEL_SEPARATE: + if (alphaData == null) alphaMode = 0x10000; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_PACKED: + if (alphaData == null) alphaMode = 0x10000; + alphaStride <<= 3; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_INDEX: + case ALPHA_MASK_RGB: + if (alphaData == null) alphaMode = 0x10000; + apr = 0; + break; + default: + alphaMode = (alphaMode << 16) / 255; // prescale + case ALPHA_CHANNEL_SOURCE: + apr = 0; + break; + } + } else { + alphaMode = 0x10000; + apr = 0; + } + + /*** Comprehensive blit (apply transformations) ***/ + final int destRedShift = getChannelShift(destRedMask); + final int destRedWidth = getChannelWidth(destRedMask, destRedShift); + final byte[] destReds = ANY_TO_EIGHT[destRedWidth]; + final int destRedPreShift = 8 - destRedWidth; + final int destGreenShift = getChannelShift(destGreenMask); + final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift); + final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth]; + final int destGreenPreShift = 8 - destGreenWidth; + final int destBlueShift = getChannelShift(destBlueMask); + final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift); + final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth]; + final int destBluePreShift = 8 - destBlueWidth; + final int destAlphaShift = getChannelShift(destAlphaMask); + final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift); + final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth]; + final int destAlphaPreShift = 8 - destAlphaWidth; + + int dp = dpr; + int sp = spr; + int ap = apr, alpha = alphaMode; + int r = 0, g = 0, b = 0, a = 0, index = 0; + int rq = 0, gq = 0, bq = 0, aq = 0; + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + ap = apr += (sfy >>> 16) * alphaStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_INDEX_8: + index = srcData[sp] & 0xff; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_4: + if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f; + else index = (srcData[sp >> 1] >>> 4) & 0x0f; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_2: + index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_MSB: + index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01; + sp += (sfx >>> 16); + break; + case TYPE_INDEX_1_LSB: + index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01; + sp += (sfx >>> 16); + break; + } + + /*** DO SPECIAL PROCESSING IF REQUIRED ***/ + r = srcReds[index] & 0xff; + g = srcGreens[index] & 0xff; + b = srcBlues[index] & 0xff; + switch (alphaMode) { + case ALPHA_CHANNEL_SEPARATE: + alpha = ((alphaData[ap] & 0xff) << 16) / 255; + ap += (sfx >> 16); + break; + case ALPHA_MASK_UNPACKED: + alpha = (alphaData[ap] != 0) ? 0x10000 : 0; + ap += (sfx >> 16); + break; + case ALPHA_MASK_PACKED: + alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000; + ap += (sfx >> 16); + break; + case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices + int i = 0; + while (i < alphaData.length) { + if (index == (alphaData[i] & 0xff)) break; + } + if (i < alphaData.length) continue; + } break; + case ALPHA_MASK_RGB: { + int i = 0; + while (i < alphaData.length) { + if ((r == (alphaData[i] & 0xff)) && + (g == (alphaData[i + 1] & 0xff)) && + (b == (alphaData[i + 2] & 0xff))) break; + i += 3; + } + if (i < alphaData.length) continue; + } break; + } + if (alpha != 0x10000) { + if (alpha == 0x0000) continue; + switch (dtype) { + case TYPE_GENERIC_8: { + final int data = destData[dp] & 0xff; + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_MSB: { + final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_LSB: { + final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_24: { + final int data = (( ((destData[dp] & 0xff) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp + 2] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_MSB: { + final int data = (( (( ((destData[dp] & 0xff) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp + 2] & 0xff)) << 8) | + (destData[dp + 3] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_LSB: { + final int data = (( (( ((destData[dp + 3] & 0xff) << 8) | + (destData[dp + 2] & 0xff)) << 8) | + (destData[dp + 1] & 0xff)) << 8) | + (destData[dp] & 0xff); + rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff; + gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff; + bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff; + aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff; + } break; + } + // Perform alpha blending + a = aq + ((a - aq) * alpha >> 16); + r = rq + ((r - rq) * alpha >> 16); + g = gq + ((g - gq) * alpha >> 16); + b = bq + ((b - bq) * alpha >> 16); + } + + /*** WRITE NEXT PIXEL ***/ + final int data = + (r >>> destRedPreShift << destRedShift) | + (g >>> destGreenPreShift << destGreenShift) | + (b >>> destBluePreShift << destBlueShift) | + (a >>> destAlphaPreShift << destAlphaShift); + switch (dtype) { + case TYPE_GENERIC_8: { + destData[dp] = (byte) data; + } break; + case TYPE_GENERIC_16_MSB: { + destData[dp] = (byte) (data >>> 8); + destData[dp + 1] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_16_LSB: { + destData[dp] = (byte) (data & 0xff); + destData[dp + 1] = (byte) (data >>> 8); + } break; + case TYPE_GENERIC_24: { + destData[dp] = (byte) (data >>> 16); + destData[dp + 1] = (byte) (data >>> 8); + destData[dp + 2] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_32_MSB: { + destData[dp] = (byte) (data >>> 24); + destData[dp + 1] = (byte) (data >>> 16); + destData[dp + 2] = (byte) (data >>> 8); + destData[dp + 3] = (byte) (data & 0xff); + } break; + case TYPE_GENERIC_32_LSB: { + destData[dp] = (byte) (data & 0xff); + destData[dp + 1] = (byte) (data >>> 8); + destData[dp + 2] = (byte) (data >>> 16); + destData[dp + 3] = (byte) (data >>> 24); + } break; + } + } + } +} + +/** + * Blits a direct palette image into an index palette image. + * <p> + * Note: The source and destination masks and palettes must + * always be fully specified. + * </p> + * + * @param op the blitter operation: a combination of BLIT_xxx flags + * (see BLIT_xxx constants) + * @param srcData the source byte array containing image data + * @param srcDepth the source depth: one of 8, 16, 24, 32 + * @param srcStride the source number of bytes per line + * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if srcDepth is not 16 or 32 + * @param srcX the top-left x-coord of the source blit region + * @param srcY the top-left y-coord of the source blit region + * @param srcWidth the width of the source blit region + * @param srcHeight the height of the source blit region + * @param srcRedMask the source red channel mask + * @param srcGreenMask the source green channel mask + * @param srcBlueMask the source blue channel mask + * @param alphaMode the alpha blending or mask mode, may be + * an integer 0-255 for global alpha; ignored if BLIT_ALPHA + * not specified in the blitter operations + * (see ALPHA_MODE_xxx constants) + * @param alphaData the alpha blending or mask data, varies depending + * on the value of alphaMode and sometimes ignored + * @param alphaStride the alpha data number of bytes per line + * @param alphaX the top-left x-coord of the alpha blit region + * @param alphaY the top-left y-coord of the alpha blit region + * @param destData the destination byte array containing image data + * @param destDepth the destination depth: one of 1, 2, 4, 8 + * @param destStride the destination number of bytes per line + * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST; + * ignored if destDepth is not 1 + * @param destX the top-left x-coord of the destination blit region + * @param destY the top-left y-coord of the destination blit region + * @param destWidth the width of the destination blit region + * @param destHeight the height of the destination blit region + * @param destReds the destination palette red component intensities + * @param destGreens the destination palette green component intensities + * @param destBlues the destination palette blue component intensities + * @param flipX if true the resulting image is flipped along the vertical axis + * @param flipY if true the resulting image is flipped along the horizontal axis + */ +static void blit(int op, + byte[] srcData, int srcDepth, int srcStride, int srcOrder, + int srcX, int srcY, int srcWidth, int srcHeight, + int srcRedMask, int srcGreenMask, int srcBlueMask, + int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY, + byte[] destData, int destDepth, int destStride, int destOrder, + int destX, int destY, int destWidth, int destHeight, + byte[] destReds, byte[] destGreens, byte[] destBlues, + boolean flipX, boolean flipY) { + if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return; + + // these should be supplied as params later + final int srcAlphaMask = 0; + + /*** Prepare scaling data ***/ + final int dwm1 = destWidth - 1; + final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0; + final int dhm1 = destHeight - 1; + final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0; + + /*** Prepare source-related data ***/ + final int sbpp, stype; + switch (srcDepth) { + case 8: + sbpp = 1; + stype = TYPE_GENERIC_8; + break; + case 16: + sbpp = 2; + stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB; + break; + case 24: + sbpp = 3; + stype = TYPE_GENERIC_24; + break; + case 32: + sbpp = 4; + stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int spr = srcY * srcStride + srcX * sbpp; + + /*** Prepare destination-related data ***/ + final int dtype; + switch (destDepth) { + case 8: + dtype = TYPE_INDEX_8; + break; + case 4: + destStride <<= 1; + dtype = TYPE_INDEX_4; + break; + case 2: + destStride <<= 2; + dtype = TYPE_INDEX_2; + break; + case 1: + destStride <<= 3; + dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB; + break; + default: + //throw new IllegalArgumentException("Invalid source type"); + return; + } + int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX); + final int dprxi = (flipX) ? -1 : 1; + final int dpryi = (flipY) ? -destStride : destStride; + + /*** Prepare special processing data ***/ + int apr; + if ((op & BLIT_ALPHA) != 0) { + switch (alphaMode) { + case ALPHA_MASK_UNPACKED: + case ALPHA_CHANNEL_SEPARATE: + if (alphaData == null) alphaMode = 0x10000; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_PACKED: + if (alphaData == null) alphaMode = 0x10000; + alphaStride <<= 3; + apr = alphaY * alphaStride + alphaX; + break; + case ALPHA_MASK_INDEX: + //throw new IllegalArgumentException("Invalid alpha type"); + return; + case ALPHA_MASK_RGB: + if (alphaData == null) alphaMode = 0x10000; + apr = 0; + break; + default: + alphaMode = (alphaMode << 16) / 255; // prescale + case ALPHA_CHANNEL_SOURCE: + apr = 0; + break; + } + } else { + alphaMode = 0x10000; + apr = 0; + } + final boolean ditherEnabled = (op & BLIT_DITHER) != 0; + + /*** Comprehensive blit (apply transformations) ***/ + final int srcRedShift = getChannelShift(srcRedMask); + final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)]; + final int srcGreenShift = getChannelShift(srcGreenMask); + final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)]; + final int srcBlueShift = getChannelShift(srcBlueMask); + final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)]; + final int srcAlphaShift = getChannelShift(srcAlphaMask); + final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)]; + + int dp = dpr; + int sp = spr; + int ap = apr, alpha = alphaMode; + int r = 0, g = 0, b = 0, a = 0; + int indexq = 0; + int lastindex = 0, lastr = -1, lastg = -1, lastb = -1; + final int[] rerr, gerr, berr; + int destPaletteSize = 1 << destDepth; + if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length; + if (ditherEnabled) { + rerr = new int[destWidth + 2]; + gerr = new int[destWidth + 2]; + berr = new int[destWidth + 2]; + } else { + rerr = null; gerr = null; berr = null; + } + for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, + sp = spr += (sfy >>> 16) * srcStride, + ap = apr += (sfy >>> 16) * alphaStride, + sfy = (sfy & 0xffff) + sfyi, + dp = dpr += dpryi) { + int lrerr = 0, lgerr = 0, lberr = 0; + for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, + dp += dprxi, + sfx = (sfx & 0xffff) + sfxi) { + /*** READ NEXT PIXEL ***/ + switch (stype) { + case TYPE_GENERIC_8: { + final int data = srcData[sp] & 0xff; + sp += (sfx >>> 16); + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_MSB: { + final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff); + sp += (sfx >>> 16) * 2; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_16_LSB: { + final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff); + sp += (sfx >>> 16) * 2; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_24: { + final int data = (( ((srcData[sp] & 0xff) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp + 2] & 0xff); + sp += (sfx >>> 16) * 3; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_MSB: { + final int data = (( (( ((srcData[sp] & 0xff) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp + 2] & 0xff)) << 8) | + (srcData[sp + 3] & 0xff); + sp += (sfx >>> 16) * 4; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + case TYPE_GENERIC_32_LSB: { + final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) | + (srcData[sp + 2] & 0xff)) << 8) | + (srcData[sp + 1] & 0xff)) << 8) | + (srcData[sp] & 0xff); + sp += (sfx >>> 16) * 4; + r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff; + g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff; + b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff; + a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff; + } break; + } + + /*** DO SPECIAL PROCESSING IF REQUIRED ***/ + switch (alphaMode) { + case ALPHA_CHANNEL_SEPARATE: + alpha = ((alphaData[ap] & 0xff) << 16) / 255; + ap += (sfx >> 16); + break; + case ALPHA_CHANNEL_SOURCE: + alpha = (a << 16) / 255; + break; + case ALPHA_MASK_UNPACKED: + alpha = (alphaData[ap] != 0) ? 0x10000 : 0; + ap += (sfx >> 16); + break; + case ALPHA_MASK_PACKED: + alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000; + ap += (sfx >> 16); + break; + case ALPHA_MASK_RGB: + alpha = 0x10000; + for (int i = 0; i < alphaData.length; i += 3) { + if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) { + alpha = 0x0000; + break; + } + } + break; + } + if (alpha != 0x10000) { + if (alpha == 0x0000) continue; + switch (dtype) { + case TYPE_INDEX_8: + indexq = destData[dp] & 0xff; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f; + else indexq = (destData[dp >> 1] >>> 4) & 0x0f; + break; + case TYPE_INDEX_2: + indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03; + break; + case TYPE_INDEX_1_MSB: + indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01; + break; + case TYPE_INDEX_1_LSB: + indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01; + break; + } + // Perform alpha blending + final int rq = destReds[indexq] & 0xff; + final int gq = destGreens[indexq] & 0xff; + final int bq = destBlues[indexq] & 0xff; + r = rq + ((r - rq) * alpha >> 16); + g = gq + ((g - gq) * alpha >> 16); + b = bq + ((b - bq) * alpha >> 16); + } + + /*** MAP COLOR TO THE PALETTE ***/ + if (ditherEnabled) { + // Floyd-Steinberg error diffusion + r += rerr[dx] >> 4; + if (r < 0) r = 0; else if (r > 255) r = 255; + g += gerr[dx] >> 4; + if (g < 0) g = 0; else if (g > 255) g = 255; + b += berr[dx] >> 4; + if (b < 0) b = 0; else if (b > 255) b = 255; + rerr[dx] = lrerr; + gerr[dx] = lgerr; + berr[dx] = lberr; + } + if (r != lastr || g != lastg || b != lastb) { + // moving the variable declarations out seems to make the JDK JIT happier... + for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) { + dr = (destReds[j] & 0xff) - r; + dg = (destGreens[j] & 0xff) - g; + db = (destBlues[j] & 0xff) - b; + distance = dr * dr + dg * dg + db * db; + if (distance < minDistance) { + lastindex = j; + if (distance == 0) break; + minDistance = distance; + } + } + lastr = r; lastg = g; lastb = b; + } + if (ditherEnabled) { + // Floyd-Steinberg error diffusion, cont'd... + final int dxm1 = dx - 1, dxp1 = dx + 1; + int acc; + rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr; + rerr[dx] += acc += lrerr + lrerr; + rerr[dxm1] += acc + lrerr + lrerr; + gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr; + gerr[dx] += acc += lgerr + lgerr; + gerr[dxm1] += acc + lgerr + lgerr; + berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr; + berr[dx] += acc += lberr + lberr; + berr[dxm1] += acc + lberr + lberr; + } + + /*** WRITE NEXT PIXEL ***/ + switch (dtype) { + case TYPE_INDEX_8: + destData[dp] = (byte) lastindex; + break; + case TYPE_INDEX_4: + if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex); + else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4)); + break; + case TYPE_INDEX_2: { + final int shift = 6 - (dp & 3) * 2; + destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift)); + } break; + case TYPE_INDEX_1_MSB: { + final int shift = 7 - (dp & 7); + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift)); + } break; + case TYPE_INDEX_1_LSB: { + final int shift = dp & 7; + destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift)); + } break; + } + } + } +} + +/** + * Computes the required channel shift from a mask. + */ +static int getChannelShift(int mask) { + if (mask == 0) return 0; + int i; + for (i = 0; ((mask & 1) == 0) && (i < 32); ++i) { + mask >>>= 1; + } + return i; +} + +/** + * Computes the required channel width (depth) from a mask. + */ +static int getChannelWidth(int mask, int shift) { + if (mask == 0) return 0; + int i; + mask >>>= shift; + for (i = shift; ((mask & 1) != 0) && (i < 32); ++i) { + mask >>>= 1; + } + return i - shift; +} + +/** + * Extracts a field from packed RGB data given a mask for that field. + */ +static byte getChannelField(int data, int mask) { + final int shift = getChannelShift(mask); + return ANY_TO_EIGHT[getChannelWidth(mask, shift)][(data & mask) >>> shift]; +} + +/** + * Creates an ImageData containing one band's worth of a gradient filled + * block. If <code>vertical</code> is true, the band must be tiled + * horizontally to fill a region, otherwise it must be tiled vertically. + * + * @param width the width of the region to be filled + * @param height the height of the region to be filled + * @param vertical if true sweeps from top to bottom, else + * sweeps from left to right + * @param fromRGB the color to start with + * @param toRGB the color to end with + * @param redBits the number of significant red bits, 0 for palette modes + * @param greenBits the number of significant green bits, 0 for palette modes + * @param blueBits the number of significant blue bits, 0 for palette modes + * @return the new ImageData + */ +static ImageData createGradientBand( + int width, int height, boolean vertical, + RGB fromRGB, RGB toRGB, + int redBits, int greenBits, int blueBits) { + /* Gradients are drawn as tiled bands */ + final int bandWidth, bandHeight, bitmapDepth; + final byte[] bitmapData; + final PaletteData paletteData; + /* Select an algorithm depending on the depth of the screen */ + if (redBits != 0 && greenBits != 0 && blueBits != 0) { + paletteData = new PaletteData(0x0000ff00, 0x00ff0000, 0xff000000); + bitmapDepth = 32; + if (redBits >= 8 && greenBits >= 8 && blueBits >= 8) { + /* Precise color */ + final int steps; + if (vertical) { + bandWidth = 1; + bandHeight = height; + steps = bandHeight > 1 ? bandHeight - 1 : 1; + } else { + bandWidth = width; + bandHeight = 1; + steps = bandWidth > 1 ? bandWidth - 1 : 1; + } + final int bytesPerLine = bandWidth * 4; + bitmapData = new byte[bandHeight * bytesPerLine]; + buildPreciseGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine); + buildPreciseGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine); + buildPreciseGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine); + } else { + /* Dithered color */ + final int steps; + if (vertical) { + bandWidth = (width < 8) ? width : 8; + bandHeight = height; + steps = bandHeight > 1 ? bandHeight - 1 : 1; + } else { + bandWidth = width; + bandHeight = (height < 8) ? height : 8; + steps = bandWidth > 1 ? bandWidth - 1 : 1; + } + final int bytesPerLine = bandWidth * 4; + bitmapData = new byte[bandHeight * bytesPerLine]; + buildDitheredGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine, blueBits); + buildDitheredGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine, greenBits); + buildDitheredGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine, redBits); + } + } else { + /* Dithered two tone */ + paletteData = new PaletteData(new RGB[] { fromRGB, toRGB }); + bitmapDepth = 8; + final int blendi; + if (vertical) { + bandWidth = (width < 8) ? width : 8; + bandHeight = height; + blendi = (bandHeight > 1) ? 0x1040000 / (bandHeight - 1) + 1 : 1; + } else { + bandWidth = width; + bandHeight = (height < 8) ? height : 8; + blendi = (bandWidth > 1) ? 0x1040000 / (bandWidth - 1) + 1 : 1; + } + final int bytesPerLine = (bandWidth + 3) & -4; + bitmapData = new byte[bandHeight * bytesPerLine]; + if (vertical) { + for (int dy = 0, blend = 0, dp = 0; dy < bandHeight; + ++dy, blend += blendi, dp += bytesPerLine) { + for (int dx = 0; dx < bandWidth; ++dx) { + bitmapData[dp + dx] = (blend + DITHER_MATRIX[dy & 7][dx]) < + 0x1000000 ? (byte)0 : (byte)1; + } + } + } else { + for (int dx = 0, blend = 0; dx < bandWidth; ++dx, blend += blendi) { + for (int dy = 0, dptr = dx; dy < bandHeight; ++dy, dptr += bytesPerLine) { + bitmapData[dptr] = (blend + DITHER_MATRIX[dy][dx & 7]) < + 0x1000000 ? (byte)0 : (byte)1; + } + } + } + } + return new ImageData(bandWidth, bandHeight, bitmapDepth, paletteData, 4, bitmapData); +} + +/* + * Fill in gradated values for a color channel + */ +static final void buildPreciseGradientChannel(int from, int to, int steps, + int bandWidth, int bandHeight, boolean vertical, + byte[] bitmapData, int dp, int bytesPerLine) { + int val = from << 16; + final int inc = ((to << 16) - val) / steps + 1; + if (vertical) { + for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) { + bitmapData[dp] = (byte)(val >>> 16); + val += inc; + } + } else { + for (int dx = 0; dx < bandWidth; ++dx, dp += 4) { + bitmapData[dp] = (byte)(val >>> 16); + val += inc; + } + } +} + +/* + * Fill in dithered gradated values for a color channel + */ +static final void buildDitheredGradientChannel(int from, int to, int steps, + int bandWidth, int bandHeight, boolean vertical, + byte[] bitmapData, int dp, int bytesPerLine, int bits) { + final int mask = 0xff00 >>> bits; + int val = from << 16; + final int inc = ((to << 16) - val) / steps + 1; + if (vertical) { + for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) { + for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) { + final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits; + int temp = val + thresh; + if (temp > 0xffffff) bitmapData[dptr] = -1; + else bitmapData[dptr] = (byte)((temp >>> 16) & mask); + } + val += inc; + } + } else { + for (int dx = 0; dx < bandWidth; ++dx, dp += 4) { + for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) { + final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits; + int temp = val + thresh; + if (temp > 0xffffff) bitmapData[dptr] = -1; + else bitmapData[dptr] = (byte)((temp >>> 16) & mask); + } + val += inc; + } + } +} + +/** + * Renders a gradient onto a GC. + * <p> + * This is a GC helper. + * </p> + * + * @param gc the GC to render the gradient onto + * @param device the device the GC belongs to + * @param x the top-left x coordinate of the region to be filled + * @param y the top-left y coordinate of the region to be filled + * @param width the width of the region to be filled + * @param height the height of the region to be filled + * @param vertical if true sweeps from top to bottom, else + * sweeps from left to right + * @param fromRGB the color to start with + * @param toRGB the color to end with + * @param redBits the number of significant red bits, 0 for palette modes + * @param greenBits the number of significant green bits, 0 for palette modes + * @param blueBits the number of significant blue bits, 0 for palette modes + */ +static void fillGradientRectangle(GC gc, Device device, + int x, int y, int width, int height, boolean vertical, + RGB fromRGB, RGB toRGB, + int redBits, int greenBits, int blueBits) { + /* Create the bitmap and tile it */ + ImageData band = createGradientBand(width, height, vertical, + fromRGB, toRGB, redBits, greenBits, blueBits); + Image image = new Image(device, band); + if ((band.width == 1) || (band.height == 1)) { + gc.drawImage(image, 0, 0, band.width, band.height, x, y, width, height); + } else { + if (vertical) { + for (int dx = 0; dx < width; dx += band.width) { + int blitWidth = width - dx; + if (blitWidth > band.width) blitWidth = band.width; + gc.drawImage(image, 0, 0, blitWidth, band.height, dx + x, y, blitWidth, band.height); + } + } else { + for (int dy = 0; dy < height; dy += band.height) { + int blitHeight = height - dy; + if (blitHeight > band.height) blitHeight = band.height; + gc.drawImage(image, 0, 0, band.width, blitHeight, x, dy + y, band.width, blitHeight); + } + } + } + image.dispose(); +} + }
\ No newline at end of file |