All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.swt.graphics.ImageData Maven / Gradle / Ivy

Go to download

The osx x86_64 swt jar as available in the Eclipse 4.6 (Neon) release for OSX. It is suitable for use with jface and other dependencies available from maven central in the org.eclipse.scout.sdk.deps group. The sources is copied from swt-4.6-cocoa-macosx-x86_64.zip from http://download.eclipse.org/eclipse/downloads/drops4/R-4.6-201606061100/ and javadoc is generated from sources.

The newest version!
/*******************************************************************************
 * Copyright (c) 2000, 2016 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.*;

/**
 * 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
 * Image.
 * 

* Note that the public fields x, y, * disposalMethod and delayTime are * typically only used when the image is in a set of images used * for animation. *

* * @see Image * @see ImageLoader * @see ImageData snippets * @see SWT Example: ImageAnalyzer * @see Sample code and further information */ public final class ImageData implements Cloneable { /** * 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. *

* 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. *

* If one scanline of the image is not a multiple of * this number, it will be padded with zeros until it is. *

*/ public int scanlinePad; /** * The number of bytes per scanline. *

* This is a multiple of the scanline padding. *

*/ public int bytesPerLine; /** * The pixel data of the image. *

* 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. *

*/ public byte[] data; /** * The color table for the image. */ public PaletteData palette; /** * The transparent pixel. *

* Pixels with this value are transparent. *

* The default is -1 which means 'no transparent pixel'. *

*/ public int transparentPixel; /** * An icon-specific field containing the data from the icon mask. *

* 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'. *

* The default is null which means 'no transparency mask'. *

*/ public byte[] maskData; /** * An icon-specific field containing the scanline pad of the mask. *

* If one scanline of the transparency mask is not a * multiple of this number, it will be padded with zeros until * it is. *

*/ public int maskPad; /** * The alpha data of the image. *

* Every pixel can have an alpha blending value that * varies from 0, meaning fully transparent, to 255 meaning * fully opaque. The number of bytes per scanline is * 'width'. *

*/ public byte[] alphaData; /** * The global alpha value to be used for every pixel. *

* If this value is set, the alphaData field * is ignored and when the image is rendered each pixel * will be blended with the background an amount * proportional to this value. *

* The default is -1 which means 'no global alpha value' *

*/ public int alpha; /** * The type of file from which the image was read. * * It is expressed as one of the following values: *
*
IMAGE_BMP
*
Windows BMP file format, no compression
*
IMAGE_BMP_RLE
*
Windows BMP file format, RLE compression if appropriate
*
IMAGE_GIF
*
GIF file format
*
IMAGE_ICO
*
Windows ICO file format
*
IMAGE_JPEG
*
JPEG file format
*
IMAGE_PNG
*
PNG file format
*
*/ 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: *
*
DM_UNSPECIFIED
*
disposal method not specified
*
DM_FILL_NONE
*
do nothing - leave the image in place
*
DM_FILL_BACKGROUND
*
fill with the background color
*
DM_FILL_PREVIOUS
*
restore the previous picture
*
* (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
    *
  • ERROR_INVALID_ARGUMENT - if the width or height is zero or negative, or if the depth is not * one of 1, 2, 4, 8, 16, 24 or 32
  • *
  • ERROR_NULL_ARGUMENT - if the palette is null
  • *
*/ 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
    *
  • ERROR_INVALID_ARGUMENT - if the width or height is zero or negative, or if the depth is not * one of 1, 2, 4, 8, 16, 24 or 32, or the data array is too small to contain the image data
  • *
  • ERROR_NULL_ARGUMENT - if the palette or data is null
  • *
  • ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero
  • *
*/ 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 ImageData 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. *

* 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 * ImageLoader.load(). *

* This constructor may be used to load a resource as follows: *

*
 *     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;
 *     }
 * 
* * @param stream the input stream to load the image from (must not be null) * * @exception IllegalArgumentException
    *
  • ERROR_NULL_ARGUMENT - if the stream is null
  • *
* @exception SWTException
    *
  • ERROR_IO - if an IO error occurs while reading from the stream
  • *
  • ERROR_INVALID_IMAGE - if the image stream contains invalid data
  • *
  • ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format
  • *
* * @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 ImageData 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. *

* 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 * ImageLoader.load(). *

* * @param filename the name of the file to load the image from (must not be null) * * @exception IllegalArgumentException
    *
  • ERROR_NULL_ARGUMENT - if the file name is null
  • *
* @exception SWTException
    *
  • ERROR_IO - if an IO error occurs while reading from the file
  • *
  • ERROR_INVALID_IMAGE - if the image file contains invalid data
  • *
  • ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format
  • *
*/ 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. *

* This method is for internal use, and is not described further. *

*/ 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; /* * When the image is being loaded from a PNG, we need to use the theoretical minimum * number of bytes per line to check whether there is enough data, because the actual * number of bytes per line is calculated based on the given depth, which may be larger * than the actual depth of the PNG. */ int minBytesPerLine = type == SWT.IMAGE_PNG ? ((((width + 7) / 8) + 3) / 4) * 4 : bytesPerLine; if (data != null && data.length < minBytesPerLine * height) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } 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. *

