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