JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
PixelFormatUtil.java
Go to the documentation of this file.
1/**
2 * Copyright (c) 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 */
28package com.jogamp.nativewindow.util;
29
30import java.io.IOException;
31import java.nio.ByteBuffer;
32import java.util.Arrays;
33
34import com.jogamp.common.nio.Buffers;
35import com.jogamp.common.util.Bitstream;
36
37/**
38 * Pixel Rectangle Utilities.
39 * <p>
40 * All conversion methods are endian independent.
41 * </p>
42 */
43public class PixelFormatUtil {
44 private static boolean DEBUG = false;
45
46 public static class ComponentMap {
47 /**
48 * Contains the source index for each destination index,
49 * length is {@link Composition#componentCount()} of destination.
50 */
51 final int[] dst2src;
52 /**
53 * Contains the destination index for each source index,
54 * length is {@link Composition#componentCount()} of source.
55 */
56 final int[] src2dst;
57
58 /**
59 * Contains the source index of RGBA components.
60 */
61 final int[] srcRGBA;
62 final boolean hasSrcRGB;
63
65 final int sCompCount = src.componentCount();
66 final int dCompCount = dst.componentCount();
67 final PixelFormat.CType[] sCompOrder = src.componentOrder();
68 final PixelFormat.CType[] dCompOrder = dst.componentOrder();
69
70 dst2src = new int[dCompCount];
71 for(int dIdx=0; dIdx<dCompCount; dIdx++) {
72 dst2src[dIdx] = PixelFormatUtil.find(dCompOrder[dIdx], sCompOrder, true);
73 }
74 src2dst = new int[sCompCount];
75 for(int sIdx=0; sIdx<sCompCount; sIdx++) {
76 src2dst[sIdx] = PixelFormatUtil.find(sCompOrder[sIdx], dCompOrder, true);
77 }
78 srcRGBA = new int[4];
79 srcRGBA[0] = PixelFormatUtil.find(PixelFormat.CType.R, sCompOrder, false);
80 srcRGBA[1] = PixelFormatUtil.find(PixelFormat.CType.G, sCompOrder, false);
81 srcRGBA[2] = PixelFormatUtil.find(PixelFormat.CType.B, sCompOrder, false);
82 srcRGBA[3] = PixelFormatUtil.find(PixelFormat.CType.A, sCompOrder, false);
83 hasSrcRGB = 0 <= srcRGBA[0] && 0 <= srcRGBA[1] && 0 <= srcRGBA[2];
84 }
85 }
86
87 public static final int find(final PixelFormat.CType s,
88 final PixelFormat.CType[] pool, final boolean mapRGB2Y) {
89 int i=pool.length-1;
90 while( i >= 0 && pool[i] != s) { i--; }
91
92 if( 0 > i && mapRGB2Y && 1 == pool.length && pool[0] == PixelFormat.CType.Y &&
93 ( PixelFormat.CType.R == s ||
94 PixelFormat.CType.G == s ||
95 PixelFormat.CType.B == s ) )
96 {
97 // Special case, fallback for RGB mapping -> LUMINANCE/Y
98 return 0;
99 } else {
100 return i;
101 }
102 }
103
104 /**
105 * Returns shifted bytes from the given {@code data} at given {@code offset}
106 * of maximal 4 {@code bytesPerPixel}.
107 * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
108 * @param data byte buffer covering complete pixel at position {@code offset}
109 * @param offset byte offset of pixel {@code data} start
110 * @return the shifted 32bit integer value of the pixel
111 */
112 public static int getShiftedI32(final int bytesPerPixel, final byte[] data, final int offset) {
113 if( bytesPerPixel <= 4 ) {
114 int shiftedI32 = 0;
115 for(int i=0; i<bytesPerPixel; i++) {
116 shiftedI32 |= ( 0xff & data[offset+i] ) << 8*i;
117 }
118 return shiftedI32;
119 } else {
120 throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 4");
121 }
122 }
123 /**
124 * Returns shifted bytes from the given {@code data} at given {@code offset}
125 * of maximal 8 {@code bytesPerPixel}.
126 * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
127 * @param data byte buffer covering complete pixel at position {@code offset}
128 * @param offset byte offset of pixel {@code data} start
129 * @return the shifted 64bit integer value of the pixel
130 */
131 public static long getShiftedI64(final int bytesPerPixel, final byte[] data, final int offset) {
132 if( bytesPerPixel <= 8 ) {
133 long shiftedI64 = 0;
134 for(int i=0; i<bytesPerPixel; i++) {
135 shiftedI64 |= ( 0xff & data[offset+i] ) << 8*i;
136 }
137 return shiftedI64;
138 } else {
139 throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 8");
140 }
141 }
142 /**
143 * Returns shifted bytes from the given {@code data} at current position
144 * of maximal 4 {@code bytesPerPixel}.
145 * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
146 * @param data byte buffer covering complete pixel at position {@code offset}
147 * @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged.
148 * Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes.
149 * @return the shifted 32bit integer value of the pixel
150 */
151 public static int getShiftedI32(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) {
152 if( bytesPerPixel <= 4 ) {
153 int shiftedI32 = 0;
154 if( retainDataPos ) {
155 final int offset = data.position();
156 for(int i=0; i<bytesPerPixel; i++) {
157 shiftedI32 |= ( 0xff & data.get(offset+i) ) << 8*i;
158 }
159 } else {
160 for(int i=0; i<bytesPerPixel; i++) {
161 shiftedI32 |= ( 0xff & data.get() ) << 8*i;
162 }
163 }
164 return shiftedI32;
165 } else {
166 throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 4");
167 }
168 }
169 /**
170 * Returns shifted bytes from the given {@code data} at current position
171 * of maximal 8 {@code bytesPerPixel}.
172 * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed
173 * @param data byte buffer covering complete pixel at position {@code offset}
174 * @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged.
175 * Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes.
176 * @return the shifted 64bit integer value of the pixel
177 */
178 public static long getShiftedI64(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) {
179 if( bytesPerPixel <= 8 ) {
180 long shiftedI64 = 0;
181 if( retainDataPos ) {
182 final int offset = data.position();
183 for(int i=0; i<bytesPerPixel; i++) {
184 shiftedI64 |= ( 0xff & data.get(offset+i) ) << 8*i;
185 }
186 } else {
187 for(int i=0; i<bytesPerPixel; i++) {
188 shiftedI64 |= ( 0xff & data.get() ) << 8*i;
189 }
190 }
191 return shiftedI64;
192 } else {
193 throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 8");
194 }
195 }
196
197 /**
198 * Returns the {@link PixelFormat} with reversed components of <code>fmt</code>.
199 * If no reversed {@link PixelFormat} is available, returns <code>fmt</code>.
200 */
201 public static PixelFormat getReversed(final PixelFormat fmt) {
202 switch(fmt) {
203 case RGB565:
204 return PixelFormat.BGR565;
205 case BGR565:
206 return PixelFormat.RGB565;
207 case RGBA5551:
208 return PixelFormat.ABGR1555;
209 case ABGR1555:
210 return PixelFormat.RGBA5551;
211 case RGB888:
212 return PixelFormat.BGR888;
213 case BGR888:
214 return PixelFormat.RGB888;
215 case RGBA8888:
216 return PixelFormat.ABGR8888;
217 case ABGR8888:
218 return PixelFormat.RGBA8888;
219 case ARGB8888:
220 return PixelFormat.BGRA8888;
221 case BGRA8888:
222 return PixelFormat.ABGR8888;
223 default:
224 return fmt;
225 }
226 }
227
228 public static int convertToInt32(final PixelFormat dst_fmt, final byte r, final byte g, final byte b, final byte a) {
229 switch(dst_fmt) {
230 case LUMINANCE: {
231 final byte l = ( byte) ( ( ( ( 0xff & r ) + ( 0xff & g ) + ( 0xff & b ) ) / 3 ) * a );
232 return ( 0xff ) << 24 | ( 0xff & l ) << 16 | ( 0xff & l ) << 8 | ( 0xff & l );
233 }
234 case RGB888:
235 return ( 0xff ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r );
236 case BGR888:
237 return ( 0xff ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b );
238 case RGBA8888:
239 return ( 0xff & a ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r );
240 case ABGR8888:
241 return ( 0xff & r ) << 24 | ( 0xff & g ) << 16 | ( 0xff & b ) << 8 | ( 0xff & a );
242 case ARGB8888:
243 return ( 0xff & b ) << 24 | ( 0xff & g ) << 16 | ( 0xff & r ) << 8 | ( 0xff & a );
244 case BGRA8888:
245 return ( 0xff & a ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b );
246 default:
247 throw new InternalError("Unhandled format "+dst_fmt);
248 }
249 }
250
251 public static int convertToInt32(final PixelFormat dst_fmt, final PixelFormat src_fmt, final ByteBuffer src, int srcOff) {
252 final byte r, g, b, a;
253 switch(src_fmt) {
254 case LUMINANCE:
255 r = src.get(srcOff++); // R
256 g = r; // G
257 b = r; // B
258 a = (byte) 0xff; // A
259 break;
260 case RGB888:
261 r = src.get(srcOff++); // R
262 g = src.get(srcOff++); // G
263 b = src.get(srcOff++); // B
264 a = (byte) 0xff; // A
265 break;
266 case BGR888:
267 b = src.get(srcOff++); // B
268 g = src.get(srcOff++); // G
269 r = src.get(srcOff++); // R
270 a = (byte) 0xff; // A
271 break;
272 case RGBA8888:
273 r = src.get(srcOff++); // R
274 g = src.get(srcOff++); // G
275 b = src.get(srcOff++); // B
276 a = src.get(srcOff++); // A
277 break;
278 case ABGR8888:
279 a = src.get(srcOff++); // A
280 b = src.get(srcOff++); // B
281 g = src.get(srcOff++); // G
282 r = src.get(srcOff++); // R
283 break;
284 case ARGB8888:
285 a = src.get(srcOff++); // A
286 r = src.get(srcOff++); // R
287 g = src.get(srcOff++); // G
288 b = src.get(srcOff++); // B
289 break;
290 case BGRA8888:
291 b = src.get(srcOff++); // B
292 g = src.get(srcOff++); // G
293 r = src.get(srcOff++); // R
294 a = src.get(srcOff++); // A
295 break;
296 default:
297 throw new InternalError("Unhandled format "+src_fmt);
298 }
299 return convertToInt32(dst_fmt, r, g, b, a);
300 }
301
302 public static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final int src_pixel) {
303 final byte r, g, b, a;
304 switch(src_fmt) {
305 case LUMINANCE:
306 r = (byte) ( src_pixel ); // R
307 g = r; // G
308 b = r; // B
309 a = (byte) 0xff; // A
310 break;
311 case RGB888:
312 r = (byte) ( src_pixel ); // R
313 g = (byte) ( src_pixel >>> 8 ); // G
314 b = (byte) ( src_pixel >>> 16 ); // B
315 a = (byte) 0xff; // A
316 break;
317 case BGR888:
318 b = (byte) ( src_pixel ); // B
319 g = (byte) ( src_pixel >>> 8 ); // G
320 r = (byte) ( src_pixel >>> 16 ); // R
321 a = (byte) 0xff; // A
322 break;
323 case RGBA8888:
324 r = (byte) ( src_pixel ); // R
325 g = (byte) ( src_pixel >>> 8 ); // G
326 b = (byte) ( src_pixel >>> 16 ); // B
327 a = (byte) ( src_pixel >>> 24 ); // A
328 break;
329 case ABGR8888:
330 a = (byte) ( src_pixel ); // A
331 b = (byte) ( src_pixel >>> 8 ); // B
332 g = (byte) ( src_pixel >>> 16 ); // G
333 r = (byte) ( src_pixel >>> 24 ); // R
334 break;
335 case ARGB8888:
336 a = (byte) ( src_pixel ); // A
337 r = (byte) ( src_pixel >>> 8 ); // R
338 g = (byte) ( src_pixel >>> 16 ); // G
339 b = (byte) ( src_pixel >>> 24 ); // B
340 break;
341 case BGRA8888:
342 b = (byte) ( src_pixel ); // B
343 g = (byte) ( src_pixel >>> 8 ); // G
344 r = (byte) ( src_pixel >>> 16 ); // R
345 a = (byte) ( src_pixel >>> 24 ); // A
346 break;
347 default:
348 throw new InternalError("Unhandled format "+src_fmt);
349 }
350 return convertToInt32(dest_fmt, r, g, b, a);
351 }
352
353 public static PixelRectangle convert(final PixelRectangle src,
354 final PixelFormat destFmt, final int ddestStride, final boolean isGLOriented,
355 final boolean destIsDirect) {
356 final int width = src.getSize().getWidth();
357 final int height = src.getSize().getHeight();
358 final int bpp = destFmt.comp.bytesPerPixel();
359 final int destStride;
360 if( 0 != ddestStride ) {
361 destStride = ddestStride;
362 } else {
363 destStride = bpp * width;
364 }
365 final int capacity = destStride*height;
366 final ByteBuffer destBB = destIsDirect ? Buffers.newDirectByteBuffer(capacity) : ByteBuffer.allocate(capacity).order(src.getPixels().order());
367 convert(src, destBB, destFmt, isGLOriented, destStride);
368 return new PixelRectangle.GenericPixelRect(destFmt, src.getSize(), destStride, isGLOriented, destBB);
369 }
370
371 /**
372 * @param src
373 * @param dst_bb {@link ByteBuffer} sink
374 * @param dst_fmt destination {@link PixelFormat}
375 * @param dst_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>,
376 * otherwise <i>origin at top left</i>.
377 * @param dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next.
378 * Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width
379 * or {@code zero} for default stride.
380 *
381 * @throws IllegalStateException
382 * @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid
383 */
384 public static void convert(final PixelRectangle src,
385 final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, final int dst_lineStride)
386 throws IllegalStateException
387 {
388 convert(src.getSize().getWidth(), src.getSize().getHeight(),
389 src.getPixels(), src.getPixelformat(), src.isGLOriented(), src.getStride(),
390 dst_bb, dst_fmt, dst_glOriented, dst_lineStride);
391 }
392
393
394 /**
395 * @param width width of the to be converted pixel rectangle
396 * @param height height of the to be converted pixel rectangle
397 * @param src_bb {@link ByteBuffer} source
398 * @param src_fmt source {@link PixelFormat}
399 * @param src_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>,
400 * otherwise <i>origin at top left</i>.
401 * @param src_lineStride line stride in byte-size for source, i.e. byte count from one line to the next.
402 * Must be >= {@link PixelFormat.Composition#bytesPerPixel() src_fmt.comp.bytesPerPixel()} * width
403 * or {@code zero} for default stride.
404 * @param dst_bb {@link ByteBuffer} sink
405 * @param dst_fmt destination {@link PixelFormat}
406 * @param dst_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>,
407 * otherwise <i>origin at top left</i>.
408 * @param dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next.
409 * Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width
410 * or {@code zero} for default stride.
411 *
412 * @throws IllegalStateException
413 * @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid
414 */
415 public static void convert(final int width, final int height,
416 final ByteBuffer src_bb, final PixelFormat src_fmt, final boolean src_glOriented, int src_lineStride,
417 final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, int dst_lineStride
418 ) throws IllegalStateException, IllegalArgumentException {
419 final PixelFormat.Composition src_comp = src_fmt.comp;
420 final PixelFormat.Composition dst_comp = dst_fmt.comp;
421 final int src_bpp = src_comp.bytesPerPixel();
422 final int dst_bpp = dst_comp.bytesPerPixel();
423
424 if( 0 != src_lineStride ) {
425 if( src_lineStride < src_bpp * width ) {
426 throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d",
427 "source", src_lineStride, src_bpp, width));
428 }
429 } else {
430 src_lineStride = src_bpp * width;
431 }
432 if( 0 != dst_lineStride ) {
433 if( dst_lineStride < dst_bpp * width ) {
434 throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d",
435 "destination", dst_lineStride, dst_bpp, width));
436 }
437 } else {
438 dst_lineStride = dst_bpp * width;
439 }
440
441 // final int src_comp_bitStride = src_comp.bitStride();
442 final int dst_comp_bitStride = dst_comp.bitStride();
443 final boolean vert_flip = src_glOriented != dst_glOriented;
444 final boolean fast_copy = src_comp.equals(dst_comp) && 0 == dst_comp_bitStride%8;
445 if( DEBUG ) {
446 System.err.println("XXX: size "+width+"x"+height+", fast_copy "+fast_copy);
447 System.err.println("XXX: SRC fmt "+src_fmt+", "+src_comp+", stride "+src_lineStride+", isGLOrient "+src_glOriented);
448 System.err.println("XXX: DST fmt "+dst_fmt+", "+dst_comp+", stride "+dst_lineStride+", isGLOrient "+dst_glOriented);
449 }
450
451 if( fast_copy ) {
452 // Fast copy
453 for(int y=0; y<height; y++) {
454 int src_off = vert_flip ? ( height - 1 - y ) * src_lineStride : y * src_lineStride;
455 int dst_off = dst_lineStride*y;
456 for(int x=0; x<width; x++) {
457 dst_bb.put(dst_off+0, src_bb.get(src_off+0)); // 1
458 if( 2 <= dst_bpp ) {
459 dst_bb.put(dst_off+1, src_bb.get(src_off+1)); // 2
460 if( 3 <= dst_bpp ) {
461 dst_bb.put(dst_off+2, src_bb.get(src_off+2)); // 3
462 if( 4 <= dst_bpp ) {
463 dst_bb.put(dst_off+3, src_bb.get(src_off+3)); // 4
464 }
465 }
466 }
467 src_off += src_bpp;
468 dst_off += dst_bpp;
469 }
470 }
471 } else {
472 // Conversion
473 final ComponentMap cmap = new ComponentMap(src_fmt.comp, dst_fmt.comp);
474
475 final Bitstream.ByteBufferStream srcBBS = new Bitstream.ByteBufferStream(src_bb);
476 final Bitstream<ByteBuffer> srcBitStream = new Bitstream<ByteBuffer>(srcBBS, false /* outputMode */);
477 srcBitStream.setThrowIOExceptionOnEOF(true);
478
479 final Bitstream.ByteBufferStream dstBBS = new Bitstream.ByteBufferStream(dst_bb);
480 final Bitstream<ByteBuffer> dstBitStream = new Bitstream<ByteBuffer>(dstBBS, true /* outputMode */);
481 dstBitStream.setThrowIOExceptionOnEOF(true);
482
483 if( DEBUG ) {
484 System.err.println("XXX: cmap.dst2src "+Arrays.toString(cmap.dst2src));
485 System.err.println("XXX: cmap.src2dst "+Arrays.toString(cmap.src2dst));
486 System.err.println("XXX: cmap.srcRGBA "+Arrays.toString(cmap.srcRGBA));
487 System.err.println("XXX: srcBitStream "+srcBitStream);
488 System.err.println("XXX: dstBitStream "+dstBitStream);
489 }
490 try {
491 for(int y=0; y<height; y++) {
492 final int src_off = vert_flip ? ( height - 1 - y ) * src_lineStride * 8 : y * src_lineStride * 8;
493 // final int dst_off = dst_lineStride*8*y;
494 srcBitStream.position(src_off);
495 for(int x=0; x<width; x++) {
496 convert(cmap, dst_comp, dstBitStream, src_comp, srcBitStream);
497 }
498 // srcBitStream.skip(( src_lineStride * 8 ) - ( src_comp_bitStride * width ));
499 dstBitStream.skip(( dst_lineStride * 8 ) - ( dst_comp_bitStride * width ));
500 }
501 } catch(final IOException ioe) {
502 throw new RuntimeException(ioe);
503 }
504 if( DEBUG ) {
505 System.err.println("XXX: srcBitStream "+srcBitStream);
506 System.err.println("XXX: dstBitStream "+dstBitStream);
507 }
508 }
509 }
510
511 public static void convert(final ComponentMap cmap,
512 final PixelFormat.Composition dstComp,
513 final Bitstream<ByteBuffer> dstBitStream,
514 final PixelFormat.Composition srcComp,
515 final Bitstream<ByteBuffer> srcBitStream) throws IllegalStateException, IOException {
516 final int sCompCount = srcComp.componentCount();
517 final int dCompCount = dstComp.componentCount();
518 final int[] sc = new int[sCompCount];
519 final int[] dcDef = new int[dCompCount];
520 final int[] srcCompBitCount = srcComp.componentBitCount();
521 final int[] srcCompBitMask = srcComp.componentBitMask();
522 final int[] dstCompBitCount = dstComp.componentBitCount();
523
524 // Fill w/ source values
525 for(int sIdx=0; sIdx<sCompCount; sIdx++) {
526 sc[sIdx] = srcBitStream.readBits31(srcCompBitCount[sIdx]) & srcCompBitMask[sIdx];
527 }
528 srcBitStream.skip(srcComp.bitStride() - srcComp.bitsPerPixel());
529
530 // Cache missing defaults
531 for(int i=0; i<dCompCount; i++) {
532 dcDef[i] = dstComp.defaultValue(i, false);
533 }
534
535 if( 1 == dCompCount &&
536 PixelFormat.CType.Y == dstComp.componentOrder()[0] &&
537 cmap.hasSrcRGB
538 )
539 {
540 // RGB[A] -> Y conversion
541 final int r = sc[cmap.srcRGBA[0]];
542 final int g = sc[cmap.srcRGBA[1]];
543 final int b = sc[cmap.srcRGBA[2]];
544 final float rF = srcComp.toFloat(r, cmap.srcRGBA[0], false);
545 final float gF = srcComp.toFloat(g, cmap.srcRGBA[1], false);
546 final float bF = srcComp.toFloat(b, cmap.srcRGBA[2], false);
547 final int a;
548 final float aF;
549 /** if( 0 <= cmap.srcRGBA[3] ) { // disable premultiplied-alpha
550 a = sc[cmap.srcRGBA[3]];
551 aF = srcComp.toFloat(a, false, cmap.srcRGBA[3]);
552 } else */ {
553 a = 1;
554 aF = 1f;
555 }
556 final float lF = ( rF + gF + bF ) * aF / 3f;
557 final int v = dstComp.fromFloat(lF, 0, false);
558
559 dstBitStream.writeBits31(dstCompBitCount[0], v);
560 dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel());
561 if( DEBUG ) {
562 if( srcBitStream.position() <= 8*4 ) {
563 System.err.printf("convert: rgb[a] -> Y: rgb 0x%02X 0x%02X 0x%02X 0x%02X -> %f %f %f %f"+
564 " -> %f -> dstC 0 0x%08X (%d bits: %s)%n",
565 r, g, b, a,
566 rF, gF, bF, aF,
567 lF, v, dstCompBitCount[0], Bitstream.toBinString(true, v, dstCompBitCount[0])
568 );
569 }
570 }
571 return;
572 }
573
574 for(int dIdx=0; dIdx<dCompCount; dIdx++) {
575 int sIdx;
576 if( 0 <= ( sIdx = cmap.dst2src[dIdx] ) ) {
577 final float f = srcComp.toFloat(sc[sIdx], sIdx, false);
578 final int v = dstComp.fromFloat(f, dIdx, false);
579 dstBitStream.writeBits31(dstCompBitCount[dIdx], v);
580 if( DEBUG ) {
581 if( srcBitStream.position() <= 8*4 ) {
582 System.err.printf("convert: srcC %d: 0x%08X -> %f -> dstC %d 0x%08X (%d bits: %s)%n",
583 sIdx, sc[sIdx], f, dIdx, v, dstCompBitCount[dIdx], Bitstream.toBinString(true, v, dstCompBitCount[dIdx]));
584 }
585 }
586 } else {
587 dstBitStream.writeBits31(dstCompBitCount[dIdx], dcDef[dIdx]);
588 if( DEBUG ) {
589 if( srcBitStream.position() <= 8*4 ) {
590 System.err.printf("convert: srcC %d: undef -> dstC %d 0x%08X (%d bits: %s)%n",
591 sIdx, dIdx, dcDef[dIdx], dstCompBitCount[dIdx], Bitstream.toBinString(true, dcDef[dIdx], dstCompBitCount[dIdx]));
592 }
593 }
594 }
595 }
596 dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel());
597 return;
598 }
599}
600
ComponentMap(final PixelFormat.Composition src, final PixelFormat.Composition dst)
static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final int src_pixel)
static long getShiftedI64(final int bytesPerPixel, final byte[] data, final int offset)
Returns shifted bytes from the given data at given offset of maximal 8 bytesPerPixel.
static void convert(final int width, final int height, final ByteBuffer src_bb, final PixelFormat src_fmt, final boolean src_glOriented, int src_lineStride, final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, int dst_lineStride)
static void convert(final ComponentMap cmap, final PixelFormat.Composition dstComp, final Bitstream< ByteBuffer > dstBitStream, final PixelFormat.Composition srcComp, final Bitstream< ByteBuffer > srcBitStream)
static PixelFormat getReversed(final PixelFormat fmt)
Returns the PixelFormat with reversed components of fmt.
static int convertToInt32(final PixelFormat dst_fmt, final PixelFormat src_fmt, final ByteBuffer src, int srcOff)
static void convert(final PixelRectangle src, final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, final int dst_lineStride)
static final int find(final PixelFormat.CType s, final PixelFormat.CType[] pool, final boolean mapRGB2Y)
static long getShiftedI64(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos)
Returns shifted bytes from the given data at current position of maximal 8 bytesPerPixel.
static int getShiftedI32(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos)
Returns shifted bytes from the given data at current position of maximal 4 bytesPerPixel.
static int getShiftedI32(final int bytesPerPixel, final byte[] data, final int offset)
Returns shifted bytes from the given data at given offset of maximal 4 bytesPerPixel.
static PixelRectangle convert(final PixelRectangle src, final PixelFormat destFmt, final int ddestStride, final boolean isGLOriented, final boolean destIsDirect)
static int convertToInt32(final PixelFormat dst_fmt, final byte r, final byte g, final byte b, final byte a)
BGR565
Stride is 16 bits, 16 bits per pixel, 3 discrete components.
ABGR8888
Stride is 32 bits, 32 bits per pixel, 4 uniform components of 8 bits.
BGRA8888
Stride is 32 bits, 32 bits per pixel, 4 uniform components of 8 bits.
final Composition comp
Unique Pixel Composition, i.e.
BGR888
Stride is 24 bits, 24 bits per pixel, 3 uniform components of of 8 bits.
RGBA8888
Stride is 32 bits, 32 bits per pixel, 4 uniform components of 8 bits.
RGBA5551
Stride is 16 bits, 16 bits per pixel, 4 discrete components.
RGB565
Stride is 16 bits, 16 bits per pixel, 3 discrete components.
ABGR1555
Stride is 16 bits, 16 bits per pixel, 4 discrete components.
RGB888
Stride 24 bits, 24 bits per pixel, 3 uniform components of 8 bits.
int bytesPerPixel()
Number of bytes per pixel, i.e.
Pixel Rectangle identified by it's hashCode().
DimensionImmutable getSize()
Returns the size, i.e.
ByteBuffer getPixels()
Returns the pixels.