* This method is for internal use, and is not described further. *

*/ 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. *

* IMPORTANT: This method is not part of the public * API for ImageData. 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. *

*

* This method is for internal use, and is not described further. *

* * @noreference This method is not intended to be referenced by clients. */ 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 copies of * the values in the slots of the receiver. That is, the * returned object is a deep copy of the receiver. * * @return a copy of the receiver. */ @Override 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 x in * scanline y in the receiver's alpha data. * The alpha value is between 0 (transparent) and * 255 (opaque). * * @param x the x coordinate 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
    *
  • ERROR_INVALID_ARGUMENT - if either argument is out of range
  • *
*/ 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 getWidth alpha values starting at offset * x in scanline y in the receiver's alpha * data starting at startIndex. The alpha values * are unsigned, between (byte)0 (transparent) and * (byte)255 (opaque). * * @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
    *
  • ERROR_NULL_ARGUMENT - if pixels is null
  • *
  • ERROR_INVALID_ARGUMENT - if x or y is out of bounds
  • *
  • ERROR_INVALID_ARGUMENT - if getWidth is negative
  • *
*/ 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 x in * scanline y 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
    *
  • ERROR_INVALID_ARGUMENT - if either argument is out of bounds
  • *
* @exception SWTException
    *
  • ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32
  • *
*/ 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 getWidth pixel values starting at offset * x in scanline y in the receiver's * data starting at startIndex. * * @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
    *
  • ERROR_NULL_ARGUMENT - if pixels is null
  • *
  • ERROR_INVALID_ARGUMENT - if x or y is out of bounds
  • *
  • ERROR_INVALID_ARGUMENT - if getWidth is negative
  • *
* @exception SWTException
    *
  • 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.)
  • *
*/ 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 getWidth pixel values starting at offset * x in scanline y in the receiver's * data starting at startIndex. * * @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
    *
  • ERROR_NULL_ARGUMENT - if pixels is null
  • *
  • ERROR_INVALID_ARGUMENT - if x or y is out of bounds
  • *
  • ERROR_INVALID_ARGUMENT - if getWidth is negative
  • *
* @exception SWTException
    *
  • ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4, 8, 16, 24 or 32
  • *
*/ 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 RGBs 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 ImageData 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 * SWT.TRANSPARENCY_NONE, SWT.TRANSPARENCY_MASK, * SWT.TRANSPARENCY_PIXEL or SWT.TRANSPARENCY_ALPHA. * * @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 x in * scanline y in the receiver's alpha data. * The alpha value must be between 0 (transparent) * and 255 (opaque). * * @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
    *
  • ERROR_INVALID_ARGUMENT - if x or y is out of bounds
  • *
*/ 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 x in * scanline y in the receiver's alpha data to the * values from the array alphas starting at * startIndex. The alpha values must be between * (byte)0 (transparent) and (byte)255 (opaque) * * @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
    *
  • ERROR_NULL_ARGUMENT - if pixels is null
  • *
  • ERROR_INVALID_ARGUMENT - if x or y is out of bounds
  • *
  • ERROR_INVALID_ARGUMENT - if putWidth is negative
  • *
*/ 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 x in * scanline y 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
    *
  • ERROR_INVALID_ARGUMENT - if x or y is out of bounds
  • *
* @exception SWTException
    *
  • ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32
  • *
*/ 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 x in * scanline y in the receiver's data to the * values from the array pixels starting at * startIndex. * * @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
    *
  • ERROR_NULL_ARGUMENT - if pixels is null
  • *
  • ERROR_INVALID_ARGUMENT - if x or y is out of bounds
  • *
  • ERROR_INVALID_ARGUMENT - if putWidth is negative
  • *
