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 | 3595 |
1 files changed, 0 insertions, 3595 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 deleted file mode 100755 index da358c2679..0000000000 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java +++ /dev/null @@ -1,3595 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.swt.graphics; - - -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 necessarily - * 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; - - /** - * An 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; - - /** - * An 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 from which the image was read. - * - * It is 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. - * - * It is 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, or if the depth is not - * one of 1, 2, 4, 8, 16, 24 or 32</li> - * <li>ERROR_NULL_ARGUMENT - if the palette is null</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, or if the depth is not - * one of 1, 2, 4, 8, 16, 24 or 32</li> - * <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li> - * <li>ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero</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. Application - * code is still responsible for closing the input stream. - * <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><p> - * This constructor may be used to load a resource as follows: - * </p> - * <pre> - * static ImageData loadImageData (Class clazz, String string) { - * InputStream stream = clazz.getResourceAsStream (string); - * if (stream == null) return null; - * ImageData imageData = null; - * try { - * imageData = new ImageData (stream); - * } catch (SWTException ex) { - * } finally { - * try { - * stream.close (); - * } catch (IOException ex) {} - * } - * return imageData; - * } - * </pre> - * - * @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_IO - if an IO error occurs while reading from the stream</li> - * <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data</li> - * <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li> - * </ul> - * - * @see ImageLoader#load(InputStream) - */ -public ImageData(InputStream stream) { - ImageData[] data = ImageDataLoader.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_IO - if an IO error occurs while reading from the file</li> - * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li> - * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li> - * </ul> - */ -public ImageData(String filename) { - ImageData[] data = ImageDataLoader.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); - } - if (scanlinePad == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO); - - 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> - */ -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(), - 2, 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; - switch (depth) { - case 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); - case 24: - index = (y * bytesPerLine) + (x * 3); - return ((data[index] & 0xFF) << 16) + ((data[index+1] & 0xFF) << 8) + - (data[index+2] & 0xFF); - case 16: - index = (y * bytesPerLine) + (x * 2); - return ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF); - case 8: - index = (y * bytesPerLine) + x ; - return data[index] & 0xFF; - case 4: - index = (y * bytesPerLine) + (x >> 1); - theByte = data[index] & 0xFF; - if ((x & 0x1) == 0) { - return theByte >> 4; - } else { - return theByte & 0x0F; - } - case 2: - index = (y * bytesPerLine) + (x >> 2); - theByte = data[index] & 0xFF; - int offset = 3 - (x % 4); - mask = 3 << (offset * 2); - return (theByte & mask) >> (offset * 2); - case 1: - index = (y * bytesPerLine) + (x >> 3); - theByte = data[index] & 0xFF; - mask = 1 << (7 - (x & 0x7)); - if ((theByte & mask) == 0) { - return 0; - } else { - return 1; - } - } - 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; - switch (depth) { - case 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; - case 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; - case 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; - case 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; - } - 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; - switch (depth) { - case 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; - case 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; - case 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; - case 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; - case 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; - case 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; - case 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; - } - 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. If the - * receiver has no transparency or is not an icon, returns - * an opaque mask. - * - * @return the transparency mask - */ -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, which will be one of - * <code>SWT.TRANSPARENCY_NONE</code>, <code>SWT.TRANSPARENCY_MASK</code>, - * <code>SWT.TRANSPARENCY_PIXEL</code> or <code>SWT.TRANSPARENCY_ALPHA</code>. - * - * @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; - switch (depth) { - case 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; - case 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; - case 16: - index = (y * bytesPerLine) + (x * 2); - data[index + 1] = (byte)((pixelValue >> 8) & 0xFF); - data[index] = (byte)(pixelValue & 0xFF); - return; - case 8: - index = (y * bytesPerLine) + x ; - data[index] = (byte)(pixelValue & 0xFF); - return; - case 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; - case 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; - case 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; - } - 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; - switch (depth) { - case 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; - case 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; - case 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; - case 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; - } - 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; - switch (depth) { - case 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; - case 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; - case 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; - case 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; - case 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; - case 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; - case 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; - } - 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; -} - -static final ImageData convertMask(ImageData mask) { - if (mask.depth == 1) return mask; - PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)}); - ImageData newMask = new ImageData(mask.width, mask.height, 1, palette); - /* Find index of black in mask palette */ - int blackIndex = 0; - RGB[] rgbs = mask.getRGBs(); - if (rgbs != null) { - while (blackIndex < rgbs.length) { - if (rgbs[blackIndex].equals(palette.colors[0])) break; - blackIndex++; - } - } - int[] pixels = new int[mask.width]; - for (int y = 0; y < mask.height; y++) { - mask.getPixels(0, y, mask.width, pixels, 0); - for (int i = 0; i < pixels.length; i++) { - if (pixels[i] == blackIndex) { - pixels[i] = 0; - } else { - pixels[i] = 1; - } - } - newMask.setPixels(0, y, mask.width, pixels, 0); - } - return newMask; -} - -static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) { - if (pad == newPad) return data; - int stride = (width * depth + 7) / 8; - int bpl = (stride + (pad - 1)) / pad * pad; - int newBpl = (stride + (newPad - 1)) / newPad * newPad; - byte[] newData = new byte[height * newBpl]; - int srcIndex = 0, destIndex = 0; - for (int y = 0; y < height; y++) { - System.arraycopy(data, srcIndex, newData, destIndex, stride); - srcIndex += bpl; - destIndex += newBpl; - } - return newData; -} - -/** - * 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(); -} - -} |