javafx.scene.image.PixelFormat Maven / Gradle / Ivy
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.scene.image;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;
/**
* A {@code PixelFormat} object defines the layout of data for a pixel of
* a given format.
*
* @param the type of buffer that stores the pixel data. Only {@code ByteBuffer} and {@code IntBuffer} are used.
*
* @since JavaFX 2.2
*/
public abstract class PixelFormat {
/**
* An enum describing the in-array storage format of a single pixel
* managed by a {@link PixelFormat}.
*
* @since JavaFX 2.2
*/
public enum Type {
/**
* The pixels are stored in 32-bit integers with the premultiplied
* components stored in order, from MSb to LSb:
* alpha, red, green, blue.
*/
INT_ARGB_PRE,
/**
* The pixels are stored in 32-bit integers with the non-premultiplied
* components stored in order, from MSb to LSb:
* alpha, red, green, blue.
*/
INT_ARGB,
/**
* The pixels are stored in adjacent bytes with the premultiplied
* components stored in order of increasing index:
* blue, green, red, alpha.
*/
BYTE_BGRA_PRE,
/**
* The pixels are stored in adjacent bytes with the non-premultiplied
* components stored in order of increasing index:
* blue, green, red, alpha.
*/
BYTE_BGRA,
/**
* The opaque pixels are stored in adjacent bytes with the color
* components stored in order of increasing index:
* red, green, blue.
*/
BYTE_RGB,
/**
* The pixel colors are referenced by byte indices stored in the
* pixel array, with the byte interpreted as an unsigned index into
* a list of colors provided by the {@code PixelFormat} object.
*/
BYTE_INDEXED,
}
private Type type;
PixelFormat(Type type) {
this.type = type;
}
/**
* Returns a {@code WritablePixelFormat} instance describing a pixel
* layout with the pixels stored in 32-bit integers with the
* non-premultiplied components stored in order, from MSb to LSb:
* alpha, red, green, blue.
*
* Pixels in this format can be decoded using the following sample code:
*
{@code
* int pixel = array[rowstart + x];
*
* int alpha = ((pixel >> 24) & 0xff);
* int red = ((pixel >> 16) & 0xff);
* int green = ((pixel >> 8) & 0xff);
* int blue = ((pixel >> ) & 0xff);
* }
*
* @return a {@code WritabelPixelFormat} describing the
* indicated pixel format
*/
public static WritablePixelFormat getIntArgbInstance() {
return WritablePixelFormat.IntArgb.INSTANCE;
}
/**
* Returns a {@code WritablePixelFormat} instance describing a pixel
* layout with the pixels stored in 32-bit integers with the
* premultiplied components stored in order, from MSb to LSb:
* alpha, red, green, blue.
*
* Pixels in this format can be decoded using the following sample code:
*
{@code
* int pixel = array[rowstart + x];
*
* int alpha = ((pixel >> 24) & 0xff);
* int red = ((pixel >> 16) & 0xff);
* int green = ((pixel >> 8) & 0xff);
* int blue = ((pixel >> ) & 0xff);
* }
*
* @return a {@code WritabelPixelFormat} describing the
* indicated pixel format
*/
public static WritablePixelFormat getIntArgbPreInstance() {
return WritablePixelFormat.IntArgbPre.INSTANCE;
}
/**
* Returns a {@code WritablePixelFormat} instance describing a pixel
* layout with the pixels stored in adjacent bytes with the
* non-premultiplied components stored in order of increasing index:
* blue, green, red, alpha.
*
* Pixels in this format can be decoded using the following sample code:
*
{@code
* int i = rowstart + x * 4;
*
* int blue = (array[i+0] & 0xff);
* int green = (array[i+1] & 0xff);
* int red = (array[i+2] & 0xff);
* int alpha = (array[i+3] & 0xff);
* }
*
* @return a {@code WritablePixelFormat} describing the
* indicated pixel format
*/
public static WritablePixelFormat getByteBgraInstance() {
return WritablePixelFormat.ByteBgra.INSTANCE;
}
/**
* Returns a {@code WritablePixelFormat} instance describing a pixel
* layout with the pixels stored in adjacent bytes with the
* premultiplied components stored in order of increasing index:
* blue, green, red, alpha.
*
* Pixels in this format can be decoded using the following sample code:
*
{@code
* int i = rowstart + x * 4;
*
* int blue = (array[i+0] & 0xff);
* int green = (array[i+1] & 0xff);
* int red = (array[i+2] & 0xff);
* int alpha = (array[i+3] & 0xff);
* }
*
* @return a {@code WritablePixelFormat} describing the
* indicated pixel format
*/
public static WritablePixelFormat getByteBgraPreInstance() {
return WritablePixelFormat.ByteBgraPre.INSTANCE;
}
/**
* Returns a {@code PixelFormat} instance describing a pixel
* layout with the pixels stored in adjacent bytes with the
* color components stored in order of increasing index:
* red, green, blue.
*
* Pixels in this format can be decoded using the following sample code:
*
{@code
* int i = rowstart + x * 3;
*
* int red = (array[i+0] & 0xff);
* int green = (array[i+1] & 0xff);
* int blue = (array[i+2] & 0xff);
* }
*
* @return a {@code PixelFormat} describing the
* indicated pixel format
*/
public static PixelFormat getByteRgbInstance() {
return ByteRgb.instance;
}
/**
* Creates a {@code PixelFormat} instance describing a pixel layout
* with the pixels stored as single bytes representing an index
* into the specified lookup table of premultiplied color
* values in the {@link Type#INT_ARGB_PRE INT_ARGB_PRE} format.
*
* Pixels in this format can be decoded using the following sample code:
*
{@code
* int pixel = array[rowstart + x] & 0xff;
* int argb = colors[pixel];
*
* int alpha = ((argb >> 24) & 0xff);
* int red = ((argb >> 16) & 0xff);
* int green = ((argb >> 8) & 0xff);
* int blue = ((argb ) & 0xff);
* }
*
* @param colors an {@code int[]} array of 32-bit color values in
* the {@link Type#INT_ARGB_PRE INT_ARGB_PRE} format
* @return a {@code PixelFormat} describing the indicated
* pixel format with the specified list of premultiplied colors
*/
public static PixelFormat
createByteIndexedPremultipliedInstance(int colors[])
{
return IndexedPixelFormat.createByte(colors, true);
}
/**
* Creates a {@code PixelFormat} instance describing a pixel layout
* with the pixels stored as single bytes representing an index
* into the specified lookup table of non-premultiplied color
* values in the {@link Type#INT_ARGB INT_ARGB} format.
*
* Pixels in this format can be decoded using the following sample code:
*
{@code
* int pixel = array[rowstart + x] & 0xff;
* int argb = colors[pixel];
*
* int alpha = ((argb >> 24) & 0xff);
* int red = ((argb >> 16) & 0xff);
* int green = ((argb >> 8) & 0xff);
* int blue = ((argb ) & 0xff);
* }
*
* @param colors an {@code int[]} array of 32-bit color values in
* the {@link Type#INT_ARGB INT_ARGB} format
* @return a {@code PixelFormat} describing the indicated
* pixel format with the specified list of non-premultiplied colors
*/
public static PixelFormat
createByteIndexedInstance(int colors[])
{
return IndexedPixelFormat.createByte(colors, false);
}
/**
* Returns the enum representing the storage format of the pixels
* managed by this {@code PixelFormat} object.
*
* @return the {@code Type} enum of the pixels
*/
public Type getType() {
return type;
}
/**
* Returns true iff this {@code PixelFormat} object can convert
* color information into a pixel representation.
*
* @return true iff this {@code PixelFormat} can convert colors to
* pixel data
*/
public abstract boolean isWritable();
/**
* Returns true iff the color components decoded (or encoded) by this
* format are pre-multiplied by the alpha component for more efficient
* blending calculations.
*
* @return true iff the managed color components are premultiplied
* by alpha
*/
public abstract boolean isPremultiplied();
static int NonPretoPre(int nonpre) {
int a = nonpre >>> 24;
if (a == 0xff) return nonpre;
if (a == 0x00) return 0;
int r = (nonpre >> 16) & 0xff;
int g = (nonpre >> 8) & 0xff;
int b = (nonpre ) & 0xff;
r = (r * a + 127) / 0xff;
g = (g * a + 127) / 0xff;
b = (b * a + 127) / 0xff;
return (a << 24) | (r << 16) | (g << 8) | b;
}
static int PretoNonPre(int pre) {
int a = pre >>> 24;
if (a == 0xff || a == 0x00) return pre;
int r = (pre >> 16) & 0xff;
int g = (pre >> 8) & 0xff;
int b = (pre ) & 0xff;
int halfa = a >> 1;
r = (r >= a) ? 0xff : (r * 0xff + halfa) / a;
g = (g >= a) ? 0xff : (g * 0xff + halfa) / a;
b = (b >= a) ? 0xff : (b * 0xff + halfa) / a;
return (a << 24) | (r << 16) | (g << 8) | b;
}
/**
* Reads pixel data from the buffer at the specified coordinates and
* converts it to a 32-bit integer representation of the color in the
* {@link Type#INT_ARGB INT_ARGB} format.
* The 32-bit integer will contain the 4 color components in separate
* 8-bit fields in ARGB order from the most significant byte to the least
* significant byte.
* The buffer should be positioned to the start of the pixel data such
* that {@code buf.get(0)} would return the pixel information for the
* pixel at coordinates {@code (0, 0)}.
* The {@code scanlineStride} parameter defines the distance from the pixel
* data at the start of one row to the pixel data at the start of the
* immediately following row at the next higher Y coordinate. Usually,
* {@code scanlineStride} is the same as the width of the image multiplied
* by the number of data elements per pixel (1 for the case of the
* integer and indexed formats, or 3 or 4 in the case of the byte
* formats), but some images may have further padding between rows for
* alignment or other purposes.
*
* The color components can be extracted from the returned integer using
* the following sample code:
*
* int alpha = ((retval >> 24) & 0xff);
* int red = ((retval >> 16) & 0xff);
* int green = ((retval >> 8) & 0xff);
* int blue = ((retval ) & 0xff);
*
*
* @param buf the buffer of pixel data
* @param x the X coordinate of the pixel to be read
* @param y the Y coordinate of the pixel to be read
* @param scanlineStride the number of buffer elements between the
* start of adjacent pixel rows in the buffer
* @return a 32-bit value with the color of the pixel in a format
* similar to the {@link Type#INT_ARGB INT_ARGB} pixel format
*/
public abstract int getArgb(T buf, int x, int y, int scanlineStride);
static class ByteRgb extends PixelFormat {
static final ByteRgb instance = new ByteRgb();
private ByteRgb() {
super(Type.BYTE_RGB);
}
@Override
public boolean isWritable() {
return true;
}
@Override
public boolean isPremultiplied() {
return false;
}
@Override
public int getArgb(ByteBuffer buf, int x, int y, int scanlineStride) {
int index = y * scanlineStride + x * 3;
int r = buf.get(index ) & 0xff;
int g = buf.get(index + 1) & 0xff;
int b = buf.get(index + 2) & 0xff;
return (0xff << 24) | (r << 16) | (g << 8) | b;
}
}
static class IndexedPixelFormat extends PixelFormat {
int precolors[];
int nonprecolors[];
boolean premult;
static PixelFormat createByte(int colors[], boolean premult) {
return new IndexedPixelFormat(Type.BYTE_INDEXED, premult,
Arrays.copyOf(colors, 256));
}
private IndexedPixelFormat(Type type, boolean premult, int colors[]) {
super(type);
if (premult) {
this.precolors = colors;
} else {
this.nonprecolors = colors;
}
this.premult = premult;
}
@Override
public boolean isWritable() {
return false;
}
@Override
public boolean isPremultiplied() {
return premult;
}
int[] getPreColors() {
if (precolors == null) {
int colors[] = new int[nonprecolors.length];
for (int i = 0; i < colors.length; i++) {
colors[i] = NonPretoPre(nonprecolors[i]);
}
this.precolors = colors;
}
return precolors;
}
int[] getNonPreColors() {
if (nonprecolors == null) {
int colors[] = new int[precolors.length];
for (int i = 0; i < colors.length; i++) {
colors[i] = PretoNonPre(precolors[i]);
}
this.nonprecolors = colors;
}
return nonprecolors;
}
@Override
public int getArgb(ByteBuffer buf, int x, int y, int scanlineStride) {
return getNonPreColors()[buf.get(y * scanlineStride + x) & 0xff];
}
}
}