* @exception SWTException
    *
  • ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8 * (For higher depths, use the int[] version of this method.)
  • *
*/ 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 x in * scanline y in the receiver's data to the * values from the array pixels starting at * startIndex. * * @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
    *
  • ERROR_NULL_ARGUMENT - if pixels is null
  • *
  • ERROR_INVALID_ARGUMENT - if x or y is out of bounds
  • *
  • ERROR_INVALID_ARGUMENT - if putWidth is negative
  • *
* @exception SWTException
    *
  • ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32
  • *
*/ 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. *

* 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. *

* * @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 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; } /*Fast 32 to 32 blit */ if (alphaMode == 0x10000 && stype == TYPE_GENERIC_32_MSB && dtype == TYPE_GENERIC_32_MSB) { if (srcRedMask == 0xFF00 && srcGreenMask == 0xff0000 && srcBlueMask == 0xff000000 && destRedMask == 0xFF0000 && destGreenMask == 0xff00 && destBlueMask == 0xff) { 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 + 3]; destData[dp + 1] = srcData[sp + 2]; destData[dp + 2] = srcData[sp + 1]; destData[dp + 3] = srcData[sp]; sp += (sfx >>> 16) * 4; } } return; } } /*Fast 24 to 32 blit */ if (alphaMode == 0x10000 && stype == TYPE_GENERIC_24 && dtype == TYPE_GENERIC_32_MSB) { if (srcRedMask == 0xFF && srcGreenMask == 0xff00 && srcBlueMask == 0xff0000 && destRedMask == 0xFF0000 && destGreenMask == 0xff00 && destBlueMask == 0xff) { 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] = 0; destData[dp + 1] = srcData[sp + 2]; destData[dp + 2] = srcData[sp + 1]; destData[dp + 3] = srcData[sp]; sp += (sfx >>> 16) * 3; } } 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. *

* Note: The source and destination red, green, and blue * arrays may be null if no alpha blending or dither is to be * performed. *

* * @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. *

* Note: The source and destination masks and palettes must * always be fully specified. *

* * @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; /*** Fast blit (straight copy) ***/ if (srcX == 0 && srcY == 0 && destX == 0 && destY == 0 && destWidth == srcWidth && destHeight == srcHeight) { if (destDepth == 24 && srcDepth == 8 && (op & BLIT_ALPHA) == 0 && destRedMask == 0xFF0000 && destGreenMask == 0xFF00 && destBlueMask == 0xFF) { for (int y = 0, sp = 0, dp = 0, spad = srcStride - srcWidth, dpad = destStride - (destWidth * 3); y < destHeight; y++, sp += spad, dp += dpad) { for (int x = 0; x < destWidth; x++) { int index = srcData[sp++] & 0xff; destData[dp++] = srcReds[index]; destData[dp++] = srcGreens[index]; destData[dp++] = srcBlues[index]; } } return; } if (destDepth == 32 && destOrder == MSB_FIRST && srcDepth == 8 && (op & BLIT_ALPHA) == 0 && destRedMask == 0xFF0000 && destGreenMask == 0xFF00 && destBlueMask == 0xFF) { for (int y = 0, sp = 0, dp = 0, spad = srcStride - srcWidth, dpad = destStride - (destWidth * 4); y < destHeight; y++, sp += spad, dp += dpad) { for (int x = 0; x < destWidth; x++) { int index = srcData[sp++] & 0xff; dp++; destData[dp++] = srcReds[index]; destData[dp++] = srcGreens[index]; destData[dp++] = srcBlues[index]; } } 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. *

* Note: The source and destination masks and palettes must * always be fully specified. *

* * @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 vertical 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. *

* This is a GC helper. *

* * @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, DPIUtil.autoScaleDown(band.width), DPIUtil.autoScaleDown(band.height), DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(y), DPIUtil.autoScaleDown(width), DPIUtil.autoScaleDown(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, DPIUtil.autoScaleDown(blitWidth), DPIUtil.autoScaleDown(band.height), DPIUtil.autoScaleDown(dx + x), DPIUtil.autoScaleDown(y), DPIUtil.autoScaleDown(blitWidth), DPIUtil.autoScaleDown(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, DPIUtil.autoScaleDown(band.width), DPIUtil.autoScaleDown(blitHeight), DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(dy + y), DPIUtil.autoScaleDown(band.width), DPIUtil.autoScaleDown(blitHeight)); } } } image.dispose(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy