1 /** 2 * Copyright 2014 JogAmp Community. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, are 5 * permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this list of 8 * conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 * of conditions and the following disclaimer in the documentation and/or other materials 12 * provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * The views and conclusions contained in the software and documentation are those of the 25 * authors and should not be interpreted as representing official policies, either expressed 26 * or implied, of JogAmp Community. 27 */ 28 package com.jogamp.opengl.test.junit.jogl.util.texture; 29 30 import java.io.IOException; 31 import java.net.MalformedURLException; 32 import java.nio.ByteBuffer; 33 import java.nio.ByteOrder; 34 35 import com.jogamp.nativewindow.util.Dimension; 36 import com.jogamp.nativewindow.util.PixelFormat; 37 import com.jogamp.nativewindow.util.PixelFormatUtil; 38 import com.jogamp.nativewindow.util.PixelRectangle; 39 import com.jogamp.nativewindow.util.PixelFormat.CType; 40 41 import org.junit.Assert; 42 import org.junit.Test; 43 import org.junit.FixMethodOrder; 44 import org.junit.runners.MethodSorters; 45 46 import com.jogamp.common.util.Bitstream; 47 import com.jogamp.opengl.test.junit.util.UITestCase; 48 49 /** 50 * Testing PixelFormatUtil's Conversion using synthetic test data 51 * including strides, endian-order and all PixelFormat conversions. 52 */ 53 @FixMethodOrder(MethodSorters.NAME_ASCENDING) 54 public class TestPixelFormatUtil00NEWT extends UITestCase { 55 static final byte undef_val = (byte)0xFF; 56 static final PixelFormat.Composition comp_val = PixelFormat.RGBA8888.comp; 57 static final float red___valF; 58 static final float green_valF; 59 static final float blue__valF; 60 static final float alpha_valF; 61 static final float lum___valF; 62 static { 63 // Using am equal stepping of 0x30 = 48 between each RGBA and undefined values, 64 // dividing 0xff equally by 5 excluding zero. 65 final byte red___val = (byte)0x30; 66 final byte green_val = (byte)0x60; 67 final byte blue__val = (byte)0x90; 68 final byte alpha_val = (byte)0xC0; 69 red___valF = comp_val.toFloat(red___val, 0, false); 70 green_valF = comp_val.toFloat(green_val, 1, false); 71 blue__valF = comp_val.toFloat(blue__val, 2, false); 72 alpha_valF = comp_val.toFloat(alpha_val, 3, false); 73 lum___valF = ( red___valF + green_valF + blue__valF ) / 3f; 74 } 75 76 @Test testConversion00()77 public void testConversion00() throws InterruptedException, IOException, MalformedURLException { 78 { 79 final PixelFormat fmt = PixelFormat.RGBA5551; 80 final PixelFormat.Composition comp = fmt.comp; 81 System.err.printf("%s, %s:%n", fmt, comp); 82 final int u16_alpha = comp.encode4CompI8((byte)comp.fromFloat(red___valF, 0, false), 83 (byte)comp.fromFloat(green_valF, 0, false), 84 (byte)comp.fromFloat(blue__valF, 0, false), 85 (byte)comp.fromFloat(alpha_valF, 0, false)); 86 final int u16_undef = comp.encode4CompI8((byte)comp.fromFloat(red___valF, 0, false), 87 (byte)comp.fromFloat(green_valF, 0, false), 88 (byte)comp.fromFloat(blue__valF, 0, false), 89 undef_val); 90 System.err.printf(" u16_alpha %s%n", Bitstream.toHexBinString(true, u16_alpha, comp.bitsPerPixel())); 91 System.err.printf(" u16_undef %s%n", Bitstream.toHexBinString(true, u16_undef, comp.bitsPerPixel())); 92 { 93 final byte c4NormI8_alpha = (byte)comp.fromFloat(alpha_valF, 0, false); 94 final byte c4NormI8_undef = undef_val; 95 final int compBitShift = 15; 96 final int compMask = 0x1; 97 final int v_alpha = ( c4NormI8_alpha & compMask ) << compBitShift ; 98 final int v_undef = ( c4NormI8_undef & compMask ) << compBitShift ; 99 System.err.printf(" xx_alpha %s%n", Bitstream.toHexBinString(true, v_alpha, comp.bitsPerPixel())); 100 System.err.printf(" xx_undef %s%n", Bitstream.toHexBinString(true, v_undef, comp.bitsPerPixel())); 101 } 102 } 103 { 104 final int r8 = 0x30; 105 final int g8 = 0x60; 106 final int b8 = 0x90; 107 final int a8 = 0xC0; 108 109 final int l1 = 0x1; 110 final int r5 = 0x6; 111 final int g6 = 0xC; 112 final int b5 = 0x6; 113 114 final PixelFormat rgba8888Fmt = PixelFormat.RGBA8888; 115 final PixelFormat.Composition rgba8888Comp = rgba8888Fmt.comp; 116 final PixelFormat rgb565Fmt = PixelFormat.RGB565; 117 final PixelFormat.Composition rgb565Comp = rgb565Fmt.comp; 118 final PixelFormat lumFmt = PixelFormat.LUMINANCE; 119 final PixelFormat.Composition lumComp = lumFmt.comp; 120 System.err.printf("%s, %s -> %s %s%n", rgb565Fmt, rgb565Comp, lumFmt, lumComp); 121 122 { 123 final float r8f = rgba8888Comp.toFloat(r8, 0, false); 124 final int r8fi = rgba8888Comp.fromFloat(r8f, 0, false); 125 final float g8f = rgba8888Comp.toFloat(g8, 1, false); 126 final int g8fi = rgba8888Comp.fromFloat(g8f, 1, false); 127 final float b8f = rgba8888Comp.toFloat(b8, 2, false); 128 final int b8fi = rgba8888Comp.fromFloat(b8f, 2, false); 129 final float a8f = rgba8888Comp.toFloat(a8, 3, false); 130 final int a8fi = rgba8888Comp.fromFloat(a8f, 3, false); 131 132 System.err.printf("res00.0.r %s -> %f -> %s%n", Bitstream.toHexBinString(true, r8, 8), r8f, Bitstream.toHexBinString(true, r8fi, 8)); 133 System.err.printf("res00.0.g %s -> %f -> %s%n", Bitstream.toHexBinString(true, g8, 8), g8f, Bitstream.toHexBinString(true, g8fi, 8)); 134 System.err.printf("res00.0.b %s -> %f -> %s%n", Bitstream.toHexBinString(true, b8, 8), b8f, Bitstream.toHexBinString(true, b8fi, 8)); 135 System.err.printf("res00.0.a %s -> %f -> %s%n", Bitstream.toHexBinString(true, a8, 8), a8f, Bitstream.toHexBinString(true, a8fi, 8)); 136 } 137 { 138 final float res00_0 = ( red___valF + green_valF + blue__valF ) / 3f; 139 final int res00 = rgba8888Comp.fromFloat(res00_0, 0, false); 140 System.err.printf("res01.0 ( %f + %f + %f ) / 3f = %f -> %s%n", 141 red___valF, green_valF, blue__valF, res00_0, Bitstream.toHexBinString(true, res00, 8)); 142 } 143 { 144 final float res00_0 = ( red___valF + green_valF + blue__valF ) / 3f; 145 final int res00 = lumComp.fromFloat(res00_0, 0, false); 146 System.err.printf("res02.1 ( %f + %f + %f ) / 3f = %f -> %s%n", 147 red___valF, green_valF, blue__valF, res00_0, Bitstream.toHexBinString(true, res00, 8)); 148 } 149 { 150 // sourceNorm static -> lum 151 final int rl1 = lumComp.fromFloat(red___valF, 0, false); 152 final int gl1 = lumComp.fromFloat(green_valF, 0, false); 153 final int bl1 = lumComp.fromFloat(blue__valF, 0, false); 154 final float rl2 = lumComp.toFloat(rl1, 0, false); 155 final float gl2 = lumComp.toFloat(gl1, 0, false); 156 final float bl2 = lumComp.toFloat(bl1, 0, false); 157 System.err.printf("res20.l1 ( %s + %s + %s )%n", 158 Bitstream.toHexBinString(true, rl1, 8), 159 Bitstream.toHexBinString(true, gl1, 8), 160 Bitstream.toHexBinString(true, bl1, 8)); 161 System.err.printf("res20.l2 ( %f + %f + %f )%n", rl2, gl2, bl2); 162 final float res02_l2_0 = ( rl2 + gl2 + bl2 ) / 3f; 163 final int res02_l2_x = lumComp.fromFloat(res02_l2_0, 0, false); 164 System.err.printf("res20.l3 ( %f + %f + %f ) / 3f = %f -> %s%n", 165 rl2, gl2, bl2, res02_l2_0, Bitstream.toHexBinString(true, res02_l2_x, 8)); 166 167 // rescale lum -> rgb565 168 final int r_1 = rgb565Comp.fromFloat(rl2, 0, false); 169 final int g_1 = rgb565Comp.fromFloat(gl2, 1, false); 170 final int b_1 = rgb565Comp.fromFloat(bl2, 2, false); 171 final float r_2 = rgb565Comp.toFloat(r_1, 0, false); 172 final float g_2 = rgb565Comp.toFloat(g_1, 1, false); 173 final float b_2 = rgb565Comp.toFloat(b_1, 2, false); 174 System.err.printf("res20._1 ( %s + %s + %s )%n", 175 Bitstream.toHexBinString(true, r_1, 8), 176 Bitstream.toHexBinString(true, g_1, 8), 177 Bitstream.toHexBinString(true, b_1, 8)); 178 System.err.printf("res20._2 ( %f + %f + %f )%n", r_2, g_2, b_2); 179 final float res02__3_0 = ( r_2 + g_2 + b_2 ) / 3f; 180 final int res02__3_x = lumComp.fromFloat(res02__3_0, 0, false); 181 System.err.printf("res20._3 ( %f + %f + %f ) / 3f = %f -> %s%n", 182 r_2, g_2, b_2, res02__3_0, Bitstream.toHexBinString(true, res02__3_x, 8)); 183 } 184 { 185 // sourceNorm static -> lum 186 // rescale lum -> rgb565 187 final float rF = rgb565Comp.toFloat(rescaleComp(lumComp, 0, rgb565Comp, 0, red___valF), 0, false); 188 final float gF = rgb565Comp.toFloat(rescaleComp(lumComp, 0, rgb565Comp, 1, green_valF), 1, false); 189 final float bF = rgb565Comp.toFloat(rescaleComp(lumComp, 0, rgb565Comp, 2, blue__valF), 2, false); 190 final float res01_0 = ( rF + gF + bF ) / 3f; 191 final int res01 = lumComp.fromFloat(res01_0, 0, false); 192 System.err.printf("res30.xx ( %f + %f + %f ) / 3f = %f -> %s%n", 193 rF, gF, bF, res01_0, Bitstream.toHexBinString(true, res01, 8)); 194 } 195 { 196 final float rF = rgb565Comp.toFloat(r5, 0, false); 197 final float gF = rgb565Comp.toFloat(g6, 1, false); 198 final float bF = rgb565Comp.toFloat(b5, 2, false); 199 200 final float lF = ( rF + gF + bF ) / 3f; 201 final int res00 = lumComp.fromFloat(lF, 0, false); 202 203 System.err.printf("res40 ( %f + %f + %f ) / 3f = %s%n", 204 rF, gF, bF, Bitstream.toHexBinString(true, res00, 8)); 205 } 206 } 207 208 } 209 210 @Test testConversion01_srcS000_BE_TL_destS000_TL()211 public void testConversion01_srcS000_BE_TL_destS000_TL() throws InterruptedException, IOException, MalformedURLException { 212 testConversionImpl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, 213 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); 214 } 215 @Test testConversion02_srcS000_LE_TL_destS000_TL()216 public void testConversion02_srcS000_LE_TL_destS000_TL() throws InterruptedException, IOException, MalformedURLException { 217 testConversionImpl(0 /* srcMinStrideInBytes */, ByteOrder.LITTLE_ENDIAN, false /* srcIsGLOriented */, 218 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); 219 } 220 @Test testConversion03_srcS000_BE_TL_destS259_TL()221 public void testConversion03_srcS000_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException { 222 testConversionImpl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, 223 259 /* destMinStrideInBytes */, false /* destIsGLOriented */); 224 } 225 @Test testConversion04_srcS259_BE_TL_destS259_TL()226 public void testConversion04_srcS259_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException { 227 testConversionImpl(259 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, 228 259 /* destMinStrideInBytes */, false /* destIsGLOriented */); 229 } 230 @Test testConversion05_srcS301_BE_TL_destS259_TL()231 public void testConversion05_srcS301_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException { 232 testConversionImpl(301 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, 233 259 /* destMinStrideInBytes */, false /* destIsGLOriented */); 234 } 235 236 /** 237 * Note: Fixes bit-rounding errors, i.e. RGBA5551: A 0.6f -> 0x01 -> 1f ... -> RGBA8888: A 0xff 238 */ sourceNorm(final PixelFormat.Composition srcComp, final int sIdx, final float f)239 static final float sourceNorm(final PixelFormat.Composition srcComp, final int sIdx, final float f) { 240 if( sIdx >= 0 && sIdx < srcComp.componentCount() ) { 241 return srcComp.toFloat(srcComp.fromFloat(f, sIdx, false), sIdx, false); 242 } else { 243 return 0f; 244 } 245 } rescaleComp(final PixelFormat.Composition srcComp, final int sIdx, final PixelFormat.Composition dstComp, final int dIdx, final float f)246 static final byte rescaleComp(final PixelFormat.Composition srcComp, final int sIdx, 247 final PixelFormat.Composition dstComp, final int dIdx, final float f) { 248 if( dIdx >= 0 && dIdx < dstComp.componentCount() ) { 249 return (byte)dstComp.fromFloat(sourceNorm(srcComp, sIdx, f), dIdx, false); 250 } else { 251 return (byte)0; 252 } 253 } getComponentData(final PixelFormat srcFmt, final PixelFormat dstFmt, final byte[] components)254 static final void getComponentData(final PixelFormat srcFmt, final PixelFormat dstFmt, final byte[] components) { 255 final PixelFormat.Composition srcComp = srcFmt.comp; 256 final PixelFormat.Composition dstComp = dstFmt.comp; 257 final byte b1, b2, b3, b4; 258 int u16; 259 if( PixelFormat.LUMINANCE == srcFmt ) { 260 // LUM -> Fmt Conversion 261 switch(dstFmt) { 262 case LUMINANCE: 263 b1 = rescaleComp(srcComp, 0, dstComp, 0, lum___valF); 264 b2 = undef_val; 265 b3 = undef_val; 266 b4 = undef_val; 267 break; 268 case RGB565: 269 case BGR565: 270 u16 = dstComp.encode3CompI8( 271 rescaleComp(srcComp, 0, dstComp, 0, lum___valF), 272 rescaleComp(srcComp, 0, dstComp, 1, lum___valF), 273 rescaleComp(srcComp, 0, dstComp, 2, lum___valF)); 274 b1 = (byte)( u16 & 0xff ); 275 b2 = (byte)( ( u16 >>> 8 ) & 0xff ); 276 b3 = undef_val; 277 b4 = undef_val; 278 break; 279 case RGBA5551: 280 u16 = dstComp.encode4CompI8( 281 rescaleComp(srcComp, 0, dstComp, 0, lum___valF), 282 rescaleComp(srcComp, 0, dstComp, 1, lum___valF), 283 rescaleComp(srcComp, 0, dstComp, 2, lum___valF), 284 undef_val); 285 b1 = (byte)( u16 & 0xff ); 286 b2 = (byte)( ( u16 >>> 8 ) & 0xff ); 287 b3 = undef_val; 288 b4 = undef_val; 289 break; 290 case ABGR1555: 291 u16 = dstComp.encode4CompI8( 292 undef_val, 293 rescaleComp(srcComp, 0, dstComp, 0, lum___valF), 294 rescaleComp(srcComp, 0, dstComp, 1, lum___valF), 295 rescaleComp(srcComp, 0, dstComp, 2, lum___valF) ); 296 b1 = (byte)( u16 & 0xff ); 297 b2 = (byte)( ( u16 >>> 8 ) & 0xff ); 298 b3 = undef_val; 299 b4 = undef_val; 300 break; 301 case BGRx8888: 302 case RGBx8888: 303 case RGB888: 304 case BGR888: 305 case RGBA8888: 306 b1 = rescaleComp(srcComp, 0, dstComp, 0, lum___valF); 307 b2 = rescaleComp(srcComp, 0, dstComp, 1, lum___valF); 308 b3 = rescaleComp(srcComp, 0, dstComp, 2, lum___valF); 309 b4 = undef_val; 310 break; 311 case ABGR8888: 312 case ARGB8888: 313 b1 = undef_val; 314 b2 = rescaleComp(srcComp, 0, dstComp, 1, lum___valF); 315 b3 = rescaleComp(srcComp, 0, dstComp, 2, lum___valF); 316 b4 = rescaleComp(srcComp, 0, dstComp, 3, lum___valF); 317 break; 318 case BGRA8888: 319 b1 = rescaleComp(srcComp, 0, dstComp, 0, lum___valF); 320 b2 = rescaleComp(srcComp, 0, dstComp, 1, lum___valF); 321 b3 = rescaleComp(srcComp, 0, dstComp, 2, lum___valF); 322 b4 = undef_val; 323 break; 324 default: 325 throw new InternalError("Unhandled format "+dstFmt); 326 } 327 } else { 328 final int srcIdxR = srcComp.find(CType.R); 329 final int srcIdxG = srcComp.find(CType.G); 330 final int srcIdxB = srcComp.find(CType.B); 331 final int srcIdxA = srcComp.find(CType.A); 332 final boolean srcHasAlpha = 0 <= srcIdxA; 333 final boolean srcHasRGB = 0 <= srcIdxR && 0 <= srcIdxG && 0 <= srcIdxB; 334 // 1:1 values 335 switch(dstFmt) { 336 case LUMINANCE: 337 if( srcHasRGB ) { 338 final float rF = sourceNorm(srcComp, srcIdxR, red___valF); 339 final float gF = sourceNorm(srcComp, srcIdxG, green_valF); 340 final float bF = sourceNorm(srcComp, srcIdxB, blue__valF); 341 b1 = (byte)dstComp.fromFloat( ( rF + gF + bF ) / 3f, 0, false); 342 b2 = undef_val; 343 b3 = undef_val; 344 b4 = undef_val; 345 } else { 346 b1 = rescaleComp(srcComp, 0, dstComp, 0, red___valF); 347 b2 = undef_val; 348 b3 = undef_val; 349 b4 = undef_val; 350 } 351 break; 352 case RGB565: 353 u16 = dstComp.encode3CompI8( 354 rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF), 355 rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF), 356 rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF)); 357 b1 = (byte)( u16 & 0xff ); 358 b2 = (byte)( ( u16 >>> 8 ) & 0xff ); 359 b3 = undef_val; 360 b4 = undef_val; 361 break; 362 case BGR565: 363 u16 = dstComp.encode3CompI8( 364 rescaleComp(srcComp, srcIdxB, dstComp, 0, blue__valF), 365 rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF), 366 rescaleComp(srcComp, srcIdxR, dstComp, 2, red___valF)); 367 b1 = (byte)( u16 & 0xff ); 368 b2 = (byte)( ( u16 >>> 8 ) & 0xff ); 369 b3 = undef_val; 370 b4 = undef_val; 371 break; 372 case RGBA5551: 373 u16 = dstComp.encode4CompI8( 374 rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF), 375 rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF), 376 rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF), 377 srcHasAlpha ? rescaleComp(srcComp, srcIdxA, dstComp, 3, alpha_valF) : undef_val); 378 b1 = (byte)( u16 & 0xff ); 379 b2 = (byte)( ( u16 >>> 8 ) & 0xff ); 380 b3 = undef_val; 381 b4 = undef_val; 382 break; 383 case ABGR1555: 384 u16 = dstComp.encode4CompI8( 385 srcHasAlpha ? rescaleComp(srcComp, srcIdxA, dstComp, 0, alpha_valF) : undef_val, 386 rescaleComp(srcComp, srcIdxB, dstComp, 1, blue__valF), 387 rescaleComp(srcComp, srcIdxG, dstComp, 2, green_valF), 388 rescaleComp(srcComp, srcIdxR, dstComp, 3, red___valF) ); 389 b1 = (byte)( u16 & 0xff ); 390 b2 = (byte)( ( u16 >>> 8 ) & 0xff ); 391 b3 = undef_val; 392 b4 = undef_val; 393 break; 394 case RGBx8888: 395 case RGB888: 396 b1 = rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF); 397 b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF); 398 b3 = rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF); 399 b4 = undef_val; 400 break; 401 case BGRx8888: 402 case BGR888: 403 b1 = rescaleComp(srcComp, srcIdxB, dstComp, 0, blue__valF); 404 b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF); 405 b3 = rescaleComp(srcComp, srcIdxR, dstComp, 2, red___valF); 406 b4 = undef_val; 407 break; 408 case RGBA8888: 409 b1 = rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF); 410 b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF); 411 b3 = rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF); 412 if( srcHasAlpha ) { 413 b4 = rescaleComp(srcComp, srcIdxA, dstComp, 3, alpha_valF); 414 } else { 415 b4 = undef_val; 416 } 417 break; 418 case ABGR8888: 419 if( srcHasAlpha ) { 420 b1 = rescaleComp(srcComp, srcIdxA, dstComp, 0, alpha_valF); 421 } else { 422 b1 = undef_val; 423 } 424 b2 = rescaleComp(srcComp, srcIdxB, dstComp, 1, blue__valF); 425 b3 = rescaleComp(srcComp, srcIdxG, dstComp, 2, green_valF); 426 b4 = rescaleComp(srcComp, srcIdxR, dstComp, 3, red___valF); 427 break; 428 case BGRA8888: 429 b1 = rescaleComp(srcComp, srcIdxB, dstComp, 0, blue__valF); 430 b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF); 431 b3 = rescaleComp(srcComp, srcIdxR, dstComp, 2, red___valF); 432 if( srcHasAlpha ) { 433 b4 = rescaleComp(srcComp, srcIdxA, dstComp, 3, alpha_valF); 434 } else { 435 b4 = undef_val; 436 } 437 break; 438 case ARGB8888: 439 if( srcHasAlpha ) { 440 b1 = rescaleComp(srcComp, srcIdxA, dstComp, 0, alpha_valF); 441 } else { 442 b1 = undef_val; 443 } 444 b2 = rescaleComp(srcComp, srcIdxR, dstComp, 1, red___valF); 445 b3 = rescaleComp(srcComp, srcIdxG, dstComp, 2, green_valF); 446 b4 = rescaleComp(srcComp, srcIdxB, dstComp, 3, blue__valF); 447 break; 448 default: 449 throw new InternalError("Unhandled format "+dstFmt); 450 } 451 } 452 components[0] = b1; 453 components[1] = b2; 454 components[2] = b3; 455 components[3] = b4; 456 } testConversionImpl(final int srcMinStrideInBytes, final ByteOrder srcByteOrder, final boolean srcIsGLOriented, final int destMinStrideInBytes, final boolean destIsGLOriented)457 private void testConversionImpl(final int srcMinStrideInBytes, final ByteOrder srcByteOrder, final boolean srcIsGLOriented, 458 final int destMinStrideInBytes, final boolean destIsGLOriented) 459 throws InterruptedException, IOException, MalformedURLException 460 { 461 System.err.println("Test00: srcMinStrideInBytes "+srcMinStrideInBytes+", srcByteOrder "+srcByteOrder+", srcIsGLOriented "+srcIsGLOriented+ 462 ", destMinStrideInBytes "+destMinStrideInBytes+", destIsGLOriented "+destIsGLOriented); 463 464 // final PixelFormat[] srcFormats = { PixelFormat.LUMINANCE }; 465 // final PixelFormat[] dstFormats = { PixelFormat.RGBx8888 }; 466 // final PixelFormat[] dstFormats = { PixelFormat.RGB5551 }; 467 // final PixelFormat[] dstFormats = { PixelFormat.RGB888 }; 468 // final PixelFormat[] srcFormats = { PixelFormat.RGB888 }; 469 // final PixelFormat[] dstFormats = { PixelFormat.RGB565 }; 470 final PixelFormat[] srcFormats = PixelFormat.values(); 471 final PixelFormat[] dstFormats = PixelFormat.values(); 472 final int width = 64, height = 64; 473 474 for(int i=0; i<srcFormats.length; i++) { 475 final PixelFormat srcFmt = srcFormats[i]; 476 final int srcBpp = srcFmt.comp.bytesPerPixel(); 477 final int srcStrideBytes = Math.max(srcMinStrideInBytes, width*srcBpp); 478 final ByteBuffer srcPixels = ByteBuffer.allocate(height*srcStrideBytes).order(srcByteOrder); 479 final byte[] srcData = new byte[4]; 480 getComponentData(srcFmt, srcFmt, srcData); 481 for(int y=0; y<height; y++) { 482 int o = y*srcStrideBytes; 483 for(int x=0; x<width; x++) { 484 switch(srcFmt) { 485 case LUMINANCE: 486 srcPixels.put(o++, srcData[0]); 487 break; 488 case BGR565: 489 case RGB565: 490 case ABGR1555: 491 case RGBA5551: 492 srcPixels.put(o++, srcData[0]); 493 srcPixels.put(o++, srcData[1]); 494 break; 495 case RGB888: 496 case BGR888: 497 srcPixels.put(o++, srcData[0]); 498 srcPixels.put(o++, srcData[1]); 499 srcPixels.put(o++, srcData[2]); 500 break; 501 case RGBx8888: 502 case BGRx8888: 503 case RGBA8888: 504 case ABGR8888: 505 case BGRA8888: 506 case ARGB8888: 507 srcPixels.put(o++, srcData[0]); 508 srcPixels.put(o++, srcData[1]); 509 srcPixels.put(o++, srcData[2]); 510 srcPixels.put(o++, srcData[3]); 511 break; 512 default: 513 throw new InternalError("Unhandled format "+srcFmt); 514 } 515 } 516 } 517 final PixelRectangle imageSrc = new PixelRectangle.GenericPixelRect(srcFmt, new Dimension(width, height), 518 srcStrideBytes, srcIsGLOriented, srcPixels); 519 520 System.err.println("CONVERT["+i+"][*]: Image0 - Orig: "+imageSrc); 521 System.err.printf("Source %s, %s%n", srcFmt, srcFmt.comp); 522 System.err.printf("Source Data: %s%n", Bitstream.toHexBinString(true, srcData, 0, srcFmt.comp.bytesPerPixel())); 523 testComponents(imageSrc, 0, 0, srcData, 0); 524 testComponents(imageSrc, width-1, height-1, srcData, 0); 525 526 final int maxDelta = 12; 527 528 for(int j=0; j<dstFormats.length; j++) { 529 final PixelFormat destFmt = dstFormats[j]; 530 System.err.println("CONVERT["+i+"]["+j+"]: "+srcFmt+" -> "+destFmt); 531 final int destStrideBytes = Math.max(destMinStrideInBytes, width*destFmt.comp.bytesPerPixel()); 532 final byte[] destComponents = new byte[4]; 533 getComponentData(srcFmt, destFmt, destComponents); 534 System.err.printf("Source %s, %s%n", srcFmt, srcFmt.comp); 535 System.err.printf("Source Data: %s%n", Bitstream.toHexBinString(true, srcData, 0, srcFmt.comp.bytesPerPixel())); 536 System.err.printf("Dest %s, %s%n", destFmt, destFmt.comp); 537 System.err.printf("Dest Data: %s%n", Bitstream.toHexBinString(true, destComponents, 0, destFmt.comp.bytesPerPixel())); 538 final PixelRectangle imageConv1 = PixelFormatUtil.convert(imageSrc, destFmt, destStrideBytes, destIsGLOriented, false /* nio */); 539 System.err.println("CONVERT["+i+"]["+j+"]: Conv1: "+imageConv1+", maxDelta "+maxDelta); 540 System.err.printf("Conv1 Data: %s%n", Bitstream.toHexBinString(true, imageConv1.getPixels(), 0, destFmt.comp.bytesPerPixel())); 541 testComponents(imageConv1, 0, 0, destComponents, maxDelta); 542 testComponents(imageConv1, width-1, height-1, destComponents, maxDelta); 543 if( PixelFormat.LUMINANCE != srcFmt && PixelFormat.LUMINANCE == destFmt ) { 544 // Cannot convert: RGB* -> LUM -> RGB* 545 System.err.println("CONVERT["+i+"]["+j+"]: Conv2: Dropped due to RGB* -> LUM"); 546 } else if( srcFmt.comp.componentCount() > destFmt.comp.componentCount() ) { 547 // Cannot convert back if: src.componentCount > dest.componentCount 548 System.err.println("CONVERT["+i+"]["+j+"]: Conv2: Dropped due to src.componentCount > dest.componentCount"); 549 } else { 550 final PixelRectangle imageConv2 = PixelFormatUtil.convert(imageConv1, imageSrc.getPixelformat(), imageSrc.getStride(), imageSrc.isGLOriented(), false /* nio */); 551 System.err.println("CONVERT["+i+"]["+j+"]: Conv2: "+imageConv2+", maxDelta "+maxDelta); 552 System.err.printf("Conv2 Data: %s%n", Bitstream.toHexBinString(true, imageConv2.getPixels(), 0, srcFmt.comp.bytesPerPixel())); 553 final byte[] destReComponents = new byte[4]; 554 getComponentData(destFmt, srcFmt, destReComponents); 555 System.err.printf("DestRe Data: %s%n", Bitstream.toHexBinString(true, destReComponents, 0, srcFmt.comp.bytesPerPixel())); 556 testComponents(imageConv2, 0, 0, destReComponents, maxDelta); 557 testComponents(imageConv2, width-1, height-1, destReComponents, maxDelta); 558 /** 559 * Due to 'dead' components or value range re-scale, 560 * identity comparison on byte level is not correct. 561 * 562 if( imageSrc.getStride() == imageConv1.getStride() ) { 563 Assert.assertEquals(imageSrc.getPixels(), imageConv2.getPixels()); 564 } 565 */ 566 } 567 } 568 } 569 } dumpComponents(final PixelRectangle image, int x1, int y1, final int w, final int h)570 static void dumpComponents(final PixelRectangle image, int x1, int y1, final int w, final int h) { 571 if( x1 + w >= image.getSize().getWidth() ) { 572 x1 = image.getSize().getWidth() - w; 573 } 574 if( y1 + h >= image.getSize().getHeight() ) { 575 y1 = image.getSize().getHeight() - h; 576 } 577 System.err.print("PixelsBytes "+x1+"/"+y1+" "+w+"x"+h+":"); 578 final ByteBuffer bb = image.getPixels(); 579 final int bpp = image.getPixelformat().comp.bytesPerPixel(); 580 for(int y = y1; y< y1+h; y++) { 581 System.err.printf("%n[%3d][%3d] ", x1, y); 582 int o = y * image.getStride()+x1*bpp; 583 for(int x = x1; x< x1+w; x++) { 584 switch(bpp) { 585 case 1: { 586 final byte a = bb.get(o++); 587 System.err.printf(" 0x%02X", a); 588 } 589 break; 590 case 2: { 591 final byte a = bb.get(o++), b = bb.get(o++); 592 System.err.printf(" 0x%02X%02X", b, a); 593 } 594 break; 595 case 3: { 596 final byte a = bb.get(o++), b = bb.get(o++), c = bb.get(o++); 597 System.err.printf(" 0x%02X%02X%02X", c, b, a); 598 } 599 break; 600 case 4: { 601 final byte a = bb.get(o++), b = bb.get(o++), c = bb.get(o++), d = bb.get(o++); 602 System.err.printf(" 0x%02X%02X%02X%02X", d, c, b, a); 603 } 604 break; 605 } 606 } 607 } 608 System.err.println(); 609 } 610 assertEquals(final int a, final int b, final int maxDelta)611 static final void assertEquals(final int a, final int b, final int maxDelta) { 612 final int d = Math.abs( a - b ); 613 Assert.assertTrue(String.format("Not equal: abs(%s - %s) = %d, > %d maxDelta", 614 Bitstream.toHexBinString(true, a, 8), Bitstream.toHexBinString(true, b, 8), d, maxDelta), 615 d <= maxDelta); 616 } equals(final int a, final int b, final int maxDelta)617 static final boolean equals(final int a, final int b, final int maxDelta) { 618 final int d = Math.abs( a - b ); 619 return d <= maxDelta; 620 } 621 622 /** 623 * 624 * @param image actual data 625 * @param x position in actual data 626 * @param y position in actual data 627 * @param expData expected data 628 * @param maxDelta the maximum delta between expected {@code components} and actual {@code image} data 629 */ testComponents(final PixelRectangle image, final int x, final int y, final byte[] expData, final int maxDelta)630 static void testComponents(final PixelRectangle image, final int x, final int y, final byte[] expData, final int maxDelta) { 631 dumpComponents(image, x, y, 3, 3); 632 final PixelFormat.Composition imgComp = image.getPixelformat().comp; 633 final ByteBuffer bb = image.getPixels(); 634 final int bytesPerPixel = imgComp.bytesPerPixel(); 635 final int compCount = imgComp.componentCount(); 636 final int[] compBitCount = imgComp.componentBitCount(); 637 638 final int srcPixOffset = y * image.getStride()+x*bytesPerPixel; 639 final int bbPos = bb.position(); 640 bb.position(bbPos+srcPixOffset); 641 642 final long srcPix64 = PixelFormatUtil.getShiftedI64(imgComp.bytesPerPixel(), bb, true); 643 final int[] srcComponents = new int[compCount]; 644 final long expPix64 = PixelFormatUtil.getShiftedI64(imgComp.bytesPerPixel(), expData, 0); 645 final int[] expComponents = new int[compCount]; 646 boolean equal = true; 647 for(int i=0; i<compCount; i++) { 648 srcComponents[i] = imgComp.decodeSingleI64(srcPix64, i); 649 expComponents[i] = imgComp.decodeSingleI64(expPix64, i); 650 equal = equal && equals(srcComponents[i], expComponents[i], maxDelta); 651 } 652 System.err.printf("Test [%3d][%3d] exp ", x, y); 653 for(int i=0; i<compCount; i++) { System.err.printf("%s ", Bitstream.toHexBinString(true, expComponents[i], compBitCount[i])); } 654 System.err.printf("==%nTest [%3d][%3d] has ", x, y); 655 for(int i=0; i<compCount; i++) { System.err.printf("%s ", Bitstream.toHexBinString(true, srcComponents[i], compBitCount[i])); } 656 System.err.printf(": equal %b%n%n", equal); 657 for(int i=0; i<compCount; i++) { 658 assertEquals(srcComponents[i], expComponents[i], maxDelta); 659 } 660 661 bb.position(bbPos); 662 } 663 main(final String args[])664 public static void main(final String args[]) { 665 org.junit.runner.JUnitCore.main(TestPixelFormatUtil00NEWT.class.getName()); 666 } 667 } 668