com.jogamp.nativewindow.util.PixelFormatUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jogl-all-android Show documentation
Show all versions of jogl-all-android Show documentation
Java™ Binding for the OpenGL® API (Android)
The newest version!
/**
* Copyright (c) 2014 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
package com.jogamp.nativewindow.util;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.util.Bitstream;
/**
* Pixel Rectangle Utilities.
*
* All conversion methods are endian independent.
*
*/
public class PixelFormatUtil {
private static boolean DEBUG = false;
public static class ComponentMap {
/**
* Contains the source index for each destination index,
* length is {@link Composition#componentCount()} of destination.
*/
final int[] dst2src;
/**
* Contains the destination index for each source index,
* length is {@link Composition#componentCount()} of source.
*/
final int[] src2dst;
/**
* Contains the source index of RGBA components.
*/
final int[] srcRGBA;
final boolean hasSrcRGB;
public ComponentMap(final PixelFormat.Composition src, final PixelFormat.Composition dst) {
final int sCompCount = src.componentCount();
final int dCompCount = dst.componentCount();
final PixelFormat.CType[] sCompOrder = src.componentOrder();
final PixelFormat.CType[] dCompOrder = dst.componentOrder();
dst2src = new int[dCompCount];
for(int dIdx=0; dIdx= 0 && pool[i] != s) { i--; }
if( 0 > i && mapRGB2Y && 1 == pool.length && pool[0] == PixelFormat.CType.Y &&
( PixelFormat.CType.R == s ||
PixelFormat.CType.G == s ||
PixelFormat.CType.B == s ) )
{
// Special case, fallback for RGB mapping -> LUMINANCE/Y
return 0;
} else {
return i;
}
}
/**
* Returns shifted bytes from the given {@code data} at given {@code offset}
* of maximal 4 {@code bytesPerPixel}.
* @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
* @param data byte buffer covering complete pixel at position {@code offset}
* @param offset byte offset of pixel {@code data} start
* @return the shifted 32bit integer value of the pixel
*/
public static int getShiftedI32(final int bytesPerPixel, final byte[] data, final int offset) {
if( bytesPerPixel <= 4 ) {
int shiftedI32 = 0;
for(int i=0; i 4");
}
}
/**
* Returns shifted bytes from the given {@code data} at given {@code offset}
* of maximal 8 {@code bytesPerPixel}.
* @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
* @param data byte buffer covering complete pixel at position {@code offset}
* @param offset byte offset of pixel {@code data} start
* @return the shifted 64bit integer value of the pixel
*/
public static long getShiftedI64(final int bytesPerPixel, final byte[] data, final int offset) {
if( bytesPerPixel <= 8 ) {
long shiftedI64 = 0;
for(int i=0; i 8");
}
}
/**
* Returns shifted bytes from the given {@code data} at current position
* of maximal 4 {@code bytesPerPixel}.
* @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
* @param data byte buffer covering complete pixel at position {@code offset}
* @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged.
* Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes.
* @return the shifted 32bit integer value of the pixel
*/
public static int getShiftedI32(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) {
if( bytesPerPixel <= 4 ) {
int shiftedI32 = 0;
if( retainDataPos ) {
final int offset = data.position();
for(int i=0; i 4");
}
}
/**
* Returns shifted bytes from the given {@code data} at current position
* of maximal 8 {@code bytesPerPixel}.
* @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
* @param data byte buffer covering complete pixel at position {@code offset}
* @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged.
* Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes.
* @return the shifted 64bit integer value of the pixel
*/
public static long getShiftedI64(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) {
if( bytesPerPixel <= 8 ) {
long shiftedI64 = 0;
if( retainDataPos ) {
final int offset = data.position();
for(int i=0; i 8");
}
}
/**
* Returns the {@link PixelFormat} with reversed components of fmt
.
* If no reversed {@link PixelFormat} is available, returns fmt
.
*/
public static PixelFormat getReversed(final PixelFormat fmt) {
switch(fmt) {
case RGB565:
return PixelFormat.BGR565;
case BGR565:
return PixelFormat.RGB565;
case RGBA5551:
return PixelFormat.ABGR1555;
case ABGR1555:
return PixelFormat.RGBA5551;
case RGB888:
return PixelFormat.BGR888;
case BGR888:
return PixelFormat.RGB888;
case RGBA8888:
return PixelFormat.ABGR8888;
case ABGR8888:
return PixelFormat.RGBA8888;
case ARGB8888:
return PixelFormat.BGRA8888;
case BGRA8888:
return PixelFormat.ABGR8888;
default:
return fmt;
}
}
public static int convertToInt32(final PixelFormat dst_fmt, final byte r, final byte g, final byte b, final byte a) {
switch(dst_fmt) {
case LUMINANCE: {
final byte l = ( byte) ( ( ( ( 0xff & r ) + ( 0xff & g ) + ( 0xff & b ) ) / 3 ) * a );
return ( 0xff ) << 24 | ( 0xff & l ) << 16 | ( 0xff & l ) << 8 | ( 0xff & l );
}
case RGB888:
return ( 0xff ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r );
case BGR888:
return ( 0xff ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b );
case RGBA8888:
return ( 0xff & a ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r );
case ABGR8888:
return ( 0xff & r ) << 24 | ( 0xff & g ) << 16 | ( 0xff & b ) << 8 | ( 0xff & a );
case ARGB8888:
return ( 0xff & b ) << 24 | ( 0xff & g ) << 16 | ( 0xff & r ) << 8 | ( 0xff & a );
case BGRA8888:
return ( 0xff & a ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b );
default:
throw new InternalError("Unhandled format "+dst_fmt);
}
}
public static int convertToInt32(final PixelFormat dst_fmt, final PixelFormat src_fmt, final ByteBuffer src, int srcOff) {
final byte r, g, b, a;
switch(src_fmt) {
case LUMINANCE:
r = src.get(srcOff++); // R
g = r; // G
b = r; // B
a = (byte) 0xff; // A
break;
case RGB888:
r = src.get(srcOff++); // R
g = src.get(srcOff++); // G
b = src.get(srcOff++); // B
a = (byte) 0xff; // A
break;
case BGR888:
b = src.get(srcOff++); // B
g = src.get(srcOff++); // G
r = src.get(srcOff++); // R
a = (byte) 0xff; // A
break;
case RGBA8888:
r = src.get(srcOff++); // R
g = src.get(srcOff++); // G
b = src.get(srcOff++); // B
a = src.get(srcOff++); // A
break;
case ABGR8888:
a = src.get(srcOff++); // A
b = src.get(srcOff++); // B
g = src.get(srcOff++); // G
r = src.get(srcOff++); // R
break;
case ARGB8888:
a = src.get(srcOff++); // A
r = src.get(srcOff++); // R
g = src.get(srcOff++); // G
b = src.get(srcOff++); // B
break;
case BGRA8888:
b = src.get(srcOff++); // B
g = src.get(srcOff++); // G
r = src.get(srcOff++); // R
a = src.get(srcOff++); // A
break;
default:
throw new InternalError("Unhandled format "+src_fmt);
}
return convertToInt32(dst_fmt, r, g, b, a);
}
public static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final int src_pixel) {
final byte r, g, b, a;
switch(src_fmt) {
case LUMINANCE:
r = (byte) ( src_pixel ); // R
g = r; // G
b = r; // B
a = (byte) 0xff; // A
break;
case RGB888:
r = (byte) ( src_pixel ); // R
g = (byte) ( src_pixel >>> 8 ); // G
b = (byte) ( src_pixel >>> 16 ); // B
a = (byte) 0xff; // A
break;
case BGR888:
b = (byte) ( src_pixel ); // B
g = (byte) ( src_pixel >>> 8 ); // G
r = (byte) ( src_pixel >>> 16 ); // R
a = (byte) 0xff; // A
break;
case RGBA8888:
r = (byte) ( src_pixel ); // R
g = (byte) ( src_pixel >>> 8 ); // G
b = (byte) ( src_pixel >>> 16 ); // B
a = (byte) ( src_pixel >>> 24 ); // A
break;
case ABGR8888:
a = (byte) ( src_pixel ); // A
b = (byte) ( src_pixel >>> 8 ); // B
g = (byte) ( src_pixel >>> 16 ); // G
r = (byte) ( src_pixel >>> 24 ); // R
break;
case ARGB8888:
a = (byte) ( src_pixel ); // A
r = (byte) ( src_pixel >>> 8 ); // R
g = (byte) ( src_pixel >>> 16 ); // G
b = (byte) ( src_pixel >>> 24 ); // B
break;
case BGRA8888:
b = (byte) ( src_pixel ); // B
g = (byte) ( src_pixel >>> 8 ); // G
r = (byte) ( src_pixel >>> 16 ); // R
a = (byte) ( src_pixel >>> 24 ); // A
break;
default:
throw new InternalError("Unhandled format "+src_fmt);
}
return convertToInt32(dest_fmt, r, g, b, a);
}
public static PixelRectangle convert(final PixelRectangle src,
final PixelFormat destFmt, final int ddestStride, final boolean isGLOriented,
final boolean destIsDirect) {
final int width = src.getSize().getWidth();
final int height = src.getSize().getHeight();
final int bpp = destFmt.comp.bytesPerPixel();
final int destStride;
if( 0 != ddestStride ) {
destStride = ddestStride;
} else {
destStride = bpp * width;
}
final int capacity = destStride*height;
final ByteBuffer destBB = destIsDirect ? Buffers.newDirectByteBuffer(capacity) : ByteBuffer.allocate(capacity).order(src.getPixels().order());
convert(src, destBB, destFmt, isGLOriented, destStride);
return new PixelRectangle.GenericPixelRect(destFmt, src.getSize(), destStride, isGLOriented, destBB);
}
/**
* @param src
* @param dst_bb {@link ByteBuffer} sink
* @param dst_fmt destination {@link PixelFormat}
* @param dst_glOriented if true, the source memory is laid out in OpenGL's coordinate system, origin at bottom left,
* otherwise origin at top left.
* @param dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next.
* Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width
* or {@code zero} for default stride.
*
* @throws IllegalStateException
* @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid
*/
public static void convert(final PixelRectangle src,
final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, final int dst_lineStride)
throws IllegalStateException
{
convert(src.getSize().getWidth(), src.getSize().getHeight(),
src.getPixels(), src.getPixelformat(), src.isGLOriented(), src.getStride(),
dst_bb, dst_fmt, dst_glOriented, dst_lineStride);
}
/**
* @param width width of the to be converted pixel rectangle
* @param height height of the to be converted pixel rectangle
* @param src_bb {@link ByteBuffer} source
* @param src_fmt source {@link PixelFormat}
* @param src_glOriented if true, the source memory is laid out in OpenGL's coordinate system, origin at bottom left,
* otherwise origin at top left.
* @param src_lineStride line stride in byte-size for source, i.e. byte count from one line to the next.
* Must be >= {@link PixelFormat.Composition#bytesPerPixel() src_fmt.comp.bytesPerPixel()} * width
* or {@code zero} for default stride.
* @param dst_bb {@link ByteBuffer} sink
* @param dst_fmt destination {@link PixelFormat}
* @param dst_glOriented if true, the source memory is laid out in OpenGL's coordinate system, origin at bottom left,
* otherwise origin at top left.
* @param dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next.
* Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width
* or {@code zero} for default stride.
*
* @throws IllegalStateException
* @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid
*/
public static void convert(final int width, final int height,
final ByteBuffer src_bb, final PixelFormat src_fmt, final boolean src_glOriented, int src_lineStride,
final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, int dst_lineStride
) throws IllegalStateException, IllegalArgumentException {
final PixelFormat.Composition src_comp = src_fmt.comp;
final PixelFormat.Composition dst_comp = dst_fmt.comp;
final int src_bpp = src_comp.bytesPerPixel();
final int dst_bpp = dst_comp.bytesPerPixel();
if( 0 != src_lineStride ) {
if( src_lineStride < src_bpp * width ) {
throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d",
"source", src_lineStride, src_bpp, width));
}
} else {
src_lineStride = src_bpp * width;
}
if( 0 != dst_lineStride ) {
if( dst_lineStride < dst_bpp * width ) {
throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d",
"destination", dst_lineStride, dst_bpp, width));
}
} else {
dst_lineStride = dst_bpp * width;
}
// final int src_comp_bitStride = src_comp.bitStride();
final int dst_comp_bitStride = dst_comp.bitStride();
final boolean vert_flip = src_glOriented != dst_glOriented;
final boolean fast_copy = src_comp.equals(dst_comp) && 0 == dst_comp_bitStride%8;
if( DEBUG ) {
System.err.println("XXX: size "+width+"x"+height+", fast_copy "+fast_copy);
System.err.println("XXX: SRC fmt "+src_fmt+", "+src_comp+", stride "+src_lineStride+", isGLOrient "+src_glOriented);
System.err.println("XXX: DST fmt "+dst_fmt+", "+dst_comp+", stride "+dst_lineStride+", isGLOrient "+dst_glOriented);
}
if( fast_copy ) {
// Fast copy
for(int y=0; y srcBitStream = new Bitstream(srcBBS, false /* outputMode */);
srcBitStream.setThrowIOExceptionOnEOF(true);
final Bitstream.ByteBufferStream dstBBS = new Bitstream.ByteBufferStream(dst_bb);
final Bitstream dstBitStream = new Bitstream(dstBBS, true /* outputMode */);
dstBitStream.setThrowIOExceptionOnEOF(true);
if( DEBUG ) {
System.err.println("XXX: cmap.dst2src "+Arrays.toString(cmap.dst2src));
System.err.println("XXX: cmap.src2dst "+Arrays.toString(cmap.src2dst));
System.err.println("XXX: cmap.srcRGBA "+Arrays.toString(cmap.srcRGBA));
System.err.println("XXX: srcBitStream "+srcBitStream);
System.err.println("XXX: dstBitStream "+dstBitStream);
}
try {
for(int y=0; y dstBitStream,
final PixelFormat.Composition srcComp,
final Bitstream srcBitStream) throws IllegalStateException, IOException {
final int sCompCount = srcComp.componentCount();
final int dCompCount = dstComp.componentCount();
final int[] sc = new int[sCompCount];
final int[] dcDef = new int[dCompCount];
final int[] srcCompBitCount = srcComp.componentBitCount();
final int[] srcCompBitMask = srcComp.componentBitMask();
final int[] dstCompBitCount = dstComp.componentBitCount();
// Fill w/ source values
for(int sIdx=0; sIdx Y conversion
final int r = sc[cmap.srcRGBA[0]];
final int g = sc[cmap.srcRGBA[1]];
final int b = sc[cmap.srcRGBA[2]];
final float rF = srcComp.toFloat(r, cmap.srcRGBA[0], false);
final float gF = srcComp.toFloat(g, cmap.srcRGBA[1], false);
final float bF = srcComp.toFloat(b, cmap.srcRGBA[2], false);
final int a;
final float aF;
/** if( 0 <= cmap.srcRGBA[3] ) { // disable premultiplied-alpha
a = sc[cmap.srcRGBA[3]];
aF = srcComp.toFloat(a, false, cmap.srcRGBA[3]);
} else */ {
a = 1;
aF = 1f;
}
final float lF = ( rF + gF + bF ) * aF / 3f;
final int v = dstComp.fromFloat(lF, 0, false);
dstBitStream.writeBits31(dstCompBitCount[0], v);
dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel());
if( DEBUG ) {
if( srcBitStream.position() <= 8*4 ) {
System.err.printf("convert: rgb[a] -> Y: rgb 0x%02X 0x%02X 0x%02X 0x%02X -> %f %f %f %f"+
" -> %f -> dstC 0 0x%08X (%d bits: %s)%n",
r, g, b, a,
rF, gF, bF, aF,
lF, v, dstCompBitCount[0], Bitstream.toBinString(true, v, dstCompBitCount[0])
);
}
}
return;
}
for(int dIdx=0; dIdx %f -> dstC %d 0x%08X (%d bits: %s)%n",
sIdx, sc[sIdx], f, dIdx, v, dstCompBitCount[dIdx], Bitstream.toBinString(true, v, dstCompBitCount[dIdx]));
}
}
} else {
dstBitStream.writeBits31(dstCompBitCount[dIdx], dcDef[dIdx]);
if( DEBUG ) {
if( srcBitStream.position() <= 8*4 ) {
System.err.printf("convert: srcC %d: undef -> dstC %d 0x%08X (%d bits: %s)%n",
sIdx, dIdx, dcDef[dIdx], dstCompBitCount[dIdx], Bitstream.toBinString(true, dcDef[dIdx], dstCompBitCount[dIdx]));
}
}
}
}
dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel());
return;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy