summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-02-13 00:17:09 +0100
committerSven Gothel <[email protected]>2014-02-13 00:17:09 +0100
commit21b68a5e73a672da34b37b5641b779aa1e3fa41d (patch)
tree2b57fe8af6d317678b023a5d95155ff2a8e7de59
parent0666a9ee8332e8ab59d533c65552dae8c58cf267 (diff)
TextureIO: Support PNGTextureWriter w/ TextureData IntBuffer (via PNGPixelRect and PixelFormatUtil)
TextureData IntBuffer could be caused by AWT read-pixels but is not seamlessly supported via PNGPixelRect since the latter uses a hardcoded ByteBuffer. Add static PNGPixelRect.write(..) supporting IntBuffer to support this case for now. PNGPixelRect instances do not support any Buffer type to avoid a bloated implementation. PixelFormatUtil adds support for int32 pixel format conversion.
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java80
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java40
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java3
3 files changed, 103 insertions, 20 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java
index 1bbc12f32..fd8f54152 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java
@@ -32,6 +32,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
import javax.media.nativewindow.util.Dimension;
import javax.media.nativewindow.util.DimensionImmutable;
@@ -248,19 +249,29 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect {
}
return dOff;
}
- private int setPixelRGBA8(final ImageLine line, final int lineOff, final ByteBuffer d, final int dOff, final int bytesPerPixel, final boolean hasAlpha) {
+ private int setPixelRGBA8(final ImageLine line, final int lineOff, final ByteBuffer src, final int srcOff, final int bytesPerPixel, final boolean hasAlpha) {
final int b = hasAlpha ? 4-1 : 3-1;
- if( d.limit() <= dOff + b ) {
- throw new IndexOutOfBoundsException("Buffer has unsufficient bytes left, needs ["+dOff+".."+(dOff+b)+"]: "+d);
+ if( src.limit() <= srcOff + b ) {
+ throw new IndexOutOfBoundsException("Buffer has unsufficient bytes left, needs ["+srcOff+".."+(srcOff+b)+"]: "+src);
}
- final int p = PixelFormatUtil.convertToInt32(hasAlpha ? PixelFormat.RGBA8888 : PixelFormat.RGB888, pixelformat, d, dOff);
+ final int p = PixelFormatUtil.convertToInt32(hasAlpha ? PixelFormat.RGBA8888 : PixelFormat.RGB888, pixelformat, src, srcOff);
+ line.scanline[lineOff ] = 0xff & p; // R
+ line.scanline[lineOff + 1] = 0xff & ( p >>> 8 ); // G
+ line.scanline[lineOff + 2] = 0xff & ( p >>> 16 ); // B
+ if(hasAlpha) {
+ line.scanline[lineOff + 3] = 0xff & ( p >>> 24 ); // A
+ }
+ return srcOff + pixelformat.bytesPerPixel();
+ }
+
+ private static void setPixelRGBA8(final PixelFormat pixelformat, final ImageLine line, final int lineOff, final int srcPix, final int bytesPerPixel, final boolean hasAlpha) {
+ final int p = PixelFormatUtil.convertToInt32(hasAlpha ? PixelFormat.RGBA8888 : PixelFormat.RGB888, pixelformat, srcPix);
line.scanline[lineOff ] = 0xff & p; // R
line.scanline[lineOff + 1] = 0xff & ( p >>> 8 ); // G
line.scanline[lineOff + 2] = 0xff & ( p >>> 16 ); // B
if(hasAlpha) {
line.scanline[lineOff + 3] = 0xff & ( p >>> 24 ); // A
}
- return dOff + pixelformat.bytesPerPixel();
}
/**
@@ -304,9 +315,8 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect {
final PngWriter png = new PngWriter(outstream, imi);
// add some optional metadata (chunks)
png.getMetadata().setDpi(dpi[0], dpi[1]);
- png.getMetadata().setTimeNow(0); // 0 seconds fron now = now
+ png.getMetadata().setTimeNow(0); // 0 seconds from now = now
png.getMetadata().setText(PngChunkTextVar.KEY_Title, "JogAmp PNGPixelRect");
- // png.getMetadata().setText("my key", "my text");
final boolean hasAlpha = 4 == bytesPerPixel;
final ImageLine l1 = new ImageLine(imi);
@@ -332,4 +342,60 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect {
}
}
}
+
+ public static void write(final PixelFormat pixelformat, final DimensionImmutable size,
+ int strideInPixels, final boolean isGLOriented, final IntBuffer pixels,
+ final double dpiX, final double dpiY,
+ final OutputStream outstream, final boolean closeOutstream) throws IOException {
+ final int width = size.getWidth();
+ final int height = size.getHeight();
+ final int bytesPerPixel = pixelformat.bytesPerPixel();
+ final ImageInfo imi = new ImageInfo(width, height, 8 /* bitdepth */,
+ (4 == bytesPerPixel) ? true : false /* alpha */,
+ (1 == bytesPerPixel) ? true : false /* grayscale */,
+ false /* indexed */);
+ if( 0 != strideInPixels ) {
+ if( strideInPixels < size.getWidth()) {
+ throw new IllegalArgumentException("Invalid stride "+bytesPerPixel+", must be greater than width "+size.getWidth());
+ }
+ } else {
+ strideInPixels = size.getWidth();
+ }
+ final int reqPixels = strideInPixels * size.getHeight();
+ if( pixels.limit() < reqPixels ) {
+ throw new IndexOutOfBoundsException("Dest buffer has insufficient pixels left, needs "+reqPixels+": "+pixels);
+ }
+
+ // open image for writing to a output stream
+ try {
+ final PngWriter png = new PngWriter(outstream, imi);
+ // add some optional metadata (chunks)
+ png.getMetadata().setDpi(dpiX, dpiY);
+ png.getMetadata().setTimeNow(0); // 0 seconds from now = now
+ png.getMetadata().setText(PngChunkTextVar.KEY_Title, "JogAmp PNGPixelRect");
+ final boolean hasAlpha = 4 == bytesPerPixel;
+
+ final ImageLine l1 = new ImageLine(imi);
+ for (int row = 0; row < height; row++) {
+ int dataOff = isGLOriented ? ( height - 1 - row ) * strideInPixels : row * strideInPixels;
+ int lineOff = 0;
+ if(1 == bytesPerPixel) {
+ for (int j = width - 1; j >= 0; j--) {
+ l1.scanline[lineOff++] = pixels.get(dataOff++); // // Luminance, 1 bytesPerPixel
+ }
+ } else {
+ for (int j = width - 1; j >= 0; j--) {
+ setPixelRGBA8(pixelformat, l1, lineOff, pixels.get(dataOff++), bytesPerPixel, hasAlpha);
+ lineOff += bytesPerPixel;
+ }
+ }
+ png.writeRow(l1, row);
+ }
+ png.end();
+ } finally {
+ if( closeOutstream ) {
+ IOUtil.close(outstream, false);
+ }
+ }
+ }
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
index 0cde24db4..c29bd9af2 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java
@@ -50,11 +50,13 @@ import java.io.OutputStream;
import java.net.URL;
import java.nio.Buffer;
import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.media.nativewindow.util.Dimension;
+import javax.media.nativewindow.util.DimensionImmutable;
import javax.media.nativewindow.util.PixelFormat;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
@@ -1400,18 +1402,34 @@ public class TextureIO {
final PixelFormat pixFmt = pixelAttribs.getPixelFormat();
if ( ( 1 == bytesPerPixel || 3 == bytesPerPixel || 4 == bytesPerPixel) &&
( pixelType == GL.GL_BYTE || pixelType == GL.GL_UNSIGNED_BYTE)) {
- ByteBuffer buf = (ByteBuffer) data.getBuffer();
- if (null == buf) {
- buf = (ByteBuffer) data.getMipmapData()[0];
+ Buffer buf0 = data.getBuffer();
+ if (null == buf0) {
+ buf0 = data.getMipmapData()[0];
+ }
+ if( null == buf0 ) {
+ throw new IOException("Pixel storage buffer is null");
+ }
+ final DimensionImmutable size = new Dimension(data.getWidth(), data.getHeight());
+ if( buf0 instanceof ByteBuffer ) {
+ final ByteBuffer buf = (ByteBuffer) buf0;
+ buf.rewind();
+ final PNGPixelRect image = new PNGPixelRect(pixFmt, size,
+ 0 /* stride */, true /* isGLOriented */, buf /* pixels */,
+ -1f, -1f);
+ final OutputStream outs = new BufferedOutputStream(IOUtil.getFileOutputStream(file, true /* allowOverwrite */));
+ image.write(outs, true /* close */);
+ return true;
+ } else if( buf0 instanceof IntBuffer ) {
+ final IntBuffer buf = (IntBuffer) buf0;
+ buf.rewind();
+ final OutputStream outs = new BufferedOutputStream(IOUtil.getFileOutputStream(file, true /* allowOverwrite */));
+ PNGPixelRect.write(pixFmt, size,
+ 0 /* stride */, true /* isGLOriented */, buf /* pixels */,
+ -1f, -1f, outs, true /* closeOutstream */);
+ return true;
+ } else {
+ throw new IOException("PNG writer doesn't support pixel storage buffer of type "+buf0.getClass().getName());
}
- buf.rewind();
-
- final PNGPixelRect image = new PNGPixelRect(pixFmt, new Dimension(data.getWidth(), data.getHeight()),
- 0 /* stride */, true /* isGLOriented */, buf /* pixels */,
- -1f, -1f);
- final OutputStream outs = new BufferedOutputStream(IOUtil.getFileOutputStream(file, true /* allowOverwrite */));
- image.write(outs, true /* close */);
- return true;
}
throw new IOException("PNG writer doesn't support this pixel format 0x"+Integer.toHexString(pixelFormat)+
" / type 0x"+Integer.toHexString(pixelFormat)+" (only GL_RGB/A, GL_BGR/A + bytes)");
diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java
index 361d03446..87a9ca4fc 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java
@@ -208,7 +208,6 @@ public class PixelFormatUtil {
return convertToInt32(dest_fmt, r, g, b, a);
}
- /**
public static int convertToInt32(PixelFormat dest_fmt, PixelFormat src_fmt, final int src_pixel) {
final byte r, g, b, a;
switch(src_fmt) {
@@ -258,7 +257,7 @@ public class PixelFormatUtil {
throw new InternalError("Unhandled format "+src_fmt);
}
return convertToInt32(dest_fmt, r, g, b, a);
- } */
+ }
public static PixelRectangle convert32(final PixelRectangle src,
final PixelFormat destFmt, int ddestStride, final boolean isGLOriented,