/**
* Copyright 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.opengl.test.junit.jogl.util.texture;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.jogamp.nativewindow.util.Dimension;
import com.jogamp.nativewindow.util.PixelFormat;
import com.jogamp.nativewindow.util.PixelFormatUtil;
import com.jogamp.nativewindow.util.PixelRectangle;
import com.jogamp.nativewindow.util.PixelFormat.CType;
import org.junit.Assert;
import org.junit.Test;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import com.jogamp.common.util.Bitstream;
import com.jogamp.opengl.test.junit.util.UITestCase;
/**
* Testing PixelFormatUtil's Conversion using synthetic test data
* including strides, endian-order and all PixelFormat conversions.
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestPixelFormatUtil00NEWT extends UITestCase {
static final byte undef_val = (byte)0xFF;
static final PixelFormat.Composition comp_val = PixelFormat.RGBA8888.comp;
static final float red___valF;
static final float green_valF;
static final float blue__valF;
static final float alpha_valF;
static final float lum___valF;
static {
// Using am equal stepping of 0x30 = 48 between each RGBA and undefined values,
// dividing 0xff equally by 5 excluding zero.
final byte red___val = (byte)0x30;
final byte green_val = (byte)0x60;
final byte blue__val = (byte)0x90;
final byte alpha_val = (byte)0xC0;
red___valF = comp_val.toFloat(red___val, 0, false);
green_valF = comp_val.toFloat(green_val, 1, false);
blue__valF = comp_val.toFloat(blue__val, 2, false);
alpha_valF = comp_val.toFloat(alpha_val, 3, false);
lum___valF = ( red___valF + green_valF + blue__valF ) / 3f;
}
@Test
public void testConversion00() throws InterruptedException, IOException, MalformedURLException {
{
final PixelFormat fmt = PixelFormat.RGBA5551;
final PixelFormat.Composition comp = fmt.comp;
System.err.printf("%s, %s:%n", fmt, comp);
final int u16_alpha = comp.encode4CompI8((byte)comp.fromFloat(red___valF, 0, false),
(byte)comp.fromFloat(green_valF, 0, false),
(byte)comp.fromFloat(blue__valF, 0, false),
(byte)comp.fromFloat(alpha_valF, 0, false));
final int u16_undef = comp.encode4CompI8((byte)comp.fromFloat(red___valF, 0, false),
(byte)comp.fromFloat(green_valF, 0, false),
(byte)comp.fromFloat(blue__valF, 0, false),
undef_val);
System.err.printf(" u16_alpha %s%n", Bitstream.toHexBinString(true, u16_alpha, comp.bitsPerPixel()));
System.err.printf(" u16_undef %s%n", Bitstream.toHexBinString(true, u16_undef, comp.bitsPerPixel()));
{
final byte c4NormI8_alpha = (byte)comp.fromFloat(alpha_valF, 0, false);
final byte c4NormI8_undef = undef_val;
final int compBitShift = 15;
final int compMask = 0x1;
final int v_alpha = ( c4NormI8_alpha & compMask ) << compBitShift ;
final int v_undef = ( c4NormI8_undef & compMask ) << compBitShift ;
System.err.printf(" xx_alpha %s%n", Bitstream.toHexBinString(true, v_alpha, comp.bitsPerPixel()));
System.err.printf(" xx_undef %s%n", Bitstream.toHexBinString(true, v_undef, comp.bitsPerPixel()));
}
}
{
final int r8 = 0x30;
final int g8 = 0x60;
final int b8 = 0x90;
final int a8 = 0xC0;
final int l1 = 0x1;
final int r5 = 0x6;
final int g6 = 0xC;
final int b5 = 0x6;
final PixelFormat rgba8888Fmt = PixelFormat.RGBA8888;
final PixelFormat.Composition rgba8888Comp = rgba8888Fmt.comp;
final PixelFormat rgb565Fmt = PixelFormat.RGB565;
final PixelFormat.Composition rgb565Comp = rgb565Fmt.comp;
final PixelFormat lumFmt = PixelFormat.LUMINANCE;
final PixelFormat.Composition lumComp = lumFmt.comp;
System.err.printf("%s, %s -> %s %s%n", rgb565Fmt, rgb565Comp, lumFmt, lumComp);
{
final float r8f = rgba8888Comp.toFloat(r8, 0, false);
final int r8fi = rgba8888Comp.fromFloat(r8f, 0, false);
final float g8f = rgba8888Comp.toFloat(g8, 1, false);
final int g8fi = rgba8888Comp.fromFloat(g8f, 1, false);
final float b8f = rgba8888Comp.toFloat(b8, 2, false);
final int b8fi = rgba8888Comp.fromFloat(b8f, 2, false);
final float a8f = rgba8888Comp.toFloat(a8, 3, false);
final int a8fi = rgba8888Comp.fromFloat(a8f, 3, false);
System.err.printf("res00.0.r %s -> %f -> %s%n", Bitstream.toHexBinString(true, r8, 8), r8f, Bitstream.toHexBinString(true, r8fi, 8));
System.err.printf("res00.0.g %s -> %f -> %s%n", Bitstream.toHexBinString(true, g8, 8), g8f, Bitstream.toHexBinString(true, g8fi, 8));
System.err.printf("res00.0.b %s -> %f -> %s%n", Bitstream.toHexBinString(true, b8, 8), b8f, Bitstream.toHexBinString(true, b8fi, 8));
System.err.printf("res00.0.a %s -> %f -> %s%n", Bitstream.toHexBinString(true, a8, 8), a8f, Bitstream.toHexBinString(true, a8fi, 8));
}
{
final float res00_0 = ( red___valF + green_valF + blue__valF ) / 3f;
final int res00 = rgba8888Comp.fromFloat(res00_0, 0, false);
System.err.printf("res01.0 ( %f + %f + %f ) / 3f = %f -> %s%n",
red___valF, green_valF, blue__valF, res00_0, Bitstream.toHexBinString(true, res00, 8));
}
{
final float res00_0 = ( red___valF + green_valF + blue__valF ) / 3f;
final int res00 = lumComp.fromFloat(res00_0, 0, false);
System.err.printf("res02.1 ( %f + %f + %f ) / 3f = %f -> %s%n",
red___valF, green_valF, blue__valF, res00_0, Bitstream.toHexBinString(true, res00, 8));
}
{
// sourceNorm static -> lum
final int rl1 = lumComp.fromFloat(red___valF, 0, false);
final int gl1 = lumComp.fromFloat(green_valF, 0, false);
final int bl1 = lumComp.fromFloat(blue__valF, 0, false);
final float rl2 = lumComp.toFloat(rl1, 0, false);
final float gl2 = lumComp.toFloat(gl1, 0, false);
final float bl2 = lumComp.toFloat(bl1, 0, false);
System.err.printf("res20.l1 ( %s + %s + %s )%n",
Bitstream.toHexBinString(true, rl1, 8),
Bitstream.toHexBinString(true, gl1, 8),
Bitstream.toHexBinString(true, bl1, 8));
System.err.printf("res20.l2 ( %f + %f + %f )%n", rl2, gl2, bl2);
final float res02_l2_0 = ( rl2 + gl2 + bl2 ) / 3f;
final int res02_l2_x = lumComp.fromFloat(res02_l2_0, 0, false);
System.err.printf("res20.l3 ( %f + %f + %f ) / 3f = %f -> %s%n",
rl2, gl2, bl2, res02_l2_0, Bitstream.toHexBinString(true, res02_l2_x, 8));
// rescale lum -> rgb565
final int r_1 = rgb565Comp.fromFloat(rl2, 0, false);
final int g_1 = rgb565Comp.fromFloat(gl2, 1, false);
final int b_1 = rgb565Comp.fromFloat(bl2, 2, false);
final float r_2 = rgb565Comp.toFloat(r_1, 0, false);
final float g_2 = rgb565Comp.toFloat(g_1, 1, false);
final float b_2 = rgb565Comp.toFloat(b_1, 2, false);
System.err.printf("res20._1 ( %s + %s + %s )%n",
Bitstream.toHexBinString(true, r_1, 8),
Bitstream.toHexBinString(true, g_1, 8),
Bitstream.toHexBinString(true, b_1, 8));
System.err.printf("res20._2 ( %f + %f + %f )%n", r_2, g_2, b_2);
final float res02__3_0 = ( r_2 + g_2 + b_2 ) / 3f;
final int res02__3_x = lumComp.fromFloat(res02__3_0, 0, false);
System.err.printf("res20._3 ( %f + %f + %f ) / 3f = %f -> %s%n",
r_2, g_2, b_2, res02__3_0, Bitstream.toHexBinString(true, res02__3_x, 8));
}
{
// sourceNorm static -> lum
// rescale lum -> rgb565
final float rF = rgb565Comp.toFloat(rescaleComp(lumComp, 0, rgb565Comp, 0, red___valF), 0, false);
final float gF = rgb565Comp.toFloat(rescaleComp(lumComp, 0, rgb565Comp, 1, green_valF), 1, false);
final float bF = rgb565Comp.toFloat(rescaleComp(lumComp, 0, rgb565Comp, 2, blue__valF), 2, false);
final float res01_0 = ( rF + gF + bF ) / 3f;
final int res01 = lumComp.fromFloat(res01_0, 0, false);
System.err.printf("res30.xx ( %f + %f + %f ) / 3f = %f -> %s%n",
rF, gF, bF, res01_0, Bitstream.toHexBinString(true, res01, 8));
}
{
final float rF = rgb565Comp.toFloat(r5, 0, false);
final float gF = rgb565Comp.toFloat(g6, 1, false);
final float bF = rgb565Comp.toFloat(b5, 2, false);
final float lF = ( rF + gF + bF ) / 3f;
final int res00 = lumComp.fromFloat(lF, 0, false);
System.err.printf("res40 ( %f + %f + %f ) / 3f = %s%n",
rF, gF, bF, Bitstream.toHexBinString(true, res00, 8));
}
}
}
@Test
public void testConversion01_srcS000_BE_TL_destS000_TL() throws InterruptedException, IOException, MalformedURLException {
testConversionImpl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */,
0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
}
@Test
public void testConversion02_srcS000_LE_TL_destS000_TL() throws InterruptedException, IOException, MalformedURLException {
testConversionImpl(0 /* srcMinStrideInBytes */, ByteOrder.LITTLE_ENDIAN, false /* srcIsGLOriented */,
0 /* destMinStrideInBytes */, false /* destIsGLOriented */);
}
@Test
public void testConversion03_srcS000_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException {
testConversionImpl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */,
259 /* destMinStrideInBytes */, false /* destIsGLOriented */);
}
@Test
public void testConversion04_srcS259_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException {
testConversionImpl(259 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */,
259 /* destMinStrideInBytes */, false /* destIsGLOriented */);
}
@Test
public void testConversion05_srcS301_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException {
testConversionImpl(301 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */,
259 /* destMinStrideInBytes */, false /* destIsGLOriented */);
}
/**
* Note: Fixes bit-rounding errors, i.e. RGBA5551: A 0.6f -> 0x01 -> 1f ... -> RGBA8888: A 0xff
*/
static final float sourceNorm(final PixelFormat.Composition srcComp, final int sIdx, final float f) {
if( sIdx >= 0 && sIdx < srcComp.componentCount() ) {
return srcComp.toFloat(srcComp.fromFloat(f, sIdx, false), sIdx, false);
} else {
return 0f;
}
}
static final byte rescaleComp(final PixelFormat.Composition srcComp, final int sIdx,
final PixelFormat.Composition dstComp, final int dIdx, final float f) {
if( dIdx >= 0 && dIdx < dstComp.componentCount() ) {
return (byte)dstComp.fromFloat(sourceNorm(srcComp, sIdx, f), dIdx, false);
} else {
return (byte)0;
}
}
static final void getComponentData(final PixelFormat srcFmt, final PixelFormat dstFmt, final byte[] components) {
final PixelFormat.Composition srcComp = srcFmt.comp;
final PixelFormat.Composition dstComp = dstFmt.comp;
final byte b1, b2, b3, b4;
int u16;
if( PixelFormat.LUMINANCE == srcFmt ) {
// LUM -> Fmt Conversion
switch(dstFmt) {
case LUMINANCE:
b1 = rescaleComp(srcComp, 0, dstComp, 0, lum___valF);
b2 = undef_val;
b3 = undef_val;
b4 = undef_val;
break;
case RGB565:
case BGR565:
u16 = dstComp.encode3CompI8(
rescaleComp(srcComp, 0, dstComp, 0, lum___valF),
rescaleComp(srcComp, 0, dstComp, 1, lum___valF),
rescaleComp(srcComp, 0, dstComp, 2, lum___valF));
b1 = (byte)( u16 & 0xff );
b2 = (byte)( ( u16 >>> 8 ) & 0xff );
b3 = undef_val;
b4 = undef_val;
break;
case RGBA5551:
u16 = dstComp.encode4CompI8(
rescaleComp(srcComp, 0, dstComp, 0, lum___valF),
rescaleComp(srcComp, 0, dstComp, 1, lum___valF),
rescaleComp(srcComp, 0, dstComp, 2, lum___valF),
undef_val);
b1 = (byte)( u16 & 0xff );
b2 = (byte)( ( u16 >>> 8 ) & 0xff );
b3 = undef_val;
b4 = undef_val;
break;
case ABGR1555:
u16 = dstComp.encode4CompI8(
undef_val,
rescaleComp(srcComp, 0, dstComp, 0, lum___valF),
rescaleComp(srcComp, 0, dstComp, 1, lum___valF),
rescaleComp(srcComp, 0, dstComp, 2, lum___valF) );
b1 = (byte)( u16 & 0xff );
b2 = (byte)( ( u16 >>> 8 ) & 0xff );
b3 = undef_val;
b4 = undef_val;
break;
case BGRx8888:
case RGBx8888:
case RGB888:
case BGR888:
case RGBA8888:
b1 = rescaleComp(srcComp, 0, dstComp, 0, lum___valF);
b2 = rescaleComp(srcComp, 0, dstComp, 1, lum___valF);
b3 = rescaleComp(srcComp, 0, dstComp, 2, lum___valF);
b4 = undef_val;
break;
case ABGR8888:
case ARGB8888:
b1 = undef_val;
b2 = rescaleComp(srcComp, 0, dstComp, 1, lum___valF);
b3 = rescaleComp(srcComp, 0, dstComp, 2, lum___valF);
b4 = rescaleComp(srcComp, 0, dstComp, 3, lum___valF);
break;
case BGRA8888:
b1 = rescaleComp(srcComp, 0, dstComp, 0, lum___valF);
b2 = rescaleComp(srcComp, 0, dstComp, 1, lum___valF);
b3 = rescaleComp(srcComp, 0, dstComp, 2, lum___valF);
b4 = undef_val;
break;
default:
throw new InternalError("Unhandled format "+dstFmt);
}
} else {
final int srcIdxR = srcComp.find(CType.R);
final int srcIdxG = srcComp.find(CType.G);
final int srcIdxB = srcComp.find(CType.B);
final int srcIdxA = srcComp.find(CType.A);
final boolean srcHasAlpha = 0 <= srcIdxA;
final boolean srcHasRGB = 0 <= srcIdxR && 0 <= srcIdxG && 0 <= srcIdxB;
// 1:1 values
switch(dstFmt) {
case LUMINANCE:
if( srcHasRGB ) {
final float rF = sourceNorm(srcComp, srcIdxR, red___valF);
final float gF = sourceNorm(srcComp, srcIdxG, green_valF);
final float bF = sourceNorm(srcComp, srcIdxB, blue__valF);
b1 = (byte)dstComp.fromFloat( ( rF + gF + bF ) / 3f, 0, false);
b2 = undef_val;
b3 = undef_val;
b4 = undef_val;
} else {
b1 = rescaleComp(srcComp, 0, dstComp, 0, red___valF);
b2 = undef_val;
b3 = undef_val;
b4 = undef_val;
}
break;
case RGB565:
u16 = dstComp.encode3CompI8(
rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF),
rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF),
rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF));
b1 = (byte)( u16 & 0xff );
b2 = (byte)( ( u16 >>> 8 ) & 0xff );
b3 = undef_val;
b4 = undef_val;
break;
case BGR565:
u16 = dstComp.encode3CompI8(
rescaleComp(srcComp, srcIdxB, dstComp, 0, blue__valF),
rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF),
rescaleComp(srcComp, srcIdxR, dstComp, 2, red___valF));
b1 = (byte)( u16 & 0xff );
b2 = (byte)( ( u16 >>> 8 ) & 0xff );
b3 = undef_val;
b4 = undef_val;
break;
case RGBA5551:
u16 = dstComp.encode4CompI8(
rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF),
rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF),
rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF),
srcHasAlpha ? rescaleComp(srcComp, srcIdxA, dstComp, 3, alpha_valF) : undef_val);
b1 = (byte)( u16 & 0xff );
b2 = (byte)( ( u16 >>> 8 ) & 0xff );
b3 = undef_val;
b4 = undef_val;
break;
case ABGR1555:
u16 = dstComp.encode4CompI8(
srcHasAlpha ? rescaleComp(srcComp, srcIdxA, dstComp, 0, alpha_valF) : undef_val,
rescaleComp(srcComp, srcIdxB, dstComp, 1, blue__valF),
rescaleComp(srcComp, srcIdxG, dstComp, 2, green_valF),
rescaleComp(srcComp, srcIdxR, dstComp, 3, red___valF) );
b1 = (byte)( u16 & 0xff );
b2 = (byte)( ( u16 >>> 8 ) & 0xff );
b3 = undef_val;
b4 = undef_val;
break;
case RGBx8888:
case RGB888:
b1 = rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF);
b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF);
b3 = rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF);
b4 = undef_val;
break;
case BGRx8888:
case BGR888:
b1 = rescaleComp(srcComp, srcIdxB, dstComp, 0, blue__valF);
b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF);
b3 = rescaleComp(srcComp, srcIdxR, dstComp, 2, red___valF);
b4 = undef_val;
break;
case RGBA8888:
b1 = rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF);
b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF);
b3 = rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF);
if( srcHasAlpha ) {
b4 = rescaleComp(srcComp, srcIdxA, dstComp, 3, alpha_valF);
} else {
b4 = undef_val;
}
break;
case ABGR8888:
if( srcHasAlpha ) {
b1 = rescaleComp(srcComp, srcIdxA, dstComp, 0, alpha_valF);
} else {
b1 = undef_val;
}
b2 = rescaleComp(srcComp, srcIdxB, dstComp, 1, blue__valF);
b3 = rescaleComp(srcComp, srcIdxG, dstComp, 2, green_valF);
b4 = rescaleComp(srcComp, srcIdxR, dstComp, 3, red___valF);
break;
case BGRA8888:
b1 = rescaleComp(srcComp, srcIdxB, dstComp, 0, blue__valF);
b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF);
b3 = rescaleComp(srcComp, srcIdxR, dstComp, 2, red___valF);
if( srcHasAlpha ) {
b4 = rescaleComp(srcComp, srcIdxA, dstComp, 3, alpha_valF);
} else {
b4 = undef_val;
}
break;
case ARGB8888:
if( srcHasAlpha ) {
b1 = rescaleComp(srcComp, srcIdxA, dstComp, 0, alpha_valF);
} else {
b1 = undef_val;
}
b2 = rescaleComp(srcComp, srcIdxR, dstComp, 1, red___valF);
b3 = rescaleComp(srcComp, srcIdxG, dstComp, 2, green_valF);
b4 = rescaleComp(srcComp, srcIdxB, dstComp, 3, blue__valF);
break;
default:
throw new InternalError("Unhandled format "+dstFmt);
}
}
components[0] = b1;
components[1] = b2;
components[2] = b3;
components[3] = b4;
}
private void testConversionImpl(final int srcMinStrideInBytes, final ByteOrder srcByteOrder, final boolean srcIsGLOriented,
final int destMinStrideInBytes, final boolean destIsGLOriented)
throws InterruptedException, IOException, MalformedURLException
{
System.err.println("Test00: srcMinStrideInBytes "+srcMinStrideInBytes+", srcByteOrder "+srcByteOrder+", srcIsGLOriented "+srcIsGLOriented+
", destMinStrideInBytes "+destMinStrideInBytes+", destIsGLOriented "+destIsGLOriented);
// final PixelFormat[] srcFormats = { PixelFormat.LUMINANCE };
// final PixelFormat[] dstFormats = { PixelFormat.RGBx8888 };
// final PixelFormat[] dstFormats = { PixelFormat.RGB5551 };
// final PixelFormat[] dstFormats = { PixelFormat.RGB888 };
// final PixelFormat[] srcFormats = { PixelFormat.RGB888 };
// final PixelFormat[] dstFormats = { PixelFormat.RGB565 };
final PixelFormat[] srcFormats = PixelFormat.values();
final PixelFormat[] dstFormats = PixelFormat.values();
final int width = 64, height = 64;
for(int i=0; i<srcFormats.length; i++) {
final PixelFormat srcFmt = srcFormats[i];
final int srcBpp = srcFmt.comp.bytesPerPixel();
final int srcStrideBytes = Math.max(srcMinStrideInBytes, width*srcBpp);
final ByteBuffer srcPixels = ByteBuffer.allocate(height*srcStrideBytes).order(srcByteOrder);
final byte[] srcData = new byte[4];
getComponentData(srcFmt, srcFmt, srcData);
for(int y=0; y<height; y++) {
int o = y*srcStrideBytes;
for(int x=0; x<width; x++) {
switch(srcFmt) {
case LUMINANCE:
srcPixels.put(o++, srcData[0]);
break;
case BGR565:
case RGB565:
case ABGR1555:
case RGBA5551:
srcPixels.put(o++, srcData[0]);
srcPixels.put(o++, srcData[1]);
break;
case RGB888:
case BGR888:
srcPixels.put(o++, srcData[0]);
srcPixels.put(o++, srcData[1]);
srcPixels.put(o++, srcData[2]);
break;
case RGBx8888:
case BGRx8888:
case RGBA8888:
case ABGR8888:
case BGRA8888:
case ARGB8888:
srcPixels.put(o++, srcData[0]);
srcPixels.put(o++, srcData[1]);
srcPixels.put(o++, srcData[2]);
srcPixels.put(o++, srcData[3]);
break;
default:
throw new InternalError("Unhandled format "+srcFmt);
}
}
}
final PixelRectangle imageSrc = new PixelRectangle.GenericPixelRect(srcFmt, new Dimension(width, height),
srcStrideBytes, srcIsGLOriented, srcPixels);
System.err.println("CONVERT["+i+"][*]: Image0 - Orig: "+imageSrc);
System.err.printf("Source %s, %s%n", srcFmt, srcFmt.comp);
System.err.printf("Source Data: %s%n", Bitstream.toHexBinString(true, srcData, 0, srcFmt.comp.bytesPerPixel()));
testComponents(imageSrc, 0, 0, srcData, 0);
testComponents(imageSrc, width-1, height-1, srcData, 0);
final int maxDelta = 12;
for(int j=0; j<dstFormats.length; j++) {
final PixelFormat destFmt = dstFormats[j];
System.err.println("CONVERT["+i+"]["+j+"]: "+srcFmt+" -> "+destFmt);
final int destStrideBytes = Math.max(destMinStrideInBytes, width*destFmt.comp.bytesPerPixel());
final byte[] destComponents = new byte[4];
getComponentData(srcFmt, destFmt, destComponents);
System.err.printf("Source %s, %s%n", srcFmt, srcFmt.comp);
System.err.printf("Source Data: %s%n", Bitstream.toHexBinString(true, srcData, 0, srcFmt.comp.bytesPerPixel()));
System.err.printf("Dest %s, %s%n", destFmt, destFmt.comp);
System.err.printf("Dest Data: %s%n", Bitstream.toHexBinString(true, destComponents, 0, destFmt.comp.bytesPerPixel()));
final PixelRectangle imageConv1 = PixelFormatUtil.convert(imageSrc, destFmt, destStrideBytes, destIsGLOriented, false /* nio */);
System.err.println("CONVERT["+i+"]["+j+"]: Conv1: "+imageConv1+", maxDelta "+maxDelta);
System.err.printf("Conv1 Data: %s%n", Bitstream.toHexBinString(true, imageConv1.getPixels(), 0, destFmt.comp.bytesPerPixel()));
testComponents(imageConv1, 0, 0, destComponents, maxDelta);
testComponents(imageConv1, width-1, height-1, destComponents, maxDelta);
if( PixelFormat.LUMINANCE != srcFmt && PixelFormat.LUMINANCE == destFmt ) {
// Cannot convert: RGB* -> LUM -> RGB*
System.err.println("CONVERT["+i+"]["+j+"]: Conv2: Dropped due to RGB* -> LUM");
} else if( srcFmt.comp.componentCount() > destFmt.comp.componentCount() ) {
// Cannot convert back if: src.componentCount > dest.componentCount
System.err.println("CONVERT["+i+"]["+j+"]: Conv2: Dropped due to src.componentCount > dest.componentCount");
} else {
final PixelRectangle imageConv2 = PixelFormatUtil.convert(imageConv1, imageSrc.getPixelformat(), imageSrc.getStride(), imageSrc.isGLOriented(), false /* nio */);
System.err.println("CONVERT["+i+"]["+j+"]: Conv2: "+imageConv2+", maxDelta "+maxDelta);
System.err.printf("Conv2 Data: %s%n", Bitstream.toHexBinString(true, imageConv2.getPixels(), 0, srcFmt.comp.bytesPerPixel()));
final byte[] destReComponents = new byte[4];
getComponentData(destFmt, srcFmt, destReComponents);
System.err.printf("DestRe Data: %s%n", Bitstream.toHexBinString(true, destReComponents, 0, srcFmt.comp.bytesPerPixel()));
testComponents(imageConv2, 0, 0, destReComponents, maxDelta);
testComponents(imageConv2, width-1, height-1, destReComponents, maxDelta);
/**
* Due to 'dead' components or value range re-scale,
* identity comparison on byte level is not correct.
*
if( imageSrc.getStride() == imageConv1.getStride() ) {
Assert.assertEquals(imageSrc.getPixels(), imageConv2.getPixels());
}
*/
}
}
}
}
static void dumpComponents(final PixelRectangle image, int x1, int y1, final int w, final int h) {
if( x1 + w >= image.getSize().getWidth() ) {
x1 = image.getSize().getWidth() - w;
}
if( y1 + h >= image.getSize().getHeight() ) {
y1 = image.getSize().getHeight() - h;
}
System.err.print("PixelsBytes "+x1+"/"+y1+" "+w+"x"+h+":");
final ByteBuffer bb = image.getPixels();
final int bpp = image.getPixelformat().comp.bytesPerPixel();
for(int y = y1; y< y1+h; y++) {
System.err.printf("%n[%3d][%3d] ", x1, y);
int o = y * image.getStride()+x1*bpp;
for(int x = x1; x< x1+w; x++) {
switch(bpp) {
case 1: {
final byte a = bb.get(o++);
System.err.printf(" 0x%02X", a);
}
break;
case 2: {
final byte a = bb.get(o++), b = bb.get(o++);
System.err.printf(" 0x%02X%02X", b, a);
}
break;
case 3: {
final byte a = bb.get(o++), b = bb.get(o++), c = bb.get(o++);
System.err.printf(" 0x%02X%02X%02X", c, b, a);
}
break;
case 4: {
final byte a = bb.get(o++), b = bb.get(o++), c = bb.get(o++), d = bb.get(o++);
System.err.printf(" 0x%02X%02X%02X%02X", d, c, b, a);
}
break;
}
}
}
System.err.println();
}
static final void assertEquals(final int a, final int b, final int maxDelta) {
final int d = Math.abs( a - b );
Assert.assertTrue(String.format("Not equal: abs(%s - %s) = %d, > %d maxDelta",
Bitstream.toHexBinString(true, a, 8), Bitstream.toHexBinString(true, b, 8), d, maxDelta),
d <= maxDelta);
}
static final boolean equals(final int a, final int b, final int maxDelta) {
final int d = Math.abs( a - b );
return d <= maxDelta;
}
/**
*
* @param image actual data
* @param x position in actual data
* @param y position in actual data
* @param expData expected data
* @param maxDelta the maximum delta between expected {@code components} and actual {@code image} data
*/
static void testComponents(final PixelRectangle image, final int x, final int y, final byte[] expData, final int maxDelta) {
dumpComponents(image, x, y, 3, 3);
final PixelFormat.Composition imgComp = image.getPixelformat().comp;
final ByteBuffer bb = image.getPixels();
final int bytesPerPixel = imgComp.bytesPerPixel();
final int compCount = imgComp.componentCount();
final int[] compBitCount = imgComp.componentBitCount();
final int srcPixOffset = y * image.getStride()+x*bytesPerPixel;
final int bbPos = bb.position();
bb.position(bbPos+srcPixOffset);
final long srcPix64 = PixelFormatUtil.getShiftedI64(imgComp.bytesPerPixel(), bb, true);
final int[] srcComponents = new int[compCount];
final long expPix64 = PixelFormatUtil.getShiftedI64(imgComp.bytesPerPixel(), expData, 0);
final int[] expComponents = new int[compCount];
boolean equal = true;
for(int i=0; i<compCount; i++) {
srcComponents[i] = imgComp.decodeSingleI64(srcPix64, i);
expComponents[i] = imgComp.decodeSingleI64(expPix64, i);
equal = equal && equals(srcComponents[i], expComponents[i], maxDelta);
}
System.err.printf("Test [%3d][%3d] exp ", x, y);
for(int i=0; i<compCount; i++) { System.err.printf("%s ", Bitstream.toHexBinString(true, expComponents[i], compBitCount[i])); }
System.err.printf("==%nTest [%3d][%3d] has ", x, y);
for(int i=0; i<compCount; i++) { System.err.printf("%s ", Bitstream.toHexBinString(true, srcComponents[i], compBitCount[i])); }
System.err.printf(": equal %b%n%n", equal);
for(int i=0; i<compCount; i++) {
assertEquals(srcComponents[i], expComponents[i], maxDelta);
}
bb.position(bbPos);
}
public static void main(final String args[]) {
org.junit.runner.JUnitCore.main(TestPixelFormatUtil00NEWT.class.getName());
}
}