From 05eef46e33f41f5c234ffb1563fd8f641208fe85 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 11 Jun 2013 16:29:48 +0200 Subject: Adapt to GlueGen commit 1a01dce6c42b398cdd68d405828774a3ab366456 --- .../jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/jogl/classes/jogamp/opengl/util') diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java index 32c863553..883c13f51 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java @@ -28,6 +28,8 @@ package jogamp.opengl.util.av.impl; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -132,7 +134,10 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { static boolean initSingleton() { return ready; } private static boolean initSymbols() { - final DynamicLibraryBundle dl = new DynamicLibraryBundle(new FFMPEGDynamicLibraryBundleInfo()); + final DynamicLibraryBundle dl = AccessController.doPrivileged(new PrivilegedAction() { + public DynamicLibraryBundle run() { + return new DynamicLibraryBundle(new FFMPEGDynamicLibraryBundleInfo()); + } } ); final boolean avutilLoaded = dl.isToolLibLoaded(0); final boolean avformatLoaded = dl.isToolLibLoaded(1); final boolean avcodecLoaded = dl.isToolLibLoaded(2); -- cgit v1.2.3 From a83aea49479818a1e5037d11a3e7f7d1f019c939 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 14 Jun 2013 17:51:45 +0200 Subject: Fix Bug 745: NPE - QTT definition shall be allowd to _follow_ SOF (frame) - Reference QTT via QTT[] passed to frame, validate after parsing. --- make/scripts/tests.sh | 7 +- .../jogamp/opengl/util/jpeg/JPEGDecoder.java | 72 +++++++++++++++------ .../util/texture/TestJPEGTextureFromFileNEWT.java | 21 +++++- .../jogl/util/texture/bug745_qttdef_post_frame.jpg | Bin 0 -> 8415 bytes 4 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/bug745_qttdef_post_frame.jpg (limited to 'src/jogl/classes/jogamp/opengl/util') diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 809618ce1..452f28016 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -205,7 +205,7 @@ function jrun() { #D_ARGS="-Dnewt.debug=all" #D_ARGS="-Djogl.debug.GLCanvas -Djogl.debug.GLJPanel" #D_ARGS="-Djogl.debug.PNGImage" - #D_ARGS="-Djogl.debug.JPEGImage" + D_ARGS="-Djogl.debug.JPEGImage" #D_ARGS="-Djogl.debug.GLDrawable -Dnativewindow.debug.GraphicsConfiguration -Djogl.debug.CapabilitiesChooser" #X_ARGS="-Dsun.java2d.noddraw=True -Dsun.java2d.opengl=True -Dsun.java2d.xrender=false" #X_ARGS="-Dsun.java2d.noddraw=True -Dsun.java2d.opengl=false -Dsun.java2d.xrender=false" @@ -340,7 +340,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLPointsNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLMesaBug651NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLMesaBug658NEWT $* -testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestX11DefaultDisplay $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestX11DefaultDisplay $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer01GLCanvasAWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer02NewtCanvasAWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestAddRemove01GLCanvasSwingAWT $* @@ -526,11 +526,10 @@ testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestX11DefaultDisplay $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestTexture01AWT $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestTexture02AWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGImage00NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGImage01NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGJoglAWTCompareNewtAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGJoglAWTBenchmarkNewtAWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGTextureFromFileNEWT $* +testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGTextureFromFileNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGImage01NEWT $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileNEWT $* diff --git a/src/jogl/classes/jogamp/opengl/util/jpeg/JPEGDecoder.java b/src/jogl/classes/jogamp/opengl/util/jpeg/JPEGDecoder.java index 251291a14..833771dd1 100644 --- a/src/jogl/classes/jogamp/opengl/util/jpeg/JPEGDecoder.java +++ b/src/jogl/classes/jogamp/opengl/util/jpeg/JPEGDecoder.java @@ -301,13 +301,15 @@ public class JPEGDecoder { private final ArrayHashSet compIDs; private final ComponentIn[] comps; private final int compCount; + /** quantization tables */ + final int[][] qtt; int maxCompID; int maxH; int maxV; int mcusPerLine; int mcusPerColumn; - Frame(boolean progressive, int precision, int scanLines, int samplesPerLine, int componentsCount) { + Frame(boolean progressive, int precision, int scanLines, int samplesPerLine, int componentsCount, int[][] qtt) { this.progressive = progressive; this.precision = precision; this.scanLines = scanLines; @@ -315,6 +317,7 @@ public class JPEGDecoder { compIDs = new ArrayHashSet(componentsCount); comps = new ComponentIn[componentsCount]; this.compCount = componentsCount; + this.qtt = qtt; } private final void checkBounds(int idx) { @@ -322,6 +325,17 @@ public class JPEGDecoder { throw new CodecException("Idx out of bounds "+idx+", "+this); } } + public final void validateComponents() { + for(int i=0; i null QTT"); + } + } + } public final int getCompCount() { return compCount; } public final int getMaxCompID() { return maxCompID; } @@ -357,7 +371,8 @@ public class JPEGDecoder { /** The JPEG encoded components */ class ComponentIn { final int h, v; - final int[] quantizationTable; + /** index to frame.qtt[] */ + final int qttIdx; int blocksPerColumn; int blocksPerColumnForMcu; int blocksPerLine; @@ -368,10 +383,10 @@ public class JPEGDecoder { BinObj huffmanTableAC; BinObj huffmanTableDC; - ComponentIn(int h, int v, int[] quantizationTable) { + ComponentIn(int h, int v, int qttIdx) { this.h = h; this.v = v; - this.quantizationTable = quantizationTable; + this.qttIdx = qttIdx; } public final void allocateBlocks(int blocksPerColumn, int blocksPerColumnForMcu, int blocksPerLine, int blocksPerLineForMcu) { @@ -389,7 +404,7 @@ public class JPEGDecoder { } public final String toString() { - return "CompIn[h "+h+", v "+v+", blocks["+blocksPerColumn+", mcu "+blocksPerColumnForMcu+"]["+blocksPerLine+", mcu "+blocksPerLineForMcu+"][64]]"; + return "CompIn[h "+h+", v "+v+", qttIdx "+qttIdx+", blocks["+blocksPerColumn+", mcu "+blocksPerColumnForMcu+"]["+blocksPerLine+", mcu "+blocksPerLineForMcu+"][64]]"; } } @@ -526,12 +541,14 @@ public class JPEGDecoder { } public synchronized JPEGDecoder parse(final InputStream inputStream) throws IOException { clear(inputStream); - Frame frame = null; - int resetInterval = 0; - int[][] quantizationTables = new int[0x0F][]; // 4 bits - ArrayList frames = new ArrayList(); + + final int[][] quantizationTables = new int[0x0F][]; // 4 bits final BinObj[] huffmanTablesAC = new BinObj[0x0F]; // Huffman table spec - 4 bits final BinObj[] huffmanTablesDC = new BinObj[0x0F]; // Huffman table spec - 4 bits + // final ArrayList frames = new ArrayList(); // JAU: max 1-frame + + Frame frame = null; + int resetInterval = 0; int fileMarker = readUint16(); if ( fileMarker != M_SOI ) { throw new CodecException("SOI not found, but has marker "+toHexString(fileMarker)); @@ -579,6 +596,7 @@ public class JPEGDecoder { while( count < quantizationTablesLength ) { final int quantizationTableSpec = readUint8(); count++; final int precisionID = quantizationTableSpec >> 4; + final int tableIdx = quantizationTableSpec & 0x0F; final int[] tableData = new int[64]; if ( precisionID == 0 ) { // 8 bit values for (int j = 0; j < 64; j++) { @@ -591,12 +609,15 @@ public class JPEGDecoder { tableData[z] = readUint16(); count+=2; } } else { - throw new CodecException("DQT: invalid table precision "+precisionID+", quantizationTableSpec "+quantizationTableSpec); + throw new CodecException("DQT: invalid table precision "+precisionID+", quantizationTableSpec "+quantizationTableSpec+", idx "+tableIdx); } - quantizationTables[quantizationTableSpec & 0x0F] = tableData; + quantizationTables[tableIdx] = tableData; + if( DEBUG ) { + System.err.println("JPEG.parse.QTT["+tableIdx+"]: spec "+quantizationTableSpec+", precision "+precisionID+", data "+count+"/"+quantizationTablesLength); + } } if(count!=quantizationTablesLength){ - throw new CodecException("ERROR: QTT format error [count!=Length]"); + throw new CodecException("ERROR: QTT format error [count!=Length]: "+count+"/"+quantizationTablesLength); } fileMarker = 0; // consumed and get-next } @@ -604,6 +625,9 @@ public class JPEGDecoder { case M_SOF0: case M_SOF2: { + if( null != frame ) { // JAU: max 1-frame + throw new CodecException("only single frame JPEGs supported"); + } int count = 0; final int sofLen = readUint16(); count+=2; // header length; final int componentsCount; @@ -613,7 +637,7 @@ public class JPEGDecoder { final int scanLines = readUint16(); count+=2; final int samplesPerLine = readUint16(); count+=2; componentsCount = readUint8(); count++; - frame = new Frame(progressive, precision, scanLines, samplesPerLine, componentsCount); + frame = new Frame(progressive, precision, scanLines, samplesPerLine, componentsCount, quantizationTables); width = frame.samplesPerLine; height = frame.scanLines; } @@ -622,14 +646,15 @@ public class JPEGDecoder { final int temp = readUint8(); count++; final int h = temp >> 4; final int v = temp & 0x0F; - final int qId = readUint8(); count++; - frame.putOrdered(componentId, new ComponentIn(h, v, quantizationTables[qId])); + final int qttIdx = readUint8(); count++; + final ComponentIn compIn = new ComponentIn(h, v, qttIdx); + frame.putOrdered(componentId, compIn); } if(count!=sofLen){ throw new CodecException("ERROR: SOF format error [count!=Length]"); } prepareComponents(frame); - frames.add(frame); + // frames.add(frame); // JAU: max 1-frame if(DEBUG) { System.err.println("JPG.parse.SOF[02]: Got frame "+frame); } fileMarker = 0; // consumed and get-next } @@ -711,14 +736,21 @@ public class JPEGDecoder { } } if(DEBUG) { System.err.println("JPG.parse.2: End of parsing input "+this); } + /** // JAU: max 1-frame if ( frames.size() != 1 ) { - throw new CodecException("only single frame JPEGs supported"); + throw new CodecException("only single frame JPEGs supported "+this); + } */ + if( null == frame ) { + throw new CodecException("no single frame found in stream "+this); } + frame.validateComponents(); final int compCount = frame.getCompCount(); this.components = new ComponentOut[compCount]; for (int i = 0; i < compCount; i++) { final ComponentIn component = frame.getCompByIndex(i); + // System.err.println("JPG.parse.buildComponentData["+i+"]: "+component); // JAU + // System.err.println("JPG.parse.buildComponentData["+i+"]: "+frame); // JAU this.components[i] = new ComponentOut( output.buildComponentData(frame, component), (float)component.h / (float)frame.maxH, (float)component.v / (float)frame.maxV ); @@ -834,12 +866,14 @@ public class JPEGDecoder { final byte[] r = new byte[64]; for (int blockRow = 0; blockRow < blocksPerColumn; blockRow++) { - int scanLine = blockRow << 3; + final int scanLine = blockRow << 3; + // System.err.println("JPG.buildComponentData: row "+blockRow+"/"+blocksPerColumn+" -> scanLine "+scanLine); // JAU for (int i = 0; i < 8; i++) { lines.add(new byte[samplesPerLine]); } for (int blockCol = 0; blockCol < blocksPerLine; blockCol++) { - quantizeAndInverse(component.getBlock(blockRow, blockCol), r, R, component.quantizationTable); + // System.err.println("JPG.buildComponentData: col "+blockCol+"/"+blocksPerLine+", comp.qttIdx "+component.qttIdx+", qtt "+frame.qtt[component.qttIdx]); // JAU + quantizeAndInverse(component.getBlock(blockRow, blockCol), r, R, frame.qtt[component.qttIdx]); final int sample = blockCol << 3; int offset = 0; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGTextureFromFileNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGTextureFromFileNEWT.java index 55e8152ae..82867f9e6 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGTextureFromFileNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGTextureFromFileNEWT.java @@ -74,6 +74,8 @@ public class TestJPEGTextureFromFileNEWT extends UITestCase { InputStream testTextureStream03CMYK_01; InputStream testTextureStream03YCCK_01; + InputStream testTextureStream04QTTDefPostFrame; + @Before public void initTest() throws IOException { { @@ -132,6 +134,13 @@ public class TestJPEGTextureFromFileNEWT extends UITestCase { testTextureStream03YCCK_01 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream03YCCK_01); } + { + URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "bug745_qttdef_post_frame.jpg"); + Assert.assertNotNull(testTextureUrlConn); + testTextureStream04QTTDefPostFrame = testTextureUrlConn.getInputStream(); + Assert.assertNotNull(testTextureStream04QTTDefPostFrame); + } + } @After @@ -142,7 +151,10 @@ public class TestJPEGTextureFromFileNEWT extends UITestCase { testTextureStream01YUV422h_Prog = null; testTextureStream02YUV420_Base = null; testTextureStream02YUV420_Prog = null; - testTextureStream02YUV420_BaseGray = null; + testTextureStream02YUV420_BaseGray = null; + testTextureStream03CMYK_01 = null; + testTextureStream03YCCK_01 = null; + testTextureStream04QTTDefPostFrame = null; } public void testImpl(boolean useFFP, final InputStream istream) throws InterruptedException, IOException { @@ -241,7 +253,7 @@ public class TestJPEGTextureFromFileNEWT extends UITestCase { @Test public void test02YUV420BaseGray_ES2() throws InterruptedException, IOException { testImpl(false, testTextureStream02YUV420_BaseGray); - } + } @Test public void test03CMYK_01_ES2() throws InterruptedException, IOException { @@ -251,6 +263,11 @@ public class TestJPEGTextureFromFileNEWT extends UITestCase { public void test03YCCK_01_ES2() throws InterruptedException, IOException { testImpl(false, testTextureStream03YCCK_01); } + + @Test + public void test04QTTDefPostFrame_ES2() throws InterruptedException, IOException { + testImpl(false, testTextureStream04QTTDefPostFrame); + } public static void main(String args[]) throws IOException { for(int i=0; i Date: Fri, 21 Jun 2013 04:39:21 +0200 Subject: Security: Apply security changes from GlueGen GlueGen related commits - 23341a2df2d2ea36784a16fa1db8bc7385351a12 - 2d8e25398e929f553c4524e9c57f083d90ba4e08 - 8cabcd2de8b46c42dffcaaf46ccc2dc4d092ebba - f69831574d4927d03d40c330d0b047d8c89622a4 - eb842815498f5926828b49c48fffce22fc9586a2 --- .../opengl/cg/CgDynamicLibraryBundleInfo.java | 21 +++++---- .../opengl/DesktopGLDynamicLibraryBundleInfo.java | 4 +- .../opengl/DesktopGLDynamicLookupHelper.java | 4 +- src/jogl/classes/jogamp/opengl/GLContextImpl.java | 54 +++++++++++++++------- .../jogamp/opengl/GLDebugMessageHandler.java | 9 ++-- .../jogamp/opengl/GLDynamicLibraryBundleInfo.java | 11 +++-- .../jogamp/opengl/GLDynamicLookupHelper.java | 2 +- .../egl/DesktopES2DynamicLibraryBundleInfo.java | 6 +-- src/jogl/classes/jogamp/opengl/egl/EGLContext.java | 3 +- .../jogamp/opengl/egl/EGLDrawableFactory.java | 12 ++--- .../opengl/egl/EGLDynamicLibraryBundleInfo.java | 6 +-- .../opengl/egl/EGLES1DynamicLibraryBundleInfo.java | 4 +- .../opengl/egl/EGLES2DynamicLibraryBundleInfo.java | 4 +- .../cgl/MacOSXCGLDynamicLibraryBundleInfo.java | 4 +- .../av/impl/FFMPEGDynamicLibraryBundleInfo.java | 38 +++++++++------ .../opengl/util/av/impl/FFMPEGMediaPlayer.java | 36 +++++++++------ .../windows/wgl/WindowsWGLDrawableFactory.java | 31 ++++++++----- .../wgl/WindowsWGLDynamicLibraryBundleInfo.java | 4 +- .../opengl/x11/glx/X11GLXDrawableFactory.java | 31 ++++++++----- .../x11/glx/X11GLXDynamicLibraryBundleInfo.java | 4 +- 20 files changed, 174 insertions(+), 114 deletions(-) (limited to 'src/jogl/classes/jogamp/opengl/util') diff --git a/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java b/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java index d160eccff..ca4846939 100644 --- a/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java @@ -39,8 +39,8 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.*; -public class CgDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { - private static List glueLibNames; +public final class CgDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { + private static final List glueLibNames; static { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { @@ -69,11 +69,16 @@ public class CgDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { /** Make Cg symbols available to CgGL */ @Override - public boolean shallLinkGlobal() { return true; } + public final boolean shallLinkGlobal() { return true; } - /** default **/ + /** + * {@inheritDoc} + *

+ * Returns false. + *

+ */ @Override - public boolean shallLookupGlobal() { return false; } + public final boolean shallLookupGlobal() { return false; } /** Tool has none **/ @Override @@ -88,12 +93,12 @@ public class CgDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { } @Override - public boolean useToolGetProcAdressFirst(String funcName) { + public final boolean useToolGetProcAdressFirst(String funcName) { return false; } @Override - public List> getToolLibNames() { + public final List> getToolLibNames() { final List> libsList = new ArrayList>(); final List libsCg = new ArrayList(); libsCg.add("Cg"); @@ -112,7 +117,7 @@ public class CgDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { } @Override - public RunnableExecutor getLibLoaderExecutor() { + public final RunnableExecutor getLibLoaderExecutor() { return DynamicLibraryBundle.getDefaultRunnableExecutor(); } } diff --git a/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLibraryBundleInfo.java index f77f1135b..ef9477a31 100644 --- a/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLibraryBundleInfo.java @@ -32,7 +32,7 @@ import java.util.List; import java.util.ArrayList; public abstract class DesktopGLDynamicLibraryBundleInfo extends GLDynamicLibraryBundleInfo { - private static List glueLibNames; + private static final List glueLibNames; static { glueLibNames = new ArrayList(); @@ -49,7 +49,7 @@ public abstract class DesktopGLDynamicLibraryBundleInfo extends GLDynamicLibrary } @Override - public boolean useToolGetProcAdressFirst(String funcName) { + public final boolean useToolGetProcAdressFirst(String funcName) { return true; } diff --git a/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java b/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java index ff49303ca..8eb3468ed 100644 --- a/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java +++ b/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java @@ -37,9 +37,9 @@ public class DesktopGLDynamicLookupHelper extends GLDynamicLookupHelper { super(info); } - public DesktopGLDynamicLibraryBundleInfo getDesktopGLBundleInfo() { return (DesktopGLDynamicLibraryBundleInfo) getBundleInfo(); } + public final DesktopGLDynamicLibraryBundleInfo getDesktopGLBundleInfo() { return (DesktopGLDynamicLibraryBundleInfo) getBundleInfo(); } - public synchronized boolean loadGLULibrary() { + public final synchronized boolean loadGLULibrary() { /** hacky code .. where all platform GLU libs are tried ..*/ if(null==gluLib) { List gluLibNames = new ArrayList(); diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index cab629c3a..4ab051028 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -42,6 +42,8 @@ package jogamp.opengl; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; @@ -1144,10 +1146,31 @@ public abstract class GLContextImpl extends GLContext { /** Helper routine which resets a ProcAddressTable generated by the GLEmitter by looking up anew all of its function pointers. */ - protected final void resetProcAddressTable(ProcAddressTable table) { - table.reset(getDrawableImpl().getGLDynamicLookupHelper() ); + protected final void resetProcAddressTable(final ProcAddressTable table) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + table.reset(getDrawableImpl().getGLDynamicLookupHelper() ); + return null; + } + } ); } - + + /** + * Catches IllegalArgumentException and returns 0 if functionName is n/a, + * otherwise the ProcAddressTable's field value. + */ + /* pp */ final long getAddressFor(final ProcAddressTable table, final String functionName) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Long run() { + try { + return Long.valueOf( table.getAddressFor(functionName) ); + } catch (IllegalArgumentException iae) { + return Long.valueOf(0); + } + } + } ).longValue(); + } + private final boolean initGLRendererAndGLVersionStrings() { final GLDynamicLookupHelper glDynLookupHelper = getDrawableImpl().getGLDynamicLookupHelper(); final long _glGetString = glDynLookupHelper.dynamicLookupFunction("glGetString"); @@ -1748,7 +1771,7 @@ public abstract class GLContextImpl extends GLContext { // Check GL 1st (cached) if(null!=glProcAddressTable) { // null if this context wasn't not created try { - if(0!=glProcAddressTable.getAddressFor(glFunctionName)) { + if( glProcAddressTable.isFunctionAvailable( glFunctionName ) ) { return true; } } catch (Exception e) {} @@ -1758,27 +1781,24 @@ public abstract class GLContextImpl extends GLContext { final ProcAddressTable pTable = getPlatformExtProcAddressTable(); if(null!=pTable) { try { - if(0!=pTable.getAddressFor(glFunctionName)) { + if( pTable.isFunctionAvailable( glFunctionName ) ) { return true; } } catch (Exception e) {} } // dynamic function lookup at last incl name aliasing (not cached) - DynamicLookupHelper dynLookup = getDrawableImpl().getGLDynamicLookupHelper(); - String tmpBase = GLNameResolver.normalizeVEN(GLNameResolver.normalizeARB(glFunctionName, true), true); - long addr = 0; + final DynamicLookupHelper dynLookup = getDrawableImpl().getGLDynamicLookupHelper(); + final String tmpBase = GLNameResolver.normalizeVEN(GLNameResolver.normalizeARB(glFunctionName, true), true); + boolean res = false; int variants = GLNameResolver.getFuncNamePermutationNumber(tmpBase); - for(int i = 0; 0==addr && i < variants; i++) { - String tmp = GLNameResolver.getFuncNamePermutation(tmpBase, i); + for(int i = 0; !res && i < variants; i++) { + final String tmp = GLNameResolver.getFuncNamePermutation(tmpBase, i); try { - addr = dynLookup.dynamicLookupFunction(tmp); + res = dynLookup.isFunctionAvailable(tmp); } catch (Exception e) { } } - if(0!=addr) { - return true; - } - return false; + return res; } @Override @@ -2078,8 +2098,8 @@ public abstract class GLContextImpl extends GLContext { } /** Internal bootstraping glGetString(GL_RENDERER) */ - protected static native String glGetStringInt(int name, long procAddress); + private static native String glGetStringInt(int name, long procAddress); /** Internal bootstraping glGetIntegerv(..) for version */ - protected static native void glGetIntegervInt(int pname, int[] params, int params_offset, long procAddress); + private static native void glGetIntegervInt(int pname, int[] params, int params_offset, long procAddress); } diff --git a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java index 0000e6199..392b5db28 100644 --- a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java +++ b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java @@ -39,8 +39,6 @@ import com.jogamp.common.os.Platform; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.opengl.GLExtensions; -import jogamp.opengl.gl4.GL4bcProcAddressTable; - /** * The GLDebugMessageHandler, handling GL_ARB_debug_output or GL_AMD_debug_output * debug messages.
@@ -148,14 +146,13 @@ public class GLDebugMessageHandler { } final ProcAddressTable procAddressTable = ctx.getGLProcAddressTable(); - if( procAddressTable instanceof GL4bcProcAddressTable) { - final GL4bcProcAddressTable desktopProcAddressTable = (GL4bcProcAddressTable)procAddressTable; + if( ctx.isGL4() ) { switch(extType) { case EXT_ARB: - glDebugMessageCallbackProcAddress = desktopProcAddressTable._addressof_glDebugMessageCallbackARB; + glDebugMessageCallbackProcAddress = ctx.getAddressFor(procAddressTable, "glDebugMessageCallbackARB"); break; case EXT_AMD: - glDebugMessageCallbackProcAddress = desktopProcAddressTable._addressof_glDebugMessageCallbackAMD; + glDebugMessageCallbackProcAddress = ctx.getAddressFor(procAddressTable, "glDebugMessageCallbackAMD"); break; } } else { diff --git a/src/jogl/classes/jogamp/opengl/GLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/GLDynamicLibraryBundleInfo.java index a2e3b3175..8ba9f617b 100644 --- a/src/jogl/classes/jogamp/opengl/GLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/GLDynamicLibraryBundleInfo.java @@ -46,16 +46,19 @@ public abstract class GLDynamicLibraryBundleInfo implements DynamicLibraryBundle * *

*/ - public boolean shallLinkGlobal() { return true; } + public final boolean shallLinkGlobal() { return true; } /** - * Default value: false. - */ + * {@inheritDoc} + *

+ * Returns false. + *

+ */ @Override public boolean shallLookupGlobal() { return false; } @Override - public RunnableExecutor getLibLoaderExecutor() { + public final RunnableExecutor getLibLoaderExecutor() { return DynamicLibraryBundle.getDefaultRunnableExecutor(); } } diff --git a/src/jogl/classes/jogamp/opengl/GLDynamicLookupHelper.java b/src/jogl/classes/jogamp/opengl/GLDynamicLookupHelper.java index d2dac8148..1ed73f15e 100644 --- a/src/jogl/classes/jogamp/opengl/GLDynamicLookupHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDynamicLookupHelper.java @@ -36,7 +36,7 @@ public class GLDynamicLookupHelper extends DynamicLibraryBundle { super(info); } - public GLDynamicLibraryBundleInfo getGLBundleInfo() { return (GLDynamicLibraryBundleInfo) getBundleInfo(); } + public final GLDynamicLibraryBundleInfo getGLBundleInfo() { return (GLDynamicLibraryBundleInfo) getBundleInfo(); } /** NOP per default */ public boolean loadGLULibrary() { return false; } diff --git a/src/jogl/classes/jogamp/opengl/egl/DesktopES2DynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/DesktopES2DynamicLibraryBundleInfo.java index 771d16d46..3d59d1d53 100644 --- a/src/jogl/classes/jogamp/opengl/egl/DesktopES2DynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/DesktopES2DynamicLibraryBundleInfo.java @@ -36,8 +36,8 @@ import jogamp.opengl.*; * Implementation of the DynamicLookupHelper for Desktop ES2 (AMD, ..) * where EGL and ES2 functions reside within the desktop OpenGL library. */ -public class DesktopES2DynamicLibraryBundleInfo extends GLDynamicLibraryBundleInfo { - static List glueLibNames; +public final class DesktopES2DynamicLibraryBundleInfo extends GLDynamicLibraryBundleInfo { + static final List glueLibNames; static { glueLibNames = new ArrayList(); glueLibNames.add("jogl_mobile"); @@ -61,7 +61,7 @@ public class DesktopES2DynamicLibraryBundleInfo extends GLDynamicLibraryBundleIn return true; } - public List> getToolLibNames() { + public final List> getToolLibNames() { final List> libsList = new ArrayList>(); final List libsGL = new ArrayList(); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java index 2b8ca31c9..b54ed6599 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java @@ -259,8 +259,7 @@ public class EGLContext extends GLContextImpl { protected final StringBuilder getPlatformExtensionsStringImpl() { StringBuilder sb = new StringBuilder(); if (!eglQueryStringInitialized) { - eglQueryStringAvailable = - getDrawableImpl().getGLDynamicLookupHelper().dynamicLookupFunction("eglQueryString") != 0; + eglQueryStringAvailable = getDrawableImpl().getGLDynamicLookupHelper().isFunctionAvailable("eglQueryString"); eglQueryStringInitialized = true; } if (eglQueryStringAvailable) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index adb78b3b9..79d1fad62 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -91,9 +91,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { private static final boolean isANGLE(GLDynamicLookupHelper dl) { if(Platform.OSType.WINDOWS == Platform.OS_TYPE) { - final boolean r = 0 != dl.dynamicLookupFunction("eglQuerySurfacePointerANGLE") || - 0 != dl.dynamicLookupFunction("glBlitFramebufferANGLE") || - 0 != dl.dynamicLookupFunction("glRenderbufferStorageMultisampleANGLE"); + final boolean r = dl.isFunctionAvailable("eglQuerySurfacePointerANGLE") || + dl.isFunctionAvailable("glBlitFramebufferANGLE") || + dl.isFunctionAvailable("glRenderbufferStorageMultisampleANGLE"); return r; } else { return false; @@ -101,9 +101,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } private static final boolean includesES1(GLDynamicLookupHelper dl) { - return 0 != dl.dynamicLookupFunction("glLoadIdentity") && - 0 != dl.dynamicLookupFunction("glEnableClientState") && - 0 != dl.dynamicLookupFunction("glColorPointer"); + return dl.isFunctionAvailable("glLoadIdentity") && + dl.isFunctionAvailable("glEnableClientState") && + dl.isFunctionAvailable("glColorPointer"); } public EGLDrawableFactory() { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java index 26b199ea2..9f4a4d2c2 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java @@ -42,7 +42,7 @@ import jogamp.opengl.*; * Currently two implementations exist, one for ES1 and one for ES2. */ public abstract class EGLDynamicLibraryBundleInfo extends GLDynamicLibraryBundleInfo { - static List glueLibNames; + static final List glueLibNames; static { glueLibNames = new ArrayList(); glueLibNames.add("jogl_mobile"); @@ -57,7 +57,7 @@ public abstract class EGLDynamicLibraryBundleInfo extends GLDynamicLibraryBundle * and false otherwise. */ @Override - public boolean shallLookupGlobal() { + public final boolean shallLookupGlobal() { if ( Platform.OSType.ANDROID == Platform.OS_TYPE ) { // Android requires global symbol lookup return true; @@ -88,7 +88,7 @@ public abstract class EGLDynamicLibraryBundleInfo extends GLDynamicLibraryBundle } } - protected List getEGLLibNamesList() { + protected final List getEGLLibNamesList() { List eglLibNames = new ArrayList(); // this is the default EGL lib name, according to the spec diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java index 0a373eb7f..dd3d6faea 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java @@ -30,12 +30,12 @@ package jogamp.opengl.egl; import java.util.*; -public class EGLES1DynamicLibraryBundleInfo extends EGLDynamicLibraryBundleInfo { +public final class EGLES1DynamicLibraryBundleInfo extends EGLDynamicLibraryBundleInfo { protected EGLES1DynamicLibraryBundleInfo() { super(); } - public List> getToolLibNames() { + public final List> getToolLibNames() { final List> libsList = new ArrayList>(); { final List libsGL = new ArrayList(); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java index d4ee852b1..d83acdb6b 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java @@ -30,12 +30,12 @@ package jogamp.opengl.egl; import java.util.*; -public class EGLES2DynamicLibraryBundleInfo extends EGLDynamicLibraryBundleInfo { +public final class EGLES2DynamicLibraryBundleInfo extends EGLDynamicLibraryBundleInfo { protected EGLES2DynamicLibraryBundleInfo() { super(); } - public List> getToolLibNames() { + public final List> getToolLibNames() { final List> libsList = new ArrayList>(); { final List libsGL = new ArrayList(); diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java index 03ec94db6..f8c874a53 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java @@ -31,13 +31,13 @@ package jogamp.opengl.macosx.cgl; import jogamp.opengl.*; import java.util.*; -public class MacOSXCGLDynamicLibraryBundleInfo extends DesktopGLDynamicLibraryBundleInfo { +public final class MacOSXCGLDynamicLibraryBundleInfo extends DesktopGLDynamicLibraryBundleInfo { protected MacOSXCGLDynamicLibraryBundleInfo() { super(); } @Override - public List> getToolLibNames() { + public final List> getToolLibNames() { final List> libsList = new ArrayList>(); final List libsGL = new ArrayList(); libsGL.add("/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"); diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java index 883c13f51..2d40fe4ec 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java @@ -55,10 +55,10 @@ import com.jogamp.common.util.RunnableExecutor; * Tue Feb 28 12:07:53 2012 322537478b63c6bc01e640643550ff539864d790 minor 1 -> 2 */ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { - private static List glueLibNames = new ArrayList(); // none + private static final List glueLibNames = new ArrayList(); // none private static final int symbolCount = 31; - private static String[] symbolNames = { + private static final String[] symbolNames = { "avcodec_version", "avformat_version", /* 3 */ "avutil_version", @@ -99,7 +99,7 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { }; // alternate symbol names - private static String[][] altSymbolNames = { + private static final String[][] altSymbolNames = { { "avcodec_open", "avcodec_open2" }, // old, 53.6.0 { "avcodec_decode_audio3", "avcodec_decode_audio4" }, // old, 53.25.0 { "av_close_input_file", "avformat_close_input" }, // old, 53.17.0 @@ -107,7 +107,7 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { }; // optional symbol names - private static String[] optionalSymbolNames = { + private static final String[] optionalSymbolNames = { "avformat_free_context", // 52.96.0 (opt) "avformat_network_init", // 53.13.0 (opt) "avformat_network_deinit", // 53.13.0 (opt) @@ -133,7 +133,7 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { static boolean initSingleton() { return ready; } - private static boolean initSymbols() { + private static final boolean initSymbols() { final DynamicLibraryBundle dl = AccessController.doPrivileged(new PrivilegedAction() { public DynamicLibraryBundle run() { return new DynamicLibraryBundle(new FFMPEGDynamicLibraryBundleInfo()); @@ -171,9 +171,13 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { } // lookup - for(int i = 0; i() { + public Object run() { + for(int i = 0; i + * Returns true. + *

+ */ @Override - public boolean shallLookupGlobal() { return true; } + public final boolean shallLookupGlobal() { + return true; + } @Override public final List getGlueLibNames() { @@ -222,7 +234,7 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { } @Override - public List> getToolLibNames() { + public final List> getToolLibNames() { List> libsList = new ArrayList>(); final List avutil = new ArrayList(); @@ -279,12 +291,12 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { } @Override - public boolean useToolGetProcAdressFirst(String funcName) { + public final boolean useToolGetProcAdressFirst(String funcName) { return false; } @Override - public RunnableExecutor getLibLoaderExecutor() { + public final RunnableExecutor getLibLoaderExecutor() { return DynamicLibraryBundle.getDefaultRunnableExecutor(); } diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java index 4be2bcb58..0c578f97f 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java @@ -31,6 +31,8 @@ package jogamp.opengl.util.av.impl; import java.io.IOException; import java.nio.Buffer; import java.nio.ByteBuffer; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; @@ -43,9 +45,6 @@ import com.jogamp.opengl.util.texture.Texture; import com.jogamp.opengl.util.texture.TextureSequence; import jogamp.opengl.GLContextImpl; -import jogamp.opengl.es1.GLES1ProcAddressTable; -import jogamp.opengl.es2.GLES2ProcAddressTable; -import jogamp.opengl.gl4.GL4bcProcAddressTable; import jogamp.opengl.util.av.EGLMediaPlayerImpl; /*** @@ -201,18 +200,29 @@ public class FFMPEGMediaPlayer extends EGLMediaPlayerImpl { } setTextureFormat(tif, tf); setTextureType(GL.GL_UNSIGNED_BYTE); - GLContextImpl ctx = (GLContextImpl)gl.getContext(); - ProcAddressTable pt = ctx.getGLProcAddressTable(); - if(pt instanceof GLES2ProcAddressTable) { - procAddrGLTexSubImage2D = ((GLES2ProcAddressTable)pt)._addressof_glTexSubImage2D; - } else if(pt instanceof GLES1ProcAddressTable) { - procAddrGLTexSubImage2D = ((GLES1ProcAddressTable)pt)._addressof_glTexSubImage2D; - } else if(pt instanceof GL4bcProcAddressTable) { - procAddrGLTexSubImage2D = ((GL4bcProcAddressTable)pt)._addressof_glTexSubImage2D; - } else { - throw new InternalError("Unknown ProcAddressTable: "+pt.getClass().getName()+" of "+ctx.getClass().getName()); + final GLContextImpl ctx = (GLContextImpl)gl.getContext(); + final ProcAddressTable pt = ctx.getGLProcAddressTable(); + if( 0 == procAddrGLTexSubImage2D ) { + throw new InternalError("glTexSubImage2D n/a in ProcAddressTable: "+pt.getClass().getName()+" of "+ctx.getGLVersion()); } } + + /** + * Catches IllegalArgumentException and returns 0 if functionName is n/a, + * otherwise the ProcAddressTable's field value. + */ + private final long getAddressFor(final ProcAddressTable table, final String functionName) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Long run() { + try { + return Long.valueOf( table.getAddressFor(functionName) ); + } catch (IllegalArgumentException iae) { + return Long.valueOf(0); + } + } + } ).longValue(); + } + private void updateAttributes2(int pixFmt, int planes, int bitsPerPixel, int bytesPerPixelPerPlane, int lSz0, int lSz1, int lSz2, int tWd0, int tWd1, int tWd2) { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index 5fb01d1a3..45edda516 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -43,6 +43,8 @@ package jogamp.opengl.windows.wgl; import java.nio.Buffer; import java.nio.ShortBuffer; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -88,19 +90,24 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { super(); synchronized(WindowsWGLDrawableFactory.class) { - if(null==windowsWGLDynamicLookupHelper) { - DesktopGLDynamicLookupHelper tmp = null; - try { - tmp = new DesktopGLDynamicLookupHelper(new WindowsWGLDynamicLibraryBundleInfo()); - } catch (GLException gle) { - if(DEBUG) { - gle.printStackTrace(); + if( null == windowsWGLDynamicLookupHelper ) { + windowsWGLDynamicLookupHelper = AccessController.doPrivileged(new PrivilegedAction() { + public DesktopGLDynamicLookupHelper run() { + DesktopGLDynamicLookupHelper tmp; + try { + tmp = new DesktopGLDynamicLookupHelper(new WindowsWGLDynamicLibraryBundleInfo()); + if(null!=tmp && tmp.isLibComplete()) { + WGL.getWGLProcAddressTable().reset(tmp); + } + } catch (Exception ex) { + tmp = null; + if(DEBUG) { + ex.printStackTrace(); + } + } + return tmp; } - } - if(null!=tmp && tmp.isLibComplete()) { - windowsWGLDynamicLookupHelper = tmp; - WGL.getWGLProcAddressTable().reset(windowsWGLDynamicLookupHelper); - } + } ); } } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDynamicLibraryBundleInfo.java index a553bd4c2..7ec6c50f8 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDynamicLibraryBundleInfo.java @@ -31,13 +31,13 @@ package jogamp.opengl.windows.wgl; import jogamp.opengl.*; import java.util.*; -public class WindowsWGLDynamicLibraryBundleInfo extends DesktopGLDynamicLibraryBundleInfo { +public final class WindowsWGLDynamicLibraryBundleInfo extends DesktopGLDynamicLibraryBundleInfo { protected WindowsWGLDynamicLibraryBundleInfo() { super(); } @Override - public List> getToolLibNames() { + public final List> getToolLibNames() { final List> libsList = new ArrayList>(); final List libsGL = new ArrayList(); libsGL.add("OpenGL32"); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index 394293bc0..b3b02e23f 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -39,6 +39,8 @@ package jogamp.opengl.x11.glx; import java.nio.Buffer; import java.nio.ShortBuffer; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -91,19 +93,24 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { super(); synchronized(X11GLXDrawableFactory.class) { - if(null==x11GLXDynamicLookupHelper) { - DesktopGLDynamicLookupHelper tmp = null; - try { - tmp = new DesktopGLDynamicLookupHelper(new X11GLXDynamicLibraryBundleInfo()); - } catch (GLException gle) { - if(DEBUG) { - gle.printStackTrace(); + if( null == x11GLXDynamicLookupHelper ) { + x11GLXDynamicLookupHelper = AccessController.doPrivileged(new PrivilegedAction() { + public DesktopGLDynamicLookupHelper run() { + DesktopGLDynamicLookupHelper tmp; + try { + tmp = new DesktopGLDynamicLookupHelper(new X11GLXDynamicLibraryBundleInfo()); + if(null!=tmp && tmp.isLibComplete()) { + GLX.getGLXProcAddressTable().reset(tmp); + } + } catch (Exception ex) { + tmp = null; + if(DEBUG) { + ex.printStackTrace(); + } + } + return tmp; } - } - if(null!=tmp && tmp.isLibComplete()) { - x11GLXDynamicLookupHelper = tmp; - GLX.getGLXProcAddressTable().reset(x11GLXDynamicLookupHelper); - } + } ); } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDynamicLibraryBundleInfo.java index 6083f209c..f25f7ae2c 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDynamicLibraryBundleInfo.java @@ -31,13 +31,13 @@ package jogamp.opengl.x11.glx; import jogamp.opengl.*; import java.util.*; -public class X11GLXDynamicLibraryBundleInfo extends DesktopGLDynamicLibraryBundleInfo { +public final class X11GLXDynamicLibraryBundleInfo extends DesktopGLDynamicLibraryBundleInfo { protected X11GLXDynamicLibraryBundleInfo() { super(); } @Override - public List> getToolLibNames() { + public final List> getToolLibNames() { final List> libsList = new ArrayList>(); final List libsGL = new ArrayList(); -- cgit v1.2.3 From 7ae47a845c625b9677b5879831d87a14d8e57311 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 21 Jun 2013 07:38:04 +0200 Subject: GL*ProcAddressTable: Fix regressions: getField(..) -> getDeclaredField(..), incl. access check; Move getAddressFor() from ctx -> private dbg-handler (sec); FFMPEGMediaPlayer: Missed fetching func-ptr 'glTexSubImage2D'. --- make/scripts/tests.sh | 7 ++--- .../com/jogamp/gluegen/opengl/GLEmitter.java | 31 ++++++++++++++++------ src/jogl/classes/jogamp/opengl/GLContextImpl.java | 16 ----------- .../jogamp/opengl/GLDebugMessageHandler.java | 18 +++++++++++-- .../opengl/util/av/impl/FFMPEGMediaPlayer.java | 1 + 5 files changed, 44 insertions(+), 29 deletions(-) (limited to 'src/jogl/classes/jogamp/opengl/util') diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index b44b7f8ff..46d7876d3 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -139,7 +139,8 @@ function jrun() { #D_ARGS="-Dnewt.test.Screen.disableRandR13" #D_ARGS="-Dnewt.test.Screen.disableScreenMode -Dnewt.debug.Screen" #D_ARGS="-Dnewt.debug.Screen -Djogl.debug.Animator" - D_ARGS="-Djogl.debug=all -Dnativewindow.debug=all -Djogamp.debug.ProcAddressHelper -Djogamp.debug.NativeLibrary -Djogamp.debug.NativeLibrary.Lookup -Djogamp.debug.JNILibLoader -Djogamp.debug.TempJarCache -Djogamp.debug.JarUtil" + #D_ARGS="-Djogamp.debug.ProcAddressHelper -Djogamp.debug.NativeLibrary -Djogamp.debug.NativeLibrary.Lookup -Djogamp.debug.JNILibLoader -Djogamp.debug.TempJarCache -Djogamp.debug.JarUtil" + #D_ARGS="-Djogl.debug.GLContext -Djogamp.debug.NativeLibrary -Djogamp.debug.JNILibLoader -Djogl.debug.DebugGL -Djogl.debug.GLDebugMessageHandler" #D_ARGS="-Dnewt.debug.MainThread" #D_ARGS="-Dnativewindow.debug.GraphicsConfiguration -Dnativewindow.debug.NativeWindow" #D_ARGS="-Djogl.debug.GLCanvas -Djogl.debug.Animator -Djogl.debug.GLDrawable -Djogl.debug.GLContext -Djogl.debug.GLContext.TraceSwitch" @@ -306,7 +307,7 @@ function testawtswt() { # av demos # #testnoawt jogamp.opengl.openal.av.ALDummyUsage $* -#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube $* +testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieSimple $* # @@ -315,7 +316,7 @@ function testawtswt() { #testnoawt com.jogamp.nativewindow.NativeWindowVersion $* #testnoawt com.jogamp.opengl.JoglVersion $* #testnoawt com.jogamp.newt.NewtVersion $* -testnoawt com.jogamp.newt.opengl.GLWindow $* +#testnoawt com.jogamp.newt.opengl.GLWindow $* #testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix01NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix02NOUI $* diff --git a/src/jogl/classes/com/jogamp/gluegen/opengl/GLEmitter.java b/src/jogl/classes/com/jogamp/gluegen/opengl/GLEmitter.java index 356482581..7c49b62d7 100644 --- a/src/jogl/classes/com/jogamp/gluegen/opengl/GLEmitter.java +++ b/src/jogl/classes/com/jogamp/gluegen/opengl/GLEmitter.java @@ -39,7 +39,6 @@ */ package com.jogamp.gluegen.opengl; -import com.jogamp.common.util.SecurityUtil; import com.jogamp.gluegen.ConstantDefinition; import com.jogamp.gluegen.FunctionEmitter; import com.jogamp.gluegen.GlueEmitterControls; @@ -461,7 +460,7 @@ public class GLEmitter extends ProcAddressEmitter { @Override protected void endProcAddressTable() throws Exception { PrintWriter w = tableWriter; - + w.println(" @Override"); w.println(" protected boolean isFunctionAvailableImpl(String functionNameUsr) throws IllegalArgumentException {"); w.println(" final String functionNameBase = "+GLNameResolver.class.getName()+".normalizeVEN(com.jogamp.gluegen.runtime.opengl.GLNameResolver.normalizeARB(functionNameUsr, true), true);"); @@ -470,9 +469,17 @@ public class GLEmitter extends ProcAddressEmitter { w.println(" int funcNamePermNum = "+GLNameResolver.class.getName()+".getFuncNamePermutationNumber(functionNameBase);"); w.println(" for(int i = 0; null==addressField && i < funcNamePermNum; i++) {"); w.println(" final String addressFieldName = "+GLNameResolver.class.getName()+".getFuncNamePermutation(addressFieldNameBase, i);"); - w.println(" try {"); - w.println(" addressField = getClass().getField(addressFieldName);"); - w.println(" } catch (Exception e) { }"); + w.println(" addressField = java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {"); + w.println(" public java.lang.reflect.Field run() {"); + w.println(" try {"); + w.println(" final java.lang.reflect.Field addressField = "+tableClassName+".class.getDeclaredField( addressFieldName );"); + w.println(" addressField.setAccessible(true); // we need to read the protected value!"); + w.println(" return addressField;"); + w.println(" } catch (NoSuchFieldException ex) {"); + w.println(" return null;"); + w.println(" }"); + w.println(" }"); + w.println(" } );"); w.println(" }"); w.println(); w.println(" if(null==addressField) {"); @@ -502,9 +509,17 @@ public class GLEmitter extends ProcAddressEmitter { w.println(" int funcNamePermNum = "+GLNameResolver.class.getName()+".getFuncNamePermutationNumber(functionNameBase);"); w.println(" for(int i = 0; null==addressField && i < funcNamePermNum; i++) {"); w.println(" final String addressFieldName = "+GLNameResolver.class.getName()+".getFuncNamePermutation(addressFieldNameBase, i);"); - w.println(" try {"); - w.println(" addressField = getClass().getField(addressFieldName);"); - w.println(" } catch (Exception e) { }"); + w.println(" addressField = java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {"); + w.println(" public java.lang.reflect.Field run() {"); + w.println(" try {"); + w.println(" final java.lang.reflect.Field addressField = "+tableClassName+".class.getDeclaredField( addressFieldName );"); + w.println(" addressField.setAccessible(true); // we need to read the protected value!"); + w.println(" return addressField;"); + w.println(" } catch (NoSuchFieldException ex) {"); + w.println(" return null;"); + w.println(" }"); + w.println(" }"); + w.println(" } );"); w.println(" }"); w.println(); w.println(" if(null==addressField) {"); diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 4ab051028..6254b6f44 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -1155,22 +1155,6 @@ public abstract class GLContextImpl extends GLContext { } ); } - /** - * Catches IllegalArgumentException and returns 0 if functionName is n/a, - * otherwise the ProcAddressTable's field value. - */ - /* pp */ final long getAddressFor(final ProcAddressTable table, final String functionName) { - return AccessController.doPrivileged(new PrivilegedAction() { - public Long run() { - try { - return Long.valueOf( table.getAddressFor(functionName) ); - } catch (IllegalArgumentException iae) { - return Long.valueOf(0); - } - } - } ).longValue(); - } - private final boolean initGLRendererAndGLVersionStrings() { final GLDynamicLookupHelper glDynLookupHelper = getDrawableImpl().getGLDynamicLookupHelper(); final long _glGetString = glDynLookupHelper.dynamicLookupFunction("glGetString"); diff --git a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java index 392b5db28..4c7f414ca 100644 --- a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java +++ b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java @@ -27,6 +27,8 @@ */ package jogamp.opengl; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import javax.media.nativewindow.NativeWindowException; @@ -105,6 +107,18 @@ public class GLDebugMessageHandler { } } + private final long getAddressFor(final ProcAddressTable table, final String functionName) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Long run() { + try { + return Long.valueOf( table.getAddressFor(functionName) ); + } catch (IllegalArgumentException iae) { + return Long.valueOf(0); + } + } + } ).longValue(); + } + public void init() { ctx.validateCurrent(); if( isAvailable()) { @@ -149,10 +163,10 @@ public class GLDebugMessageHandler { if( ctx.isGL4() ) { switch(extType) { case EXT_ARB: - glDebugMessageCallbackProcAddress = ctx.getAddressFor(procAddressTable, "glDebugMessageCallbackARB"); + glDebugMessageCallbackProcAddress = getAddressFor(procAddressTable, "glDebugMessageCallbackARB"); break; case EXT_AMD: - glDebugMessageCallbackProcAddress = ctx.getAddressFor(procAddressTable, "glDebugMessageCallbackAMD"); + glDebugMessageCallbackProcAddress = getAddressFor(procAddressTable, "glDebugMessageCallbackAMD"); break; } } else { diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java index 0c578f97f..a4178967c 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java @@ -202,6 +202,7 @@ public class FFMPEGMediaPlayer extends EGLMediaPlayerImpl { setTextureType(GL.GL_UNSIGNED_BYTE); final GLContextImpl ctx = (GLContextImpl)gl.getContext(); final ProcAddressTable pt = ctx.getGLProcAddressTable(); + procAddrGLTexSubImage2D = getAddressFor(pt, "glTexSubImage2D"); if( 0 == procAddrGLTexSubImage2D ) { throw new InternalError("glTexSubImage2D n/a in ProcAddressTable: "+pt.getClass().getName()+" of "+ctx.getGLVersion()); } -- cgit v1.2.3 From 51427b92a2d9cd3fc619854e26536c9c6adad947 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 2 Jul 2013 22:25:23 +0200 Subject: PNGJ: Bump to git sha1 a0b1101ba2d37de39428ed55c8189502e24a3125 of https://code.google.com/p/pngj/ --- .../jogamp/opengl/util/pngj/FilterType.java | 24 +++++-- .../classes/jogamp/opengl/util/pngj/ImageInfo.java | 26 +++++--- .../classes/jogamp/opengl/util/pngj/ImageLine.java | 42 +++++++----- .../jogamp/opengl/util/pngj/ImageLineHelper.java | 32 ++++++---- .../jogamp/opengl/util/pngj/ImageLines.java | 24 ++++--- .../jogamp/opengl/util/pngj/PngHelperInternal.java | 23 ++++--- .../opengl/util/pngj/PngIDatChunkInputStream.java | 9 ++- .../classes/jogamp/opengl/util/pngj/PngWriter.java | 74 +++++++++++++--------- .../opengl/util/pngj/PngjExceptionInternal.java | 3 +- .../opengl/util/pngj/PngjUnsupportedException.java | 3 +- .../opengl/util/pngj/ProgressiveOutputStream.java | 7 +- .../util/pngj/chunks/ChunkLoadBehaviour.java | 9 ++- .../jogamp/opengl/util/pngj/chunks/ChunkRaw.java | 23 ++++--- .../jogamp/opengl/util/pngj/chunks/ChunksList.java | 17 +++-- .../util/pngj/chunks/ChunksListForWrite.java | 11 ++-- .../jogamp/opengl/util/pngj/chunks/PngChunk.java | 53 ++++++++++------ .../opengl/util/pngj/chunks/PngChunkIDAT.java | 3 +- .../opengl/util/pngj/chunks/PngChunkMultiple.java | 3 +- .../opengl/util/pngj/chunks/PngChunkSingle.java | 3 +- .../opengl/util/pngj/chunks/PngMetadata.java | 31 +++++---- 20 files changed, 263 insertions(+), 157 deletions(-) (limited to 'src/jogl/classes/jogamp/opengl/util') diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/FilterType.java b/src/jogl/classes/jogamp/opengl/util/pngj/FilterType.java index e88a95a33..0fffc85b1 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/FilterType.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/FilterType.java @@ -1,5 +1,7 @@ package jogamp.opengl.util.pngj; +import java.util.HashMap; + /** * Internal PNG predictor filter, or strategy to select it. * @@ -26,15 +28,18 @@ public enum FilterType { */ FILTER_PAETH(4), /** - * Default strategy: select one of the above filters depending on global image parameters + * Default strategy: select one of the above filters depending on global + * image parameters */ FILTER_DEFAULT(-1), /** - * Aggressive strategy: select one of the above filters trying each of the filters (every 8 rows) + * Aggressive strategy: select one of the above filters trying each of the + * filters (every 8 rows) */ FILTER_AGGRESSIVE(-2), /** - * Very aggressive strategy: select one of the above filters trying each of the filters (for every row!) + * Very aggressive strategy: select one of the above filters trying each of + * the filters (for every row!) */ FILTER_VERYAGGRESSIVE(-3), /** @@ -52,12 +57,17 @@ public enum FilterType { this.val = val; } - public static FilterType getByVal(int i) { + private static HashMap byVal; + + static { + byVal = new HashMap(); for (FilterType ft : values()) { - if (ft.val == i) - return ft; + byVal.put(ft.val, ft); } - return null; + } + + public static FilterType getByVal(int i) { + return byVal.get(i); } } diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/ImageInfo.java b/src/jogl/classes/jogamp/opengl/util/pngj/ImageInfo.java index 26562ef3e..e62134cd5 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/ImageInfo.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/ImageInfo.java @@ -3,7 +3,8 @@ package jogamp.opengl.util.pngj; /** * Simple immutable wrapper for basic image info. *

- * Some parameters are redundant, but the constructor receives an 'orthogonal' subset. + * Some parameters are redundant, but the constructor receives an 'orthogonal' + * subset. *

* ref: http://www.w3.org/TR/PNG/#11IHDR */ @@ -23,14 +24,15 @@ public class ImageInfo { public final int rows; /** - * Bits per sample (per channel) in the buffer (1-2-4-8-16). This is 8-16 for RGB/ARGB images, 1-2-4-8 for - * grayscale. For indexed images, number of bits per palette index (1-2-4-8) + * Bits per sample (per channel) in the buffer (1-2-4-8-16). This is 8-16 + * for RGB/ARGB images, 1-2-4-8 for grayscale. For indexed images, number of + * bits per palette index (1-2-4-8) */ public final int bitDepth; /** - * Number of channels, as used internally: 3 for RGB, 4 for RGBA, 2 for GA (gray with alpha), 1 for grayscale or - * indexed. + * Number of channels, as used internally: 3 for RGB, 4 for RGBA, 2 for GA + * (gray with alpha), 1 for grayscale or indexed. */ public final int channels; @@ -50,7 +52,8 @@ public class ImageInfo { public final boolean indexed; /** - * Flag: true if image internally uses less than one byte per sample (bit depth 1-2-4) + * Flag: true if image internally uses less than one byte per sample (bit + * depth 1-2-4) */ public final boolean packed; @@ -75,10 +78,12 @@ public class ImageInfo { public final int samplesPerRow; /** - * Amount of "packed samples" : when several samples are stored in a single byte (bitdepth 1,2 4) they are counted - * as one "packed sample". This is less that samplesPerRow only when bitdepth is 1-2-4 (flag packed = true) + * Amount of "packed samples" : when several samples are stored in a single + * byte (bitdepth 1,2 4) they are counted as one "packed sample". This is + * less that samplesPerRow only when bitdepth is 1-2-4 (flag packed = true) *

- * This equals the number of elements in the scanline array if working with packedMode=true + * This equals the number of elements in the scanline array if working with + * packedMode=true *

* For internal use, client code should rarely access this. */ @@ -99,7 +104,8 @@ public class ImageInfo { * @param rows * Height in pixels * @param bitdepth - * Bits per sample, in the buffer : 8-16 for RGB true color and greyscale + * Bits per sample, in the buffer : 8-16 for RGB true color and + * greyscale * @param alpha * Flag: has an alpha channel (RGBA or GA) * @param grayscale diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/ImageLine.java b/src/jogl/classes/jogamp/opengl/util/pngj/ImageLine.java index 9f8a13230..e34e6a226 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/ImageLine.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/ImageLine.java @@ -5,7 +5,8 @@ import jogamp.opengl.util.pngj.ImageLineHelper.ImageLineStats; /** * Lightweight wrapper for an image scanline, used for read and write. *

- * This object can be (usually it is) reused while iterating over the image lines. + * This object can be (usually it is) reused while iterating over the image + * lines. *

* See scanline field, to understand the format. */ @@ -18,21 +19,25 @@ public class ImageLine { private int rown = 0; /** - * The 'scanline' is an array of integers, corresponds to an image line (row). + * The 'scanline' is an array of integers, corresponds to an image line + * (row). *

- * Except for 'packed' formats (gray/indexed with 1-2-4 bitdepth) each int is a "sample" (one for - * channel), (0-255 or 0-65535) in the corresponding PNG sequence: R G B R G B... or + * Except for 'packed' formats (gray/indexed with 1-2-4 bitdepth) each + * int is a "sample" (one for channel), (0-255 or 0-65535) in + * the corresponding PNG sequence: R G B R G B... or * R G B A R G B A... * or g g g ... or i i i (palette index) *

- * For bitdepth=1/2/4 , and if samplesUnpacked=false, each value is a PACKED byte! + * For bitdepth=1/2/4 , and if samplesUnpacked=false, each value is a PACKED + * byte! *

- * To convert a indexed line to RGB balues, see ImageLineHelper.palIdx2RGB() (you can't do the reverse) + * To convert a indexed line to RGB balues, see + * ImageLineHelper.palIdx2RGB() (you can't do the reverse) */ public final int[] scanline; /** - * Same as {@link #scanline}, but with one byte per sample. Only one of scanline and scanlineb is valid - this - * depends on {@link #sampleType} + * Same as {@link #scanline}, but with one byte per sample. Only one of + * scanline and scanlineb is valid - this depends on {@link #sampleType} */ public final byte[] scanlineb; @@ -53,10 +58,11 @@ public class ImageLine { public final SampleType sampleType; /** - * true: each element of the scanline array represents a sample always, even for internally packed PNG formats + * true: each element of the scanline array represents a sample always, even + * for internally packed PNG formats * - * false: if the original image was of packed type (bit depth less than 8) we keep samples packed in a single array - * element + * false: if the original image was of packed type (bit depth less than 8) + * we keep samples packed in a single array element */ public final boolean samplesUnpacked; @@ -70,11 +76,14 @@ public class ImageLine { /** * * @param imgInfo - * Inmutable ImageInfo, basic parameter of the image we are reading or writing + * Inmutable ImageInfo, basic parameter of the image we are + * reading or writing * @param stype - * INT or BYTE : this determines which scanline is the really used one + * INT or BYTE : this determines which scanline is the really + * used one * @param unpackedMode - * If true, we use unpacked format, even for packed original images + * If true, we use unpacked format, even for packed original + * images * */ public ImageLine(ImageInfo imgInfo, SampleType stype, boolean unpackedMode) { @@ -226,7 +235,10 @@ public class ImageLine { } } - /** size original: samplesPerRow sizeFinal: samplesPerRowPacked (trailing elements are trash!) **/ + /** + * size original: samplesPerRow sizeFinal: samplesPerRowPacked (trailing + * elements are trash!) + **/ static void packInplaceByte(final ImageInfo iminfo, final byte[] src, final byte[] dst, final boolean scaled) { final int bitDepth = iminfo.bitDepth; if (bitDepth >= 8) diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/ImageLineHelper.java b/src/jogl/classes/jogamp/opengl/util/pngj/ImageLineHelper.java index 98f235662..91516a704 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/ImageLineHelper.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/ImageLineHelper.java @@ -5,11 +5,14 @@ import jogamp.opengl.util.pngj.chunks.PngChunkPLTE; import jogamp.opengl.util.pngj.chunks.PngChunkTRNS; /** - * Bunch of utility static methods to process/analyze an image line at the pixel level. + * Bunch of utility static methods to process/analyze an image line at the pixel + * level. *

- * Not essential at all, some methods are probably to be removed if future releases. + * Not essential at all, some methods are probably to be removed if future + * releases. *

- * WARNING: most methods for getting/setting values work currently only for integer base imageLines + * WARNING: most methods for getting/setting values work currently only for + * integer base imageLines */ public class ImageLineHelper { @@ -18,7 +21,8 @@ public class ImageLineHelper { private final static double BIG_VALUE_NEG = Double.MAX_VALUE * (-0.5); /** - * Given an indexed line with a palette, unpacks as a RGB array, or RGBA if a non nul PngChunkTRNS chunk is passed + * Given an indexed line with a palette, unpacks as a RGB array, or RGBA if + * a non nul PngChunkTRNS chunk is passed * * @param line * ImageLine as returned from PngReader @@ -26,7 +30,8 @@ public class ImageLineHelper { * Palette chunk * @param buf * Preallocated array, optional - * @return R G B (A), one sample 0-255 per array element. Ready for pngw.writeRowInt() + * @return R G B (A), one sample 0-255 per array element. Ready for + * pngw.writeRowInt() */ public static int[] palette2rgb(ImageLine line, PngChunkPLTE pal, PngChunkTRNS trns, int[] buf) { boolean isalpha = trns != null; @@ -53,9 +58,12 @@ public class ImageLineHelper { return palette2rgb(line, pal, null, buf); } - /** what follows is pretty uninteresting/untested/obsolete, subject to change */ /** - * Just for basic info or debugging. Shows values for first and last pixel. Does not include alpha + * what follows is pretty uninteresting/untested/obsolete, subject to change + */ + /** + * Just for basic info or debugging. Shows values for first and last pixel. + * Does not include alpha */ public static String infoFirstLastPixels(ImageLine line) { return line.imgInfo.channels == 1 ? String.format("first=(%d) last=(%d)", line.scanline[0], @@ -71,8 +79,8 @@ public class ImageLineHelper { } /** - * Computes some statistics for the line. Not very efficient or elegant, mainly for tests. Only for RGB/RGBA Outputs - * values as doubles (0.0 - 1.0) + * Computes some statistics for the line. Not very efficient or elegant, + * mainly for tests. Only for RGB/RGBA Outputs values as doubles (0.0 - 1.0) */ static class ImageLineStats { public double[] prom = { 0.0, 0.0, 0.0, 0.0 }; // channel averages @@ -237,9 +245,11 @@ public class ImageLineHelper { /** * Unpacks scanline (for bitdepth 1-2-4) into a array int[] *

- * You can (OPTIONALLY) pass an preallocated array, that will be filled and returned. If null, it will be allocated + * You can (OPTIONALLY) pass an preallocated array, that will be filled and + * returned. If null, it will be allocated *

- * If scale==true, it scales the value (just a bit shift) towards 0-255. + * If + * scale==true, it scales the value (just a bit shift) towards 0-255. *

* You probably should use {@link ImageLine#unpackToNewImageLine()} * diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/ImageLines.java b/src/jogl/classes/jogamp/opengl/util/pngj/ImageLines.java index 1e0ab746a..feb50e7b6 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/ImageLines.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/ImageLines.java @@ -3,10 +3,12 @@ package jogamp.opengl.util.pngj; import jogamp.opengl.util.pngj.ImageLine.SampleType; /** - * Wraps in a matrix a set of image rows, not necessarily contiguous - but equispaced. + * Wraps in a matrix a set of image rows, not necessarily contiguous - but + * equispaced. * - * The fields mirrors those of {@link ImageLine}, and you can access each row as a ImageLine backed by the matrix row, - * see {@link #getImageLineAtMatrixRow(int)} + * The fields mirrors those of {@link ImageLine}, and you can access each row as + * a ImageLine backed by the matrix row, see + * {@link #getImageLineAtMatrixRow(int)} */ public class ImageLines { @@ -23,7 +25,8 @@ public class ImageLines { public final byte[][] scanlinesb; /** - * Allocates a matrix to store {@code nRows} image rows. See {@link ImageLine} and {@link PngReader#readRowsInt()} + * Allocates a matrix to store {@code nRows} image rows. See + * {@link ImageLine} and {@link PngReader#readRowsInt()} * {@link PngReader#readRowsByte()} * * @param imgInfo @@ -54,8 +57,9 @@ public class ImageLines { } /** - * Warning: this always returns a valid matrix row (clamping on 0 : nrows-1, and rounding down) Eg: - * rowOffset=4,rowStep=2 imageRowToMatrixRow(17) returns 6 , imageRowToMatrixRow(1) returns 0 + * Warning: this always returns a valid matrix row (clamping on 0 : nrows-1, + * and rounding down) Eg: rowOffset=4,rowStep=2 imageRowToMatrixRow(17) + * returns 6 , imageRowToMatrixRow(1) returns 0 */ public int imageRowToMatrixRow(int imrow) { int r = (imrow - rowOffset) / rowStep; @@ -86,9 +90,11 @@ public class ImageLines { * Returns a ImageLine is backed by the matrix, no allocation done * * @param mrow - * Matrix row, from 0 to nRows This is not necessarily the image row, see - * {@link #imageRowToMatrixRow(int)} and {@link #matrixRowToImageRow(int)} - * @return A new ImageLine, backed by the matrix, with the correct ('real') rownumber + * Matrix row, from 0 to nRows This is not necessarily the image + * row, see {@link #imageRowToMatrixRow(int)} and + * {@link #matrixRowToImageRow(int)} + * @return A new ImageLine, backed by the matrix, with the correct ('real') + * rownumber */ public ImageLine getImageLineAtMatrixRow(int mrow) { if (mrow < 0 || mrow > nRows) diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/PngHelperInternal.java b/src/jogl/classes/jogamp/opengl/util/pngj/PngHelperInternal.java index 63edf8d17..a950c6b33 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/PngHelperInternal.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/PngHelperInternal.java @@ -144,18 +144,23 @@ public class PngHelperInternal { } } - public static void skipBytes(InputStream is, int len) { - byte[] buf = new byte[8192 * 4]; - int read, remain = len; + public static void skipBytes(InputStream is, long len) { try { - while (remain > 0) { - read = is.read(buf, 0, remain > buf.length ? buf.length : remain); - if (read < 0) - throw new PngjInputException("error reading (skipping) : EOF"); - remain -= read; + while (len > 0) { + long n1 = is.skip(len); + if (n1 > 0) { + len -= n1; + } else if (n1 == 0) { // should we retry? lets read one byte + if (is.read() == -1) // EOF + break; + else + len--; + } else + // negative? this should never happen but... + throw new IOException("skip() returned a negative value ???"); } } catch (IOException e) { - throw new PngjInputException("error reading (skipping)", e); + throw new PngjInputException(e); } } diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/PngIDatChunkInputStream.java b/src/jogl/classes/jogamp/opengl/util/pngj/PngIDatChunkInputStream.java index 6cc39b0e6..cdad09809 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/PngIDatChunkInputStream.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/PngIDatChunkInputStream.java @@ -37,7 +37,8 @@ class PngIDatChunkInputStream extends InputStream { List foundChunksInfo = new ArrayList(); /** - * Constructor must be called just after reading length and id of first IDAT chunk + * Constructor must be called just after reading length and id of first IDAT + * chunk **/ PngIDatChunkInputStream(InputStream iStream, int lenFirstChunk, long offset) { this.offset = offset; @@ -95,7 +96,8 @@ class PngIDatChunkInputStream extends InputStream { } /** - * sometimes last row read does not fully consumes the chunk here we read the reamaing dummy bytes + * sometimes last row read does not fully consumes the chunk here we read + * the reamaing dummy bytes */ void forceChunkEnd() { if (!ended) { @@ -108,7 +110,8 @@ class PngIDatChunkInputStream extends InputStream { } /** - * This can return less than len, but never 0 Returns -1 if "pseudo file" ended prematurely. That is our error. + * This can return less than len, but never 0 Returns -1 if "pseudo file" + * ended prematurely. That is our error. */ @Override public int read(byte[] b, int off, int len) throws IOException { diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/PngWriter.java b/src/jogl/classes/jogamp/opengl/util/pngj/PngWriter.java index 601cd96c0..3e684a881 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/PngWriter.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/PngWriter.java @@ -83,8 +83,9 @@ public class PngWriter { } /** - * Constructs a new PngWriter from a output stream. After construction nothing is writen yet. You still can set some - * parameters (compression, filters) and queue chunks before start writing the pixels. + * Constructs a new PngWriter from a output stream. After construction + * nothing is writen yet. You still can set some parameters (compression, + * filters) and queue chunks before start writing the pixels. *

* See also FileHelper.createPngWriter() if available. * @@ -418,13 +419,15 @@ public class PngWriter { /** * Copies first (pre IDAT) ancillary chunks from a PngReader. *

- * Should be called when creating an image from another, before starting writing lines, to copy relevant chunks. + * Should be called when creating an image from another, before starting + * writing lines, to copy relevant chunks. *

* * @param reader * : PngReader object, already opened. * @param copy_mask - * : Mask bit (OR), see ChunksToWrite.COPY_XXX constants + * : Mask bit (OR), see ChunksToWrite.COPY_XXX + * constants */ public void copyChunksFirst(PngReader reader, int copy_mask) { copyChunks(reader, copy_mask, false); @@ -433,14 +436,15 @@ public class PngWriter { /** * Copies last (post IDAT) ancillary chunks from a PngReader. *

- * Should be called when creating an image from another, after writing all lines, before closing the writer, to copy - * additional chunks. + * Should be called when creating an image from another, after writing all + * lines, before closing the writer, to copy additional chunks. *

* * @param reader * : PngReader object, already opened and fully read. * @param copy_mask - * : Mask bit (OR), see ChunksToWrite.COPY_XXX constants + * : Mask bit (OR), see ChunksToWrite.COPY_XXX + * constants */ public void copyChunksLast(PngReader reader, int copy_mask) { copyChunks(reader, copy_mask, true); @@ -449,8 +453,8 @@ public class PngWriter { /** * Computes compressed size/raw size, approximate. *

- * Actually: compressed size = total size of IDAT data , raw size = uncompressed pixel bytes = rows * (bytesPerRow + - * 1). + * Actually: compressed size = total size of IDAT data , raw size = + * uncompressed pixel bytes = rows * (bytesPerRow + 1). * * This must be called after pngw.end() */ @@ -463,7 +467,8 @@ public class PngWriter { } /** - * Finalizes the image creation and closes the stream. This MUST be called after writing the lines. + * Finalizes the image creation and closes the stream. This MUST be called + * after writing the lines. */ public void end() { if (rowNum != imgInfo.rows - 1) @@ -525,15 +530,17 @@ public class PngWriter { * See also setCompLevel() * * @param filterType - * One of the five prediction types or strategy to choose it (see PngFilterType) Recommended - * values: DEFAULT (default) or AGGRESIVE + * One of the five prediction types or strategy to choose it (see + * PngFilterType) Recommended values: DEFAULT + * (default) or AGGRESIVE */ public void setFilterType(FilterType filterType) { filterStrat = new FilterWriteStrategy(imgInfo, filterType); } /** - * Sets maximum size of IDAT fragments. This has little effect on performance you should rarely call this + * Sets maximum size of IDAT fragments. This has little effect on + * performance you should rarely call this *

* * @param idatMaxSize @@ -553,7 +560,8 @@ public class PngWriter { } /** - * Deflater strategy: one of Deflater.FILTERED Deflater.HUFFMAN_ONLY Deflater.DEFAULT_STRATEGY + * Deflater strategy: one of Deflater.FILTERED Deflater.HUFFMAN_ONLY + * Deflater.DEFAULT_STRATEGY *

* Default: Deflater.FILTERED . This should be changed very rarely. */ @@ -562,8 +570,8 @@ public class PngWriter { } /** - * Writes line, checks that the row number is consistent with that of the ImageLine See writeRow(int[] newrow, int - * rown) + * Writes line, checks that the row number is consistent with that of the + * ImageLine See writeRow(int[] newrow, int rown) * * @deprecated Better use writeRow(ImageLine imgline, int rownumber) */ @@ -607,18 +615,22 @@ public class PngWriter { /** * Writes a full image row. *

- * This must be called sequentially from n=0 to n=rows-1 One integer per sample , in the natural order: R G B R G B - * ... (or R G B A R G B A... if has alpha) The values should be between 0 and 255 for 8 bitspc images, and between - * 0- 65535 form 16 bitspc images (this applies also to the alpha channel if present) The array can be reused. + * This must be called sequentially from n=0 to n=rows-1 One integer per + * sample , in the natural order: R G B R G B ... (or R G B A R G B A... if + * has alpha) The values should be between 0 and 255 for 8 bitspc images, + * and between 0- 65535 form 16 bitspc images (this applies also to the + * alpha channel if present) The array can be reused. *

- * Warning: the array might be modified in some cases (unpacked row with low bitdepth) + * Warning: the array might be modified in some cases (unpacked row with low + * bitdepth) *

* * @param newrow - * Array of pixel values. Warning: the array size should be exact (samplesPerRowP) + * Array of pixel values. Warning: the array size should be exact + * (samplesPerRowP) * @param rown - * Row number, from 0 (top) to rows-1 (bottom). This is just used as a check. Pass -1 if you want to - * autocompute it + * Row number, from 0 (top) to rows-1 (bottom). This is just used + * as a check. Pass -1 if you want to autocompute it */ public void writeRowInt(int[] newrow, int rown) { prepareEncodeRow(rown); @@ -627,8 +639,9 @@ public class PngWriter { } /** - * Same semantics as writeRowInt but using bytes. Each byte is still a sample. If 16bitdepth, we are passing only - * the most significant byte (and hence losing some info) + * Same semantics as writeRowInt but using bytes. Each byte is still a + * sample. If 16bitdepth, we are passing only the most significant byte (and + * hence losing some info) * * @see PngWriter#writeRowInt(int[], int) */ @@ -659,12 +672,15 @@ public class PngWriter { } /** - * If false (default), and image has bitdepth 1-2-4, the scanlines passed are assumed to be already packed. + * If false (default), and image has bitdepth 1-2-4, the scanlines passed + * are assumed to be already packed. *

- * If true, each element is a sample, the writer will perform the packing if necessary. + * If true, each element is a sample, the writer will perform the packing if + * necessary. *

- * Warning: when using {@link #writeRow(ImageLine, int)} (recommended) the packed flag of the ImageLine - * object overrides (and overwrites!) this field. + * Warning: when using {@link #writeRow(ImageLine, int)} (recommended) the + * packed flag of the ImageLine object overrides (and overwrites!) + * this field. */ public void setUseUnPackedMode(boolean useUnpackedMode) { this.unpackedMode = useUnpackedMode; diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/PngjExceptionInternal.java b/src/jogl/classes/jogamp/opengl/util/pngj/PngjExceptionInternal.java index 963abc50e..c429b893b 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/PngjExceptionInternal.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/PngjExceptionInternal.java @@ -1,7 +1,8 @@ package jogamp.opengl.util.pngj; /** - * Exception for anomalous internal problems (sort of asserts) that point to some issue with the library + * Exception for anomalous internal problems (sort of asserts) that point to + * some issue with the library * * @author Hernan J Gonzalez * diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/PngjUnsupportedException.java b/src/jogl/classes/jogamp/opengl/util/pngj/PngjUnsupportedException.java index 0801e33bb..f68458d19 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/PngjUnsupportedException.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/PngjUnsupportedException.java @@ -1,7 +1,8 @@ package jogamp.opengl.util.pngj; /** - * Exception thrown because of some valid feature of PNG standard that this library does not support + * Exception thrown because of some valid feature of PNG standard that this + * library does not support */ public class PngjUnsupportedException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/ProgressiveOutputStream.java b/src/jogl/classes/jogamp/opengl/util/pngj/ProgressiveOutputStream.java index a5bad666c..4516a0886 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/ProgressiveOutputStream.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/ProgressiveOutputStream.java @@ -4,7 +4,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; /** - * stream that outputs to memory and allows to flush fragments every 'size' bytes to some other destination + * stream that outputs to memory and allows to flush fragments every 'size' + * bytes to some other destination */ abstract class ProgressiveOutputStream extends ByteArrayOutputStream { private final int size; @@ -50,8 +51,8 @@ abstract class ProgressiveOutputStream extends ByteArrayOutputStream { } /** - * if it's time to flush data (or if forced==true) calls abstract method flushBuffer() and cleans those bytes from - * own buffer + * if it's time to flush data (or if forced==true) calls abstract method + * flushBuffer() and cleans those bytes from own buffer */ private final void checkFlushBuffer(boolean forced) { while (forced || count >= size) { diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkLoadBehaviour.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkLoadBehaviour.java index 03d50c2c4..82ab3bcf9 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkLoadBehaviour.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkLoadBehaviour.java @@ -1,7 +1,8 @@ package jogamp.opengl.util.pngj.chunks; /** - * Defines gral strategy about what to do with ancillary (non-critical) chunks when reading + * Defines gral strategy about what to do with ancillary (non-critical) chunks + * when reading */ public enum ChunkLoadBehaviour { /** @@ -9,7 +10,8 @@ public enum ChunkLoadBehaviour { */ LOAD_CHUNK_NEVER, /** - * Ancillary chunks are loaded only if 'known' (registered with the factory). + * Ancillary chunks are loaded only if 'known' (registered with the + * factory). */ LOAD_CHUNK_KNOWN, /** @@ -19,7 +21,8 @@ public enum ChunkLoadBehaviour { LOAD_CHUNK_IF_SAFE, /** * Load all chunks.
- * Notice that other restrictions might apply, see PngReader.skipChunkMaxSize PngReader.skipChunkIds + * Notice that other restrictions might apply, see + * PngReader.skipChunkMaxSize PngReader.skipChunkIds */ LOAD_CHUNK_ALWAYS; } diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkRaw.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkRaw.java index 8dd0ef476..3aba26cca 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkRaw.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkRaw.java @@ -13,13 +13,15 @@ import jogamp.opengl.util.pngj.PngjOutputException; /** * Raw (physical) chunk. *

- * Short lived object, to be created while serialing/deserializing Do not reuse it for different chunks.
+ * Short lived object, to be created while serialing/deserializing Do not reuse + * it for different chunks.
* See http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html */ public class ChunkRaw { /** - * The length counts only the data field, not itself, the chunk type code, or the CRC. Zero is a valid length. - * Although encoders and decoders should treat the length as unsigned, its value must not exceed 231-1 bytes. + * The length counts only the data field, not itself, the chunk type code, + * or the CRC. Zero is a valid length. Although encoders and decoders should + * treat the length as unsigned, its value must not exceed 231-1 bytes. */ public final int len; @@ -29,12 +31,14 @@ public class ChunkRaw { public final byte[] idbytes = new byte[4]; /** - * The data bytes appropriate to the chunk type, if any. This field can be of zero length. Does not include crc + * The data bytes appropriate to the chunk type, if any. This field can be + * of zero length. Does not include crc */ public byte[] data = null; /** - * A 4-byte CRC (Cyclic Redundancy Check) calculated on the preceding bytes in the chunk, including the chunk type - * code and chunk data fields, but not including the length field. + * A 4-byte CRC (Cyclic Redundancy Check) calculated on the preceding bytes + * in the chunk, including the chunk type code and chunk data fields, but + * not including the length field. */ private int crcval = 0; @@ -71,7 +75,8 @@ public class ChunkRaw { } /** - * Computes the CRC and writes to the stream. If error, a PngjOutputException is thrown + * Computes the CRC and writes to the stream. If error, a + * PngjOutputException is thrown */ public void writeChunk(OutputStream os) { if (idbytes.length != 4) @@ -85,8 +90,8 @@ public class ChunkRaw { } /** - * position before: just after chunk id. positon after: after crc Data should be already allocated. Checks CRC - * Return number of byte read. + * position before: just after chunk id. positon after: after crc Data + * should be already allocated. Checks CRC Return number of byte read. */ public int readChunkData(InputStream is, boolean checkCrc) { PngHelperInternal.readBytes(is, data, 0, len); diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunksList.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunksList.java index ad788f154..5ce94ff9f 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunksList.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunksList.java @@ -49,8 +49,8 @@ public class ChunksList { } /** - * Returns a copy of the list (but the chunks are not copied) This should not be used for general metadata - * handling + * Returns a copy of the list (but the chunks are not copied) This + * should not be used for general metadata handling */ public ArrayList getChunks() { return new ArrayList(chunks); @@ -96,7 +96,8 @@ public class ChunksList { } /** - * If innerid!=null and the chunk is PngChunkTextVar or PngChunkSPLT, it's filtered by that id + * If innerid!=null and the chunk is PngChunkTextVar or PngChunkSPLT, it's + * filtered by that id * * @param id * @return innerid Only used for text and SPLT chunks @@ -119,8 +120,9 @@ public class ChunksList { /** * Returns only one chunk or null if nothing found - does not include queued *

- * If more than one chunk is found, then an exception is thrown (failifMultiple=true or chunk is single) or the last - * one is returned (failifMultiple=false) + * If more than one chunk is found, then an exception is thrown + * (failifMultiple=true or chunk is single) or the last one is returned + * (failifMultiple=false) **/ public PngChunk getById1(final String id, final boolean failIfMultiple) { return getById1(id, null, failIfMultiple); @@ -129,8 +131,9 @@ public class ChunksList { /** * Returns only one chunk or null if nothing found - does not include queued *

- * If more than one chunk (after filtering by inner id) is found, then an exception is thrown (failifMultiple=true - * or chunk is single) or the last one is returned (failifMultiple=false) + * If more than one chunk (after filtering by inner id) is found, then an + * exception is thrown (failifMultiple=true or chunk is single) or the last + * one is returned (failifMultiple=false) **/ public PngChunk getById1(final String id, final String innerid, final boolean failIfMultiple) { List list = getById(id, innerid); diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunksListForWrite.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunksListForWrite.java index 204c4c2a5..e76456ad4 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunksListForWrite.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunksListForWrite.java @@ -13,7 +13,8 @@ import jogamp.opengl.util.pngj.PngjOutputException; public class ChunksListForWrite extends ChunksList { /** - * chunks not yet writen - does not include IHDR, IDAT, END, perhaps yes PLTE + * chunks not yet writen - does not include IHDR, IDAT, END, perhaps yes + * PLTE */ private final List queuedChunks = new ArrayList(); @@ -67,8 +68,9 @@ public class ChunksListForWrite extends ChunksList { /** * Remove Chunk: only from queued * - * WARNING: this depends on c.equals() implementation, which is straightforward for SingleChunks. For - * MultipleChunks, it will normally check for reference equality! + * WARNING: this depends on c.equals() implementation, which is + * straightforward for SingleChunks. For MultipleChunks, it will normally + * check for reference equality! */ public boolean removeChunk(PngChunk c) { return queuedChunks.remove(c); @@ -87,7 +89,8 @@ public class ChunksListForWrite extends ChunksList { } /** - * this should be called only for ancillary chunks and PLTE (groups 1 - 3 - 5) + * this should be called only for ancillary chunks and PLTE (groups 1 - 3 - + * 5) **/ private static boolean shouldWrite(PngChunk c, int currentGroup) { if (currentGroup == CHUNK_GROUP_2_PLTE) diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunk.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunk.java index 1d630591e..a45979ec2 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunk.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunk.java @@ -12,13 +12,16 @@ import jogamp.opengl.util.pngj.PngjExceptionInternal; * Represents a instance of a PNG chunk. *

* See http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks - * .html + * href="http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html">http://www + * .libpng.org/pub/png/spec/1.2/PNG-Chunks .html *

- * Concrete classes should extend {@link PngChunkSingle} or {@link PngChunkMultiple} + * Concrete classes should extend {@link PngChunkSingle} or + * {@link PngChunkMultiple} *

- * Note that some methods/fields are type-specific (getOrderingConstraint(), allowsMultiple()),
- * some are 'almost' type-specific (id,crit,pub,safe; the exception is PngUKNOWN),
+ * Note that some methods/fields are type-specific (getOrderingConstraint(), + * allowsMultiple()),
+ * some are 'almost' type-specific (id,crit,pub,safe; the exception is + * PngUKNOWN),
* and the rest are instance-specific */ public abstract class PngChunk { @@ -35,8 +38,9 @@ public abstract class PngChunk { protected final ImageInfo imgInfo; /** - * Possible ordering constraint for a PngChunk type -only relevant for ancillary chunks. Theoretically, there could - * be more general constraints, but these cover the constraints for standard chunks. + * Possible ordering constraint for a PngChunk type -only relevant for + * ancillary chunks. Theoretically, there could be more general constraints, + * but these cover the constraints for standard chunks. */ public enum ChunkOrderingConstraint { /** @@ -83,8 +87,8 @@ public abstract class PngChunk { /** * This static map defines which PngChunk class correspond to which ChunkID *

- * The client can add other chunks to this map statically, before reading an image, calling - * PngChunk.factoryRegister(id,class) + * The client can add other chunks to this map statically, before reading an + * image, calling PngChunk.factoryRegister(id,class) */ private final static Map> factoryMap = new HashMap>(); static { @@ -114,8 +118,9 @@ public abstract class PngChunk { /** * Registers a chunk-id (4 letters) to be associated with a PngChunk class *

- * This method should be called by user code that wants to add some chunks (not implmemented in this library) to the - * factory, so that the PngReader knows about it. + * This method should be called by user code that wants to add some chunks + * (not implmemented in this library) to the factory, so that the PngReader + * knows about it. */ public static void factoryRegister(String chunkId, Class chunkClass) { factoryMap.put(chunkId, chunkClass); @@ -124,9 +129,11 @@ public abstract class PngChunk { /** * True if the chunk-id type is known. *

- * A chunk is known if we recognize its class, according with factoryMap + * A chunk is known if we recognize its class, according with + * factoryMap *

- * This is not necessarily the same as being "STANDARD", or being implemented in this library + * This is not necessarily the same as being "STANDARD", or being + * implemented in this library *

* Unknown chunks will be parsed as instances of {@link PngChunkUNKNOWN} */ @@ -143,7 +150,8 @@ public abstract class PngChunk { } /** - * This factory creates the corresponding chunk and parses the raw chunk. This is used when reading. + * This factory creates the corresponding chunk and parses the raw chunk. + * This is used when reading. */ public static PngChunk factory(ChunkRaw chunk, ImageInfo info) { PngChunk c = factoryFromId(ChunkHelper.toString(chunk.idbytes), info); @@ -153,7 +161,8 @@ public abstract class PngChunk { } /** - * Creates one new blank chunk of the corresponding type, according to factoryMap (PngChunkUNKNOWN if not known) + * Creates one new blank chunk of the corresponding type, according to + * factoryMap (PngChunkUNKNOWN if not known) */ public static PngChunk factoryFromId(String cid, ImageInfo info) { PngChunk chunk = null; @@ -189,7 +198,8 @@ public abstract class PngChunk { } /** - * In which "chunkGroup" (see {@link ChunksList}for definition) this chunks instance was read or written. + * In which "chunkGroup" (see {@link ChunksList}for definition) this chunks + * instance was read or written. *

* -1 if not read or written (eg, queued) */ @@ -236,16 +246,16 @@ public abstract class PngChunk { } /** - * Creates the physical chunk. This is used when writing (serialization). Each particular chunk class implements its - * own logic. + * Creates the physical chunk. This is used when writing (serialization). + * Each particular chunk class implements its own logic. * * @return A newly allocated and filled raw chunk */ public abstract ChunkRaw createRawChunk(); /** - * Parses raw chunk and fill inside data. This is used when reading (deserialization). Each particular chunk class - * implements its own logic. + * Parses raw chunk and fill inside data. This is used when reading + * (deserialization). Each particular chunk class implements its own logic. */ public abstract void parseFromRaw(ChunkRaw c); @@ -254,7 +264,8 @@ public abstract class PngChunk { *

* This is used when copying chunks from a reader to a writer *

- * It should normally be a deep copy, and after the cloning this.equals(other) should return true + * It should normally be a deep copy, and after the cloning + * this.equals(other) should return true */ public abstract void cloneDataFromRead(PngChunk other); diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkIDAT.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkIDAT.java index b816db205..911513c0d 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkIDAT.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkIDAT.java @@ -7,7 +7,8 @@ import jogamp.opengl.util.pngj.ImageInfo; *

* see http://www.w3.org/TR/PNG/#11IDAT *

- * This is dummy placeholder - we write/read this chunk (actually several) by special code. + * This is dummy placeholder - we write/read this chunk (actually several) by + * special code. */ public class PngChunkIDAT extends PngChunkMultiple { public final static String ID = ChunkHelper.IDAT; diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkMultiple.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkMultiple.java index 696edd431..d44250a2f 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkMultiple.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkMultiple.java @@ -17,7 +17,8 @@ public abstract class PngChunkMultiple extends PngChunk { } /** - * NOTE: this chunk uses the default Object's equals() hashCode() implementation. + * NOTE: this chunk uses the default Object's equals() hashCode() + * implementation. * * This is the right thing to do, normally. * diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkSingle.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkSingle.java index 286f39db0..5247169e0 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkSingle.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkSingle.java @@ -3,7 +3,8 @@ package jogamp.opengl.util.pngj.chunks; import jogamp.opengl.util.pngj.ImageInfo; /** - * PNG chunk type (abstract) that does not allow multiple instances in same image. + * PNG chunk type (abstract) that does not allow multiple instances in same + * image. */ public abstract class PngChunkSingle extends PngChunk { diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngMetadata.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngMetadata.java index 52d1b22c1..ecf8b98c3 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngMetadata.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngMetadata.java @@ -7,13 +7,13 @@ import jogamp.opengl.util.pngj.PngHelperInternal; import jogamp.opengl.util.pngj.PngjException; /** - * We consider "image metadata" every info inside the image except for the most basic image info (IHDR chunk - ImageInfo - * class) and the pixels values. + * We consider "image metadata" every info inside the image except for the most + * basic image info (IHDR chunk - ImageInfo class) and the pixels values. *

* This includes the palette (if present) and all the ancillary chunks *

- * This class provides a wrapper over the collection of chunks of a image (read or to write) and provides some high - * level methods to access them + * This class provides a wrapper over the collection of chunks of a image (read + * or to write) and provides some high level methods to access them */ public class PngMetadata { private final ChunksList chunkList; @@ -31,8 +31,9 @@ public class PngMetadata { /** * Queues the chunk at the writer *

- * lazyOverwrite: if true, checks if there is a queued "equivalent" chunk and if so, overwrites it. However if that - * not check for already written chunks. + * lazyOverwrite: if true, checks if there is a queued "equivalent" chunk + * and if so, overwrites it. However if that not check for already written + * chunks. */ public void queueChunk(final PngChunk c, boolean lazyOverwrite) { ChunksListForWrite cl = getChunkListW(); @@ -87,7 +88,8 @@ public class PngMetadata { * Creates a time chunk with current time, less secsAgo seconds *

* - * @return Returns the created-queued chunk, just in case you want to examine or modify it + * @return Returns the created-queued chunk, just in case you want to + * examine or modify it */ public PngChunkTIME setTimeNow(int secsAgo) { PngChunkTIME c = new PngChunkTIME(chunkList.imageInfo); @@ -104,7 +106,8 @@ public class PngMetadata { * Creates a time chunk with diven date-time *

* - * @return Returns the created-queued chunk, just in case you want to examine or modify it + * @return Returns the created-queued chunk, just in case you want to + * examine or modify it */ public PngChunkTIME setTimeYMDHMS(int yearx, int monx, int dayx, int hourx, int minx, int secx) { PngChunkTIME c = new PngChunkTIME(chunkList.imageInfo); @@ -137,7 +140,8 @@ public class PngMetadata { * (arbitrary, should be latin1 if useLatin1) * @param useLatin1 * @param compress - * @return Returns the created-queued chunks, just in case you want to examine, touch it + * @return Returns the created-queued chunks, just in case you want to + * examine, touch it */ public PngChunkTextVar setText(String k, String val, boolean useLatin1, boolean compress) { if (compress && !useLatin1) @@ -180,7 +184,8 @@ public class PngMetadata { } /** - * Returns empty if not found, concatenated (with newlines) if multiple! - and trimmed + * Returns empty if not found, concatenated (with newlines) if multiple! - + * and trimmed *

* Use getTxtsForKey() if you don't want this behaviour */ @@ -204,7 +209,8 @@ public class PngMetadata { } /** - * Creates a new empty palette chunk, queues it for write and return it to the caller, who should fill its entries + * Creates a new empty palette chunk, queues it for write and return it to + * the caller, who should fill its entries */ public PngChunkPLTE createPLTEChunk() { PngChunkPLTE plte = new PngChunkPLTE(chunkList.imageInfo); @@ -222,7 +228,8 @@ public class PngMetadata { } /** - * Creates a new empty TRNS chunk, queues it for write and return it to the caller, who should fill its entries + * Creates a new empty TRNS chunk, queues it for write and return it to the + * caller, who should fill its entries */ public PngChunkTRNS createTRNSChunk() { PngChunkTRNS trns = new PngChunkTRNS(chunkList.imageInfo); -- cgit v1.2.3 From 18df35aa301c29bc6a85f8f8eabe0bd9407d8be6 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 9 Jul 2013 16:41:45 +0200 Subject: PNGJ: Bump to git sha1 a0b1101ba2d37de39428ed55c8189502e24a3125 of https://code.google.com/p/pngj Part 2/2 - Started w/ 51427b92a2d9cd3fc619854e26536c9c6adad947 Missed rejected patches .. --- make/scripts/tests.sh | 4 +- .../classes/jogamp/opengl/util/pngj/PngReader.java | 1940 ++++++++++---------- .../opengl/util/pngj/chunks/ChunkHelper.java | 550 +++--- .../opengl/util/pngj/chunks/PngChunkTRNS.java | 284 ++- 4 files changed, 1440 insertions(+), 1338 deletions(-) (limited to 'src/jogl/classes/jogamp/opengl/util') diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index bc37f2845..ca4dc63ae 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -405,7 +405,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle02NEWT #testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00aNEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00bNEWT $* -testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00cNEWT $* +#testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00cNEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode01aNEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode01bNEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode01cNEWT $* @@ -551,7 +551,7 @@ testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00cNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGImage00NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGImage01NEWT $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileAWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileNEWT $* +testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileNEWT $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestGLReadBufferUtilTextureIOWrite01AWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestGLReadBufferUtilTextureIOWrite01NEWT $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestGLReadBufferUtilTextureIOWrite02AWT $* diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/PngReader.java b/src/jogl/classes/jogamp/opengl/util/pngj/PngReader.java index 8cb4295a5..e42dd8733 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/PngReader.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/PngReader.java @@ -1,940 +1,1000 @@ -package jogamp.opengl.util.pngj; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.HashSet; -import java.util.zip.CRC32; -import java.util.zip.InflaterInputStream; - -import jogamp.opengl.util.pngj.ImageInfo; -import jogamp.opengl.util.pngj.ImageLine.SampleType; -import jogamp.opengl.util.pngj.chunks.ChunkHelper; -import jogamp.opengl.util.pngj.chunks.ChunkLoadBehaviour; -import jogamp.opengl.util.pngj.chunks.ChunkRaw; -import jogamp.opengl.util.pngj.chunks.ChunksList; -import jogamp.opengl.util.pngj.chunks.PngChunk; -import jogamp.opengl.util.pngj.chunks.PngChunkIDAT; -import jogamp.opengl.util.pngj.chunks.PngChunkIHDR; -import jogamp.opengl.util.pngj.chunks.PngChunkSkipped; -import jogamp.opengl.util.pngj.chunks.PngMetadata; - -/** - * Reads a PNG image, line by line. - *

- * The reading sequence is as follows:
- * 1. At construction time, the header and IHDR chunk are read (basic image info)
- * 2. Afterwards you can set some additional global options. Eg. {@link #setUnpackedMode(boolean)}, - * {@link #setCrcCheckDisabled()}.
- * 3. Optional: If you call getMetadata() or getChunksLisk() before start reading the rows, all the chunks before IDAT - * are automatically loaded and available
- * 4a. The rows are read onen by one of the readRowXXX methods: {@link #readRowInt(int)}, - * {@link PngReader#readRowByte(int)}, etc, in order, from 0 to nrows-1 (you can skip or repeat rows, but not go - * backwards)
- * 4b. Alternatively, you can read all rows, or a subset, in a single call: {@link #readRowsInt()}, - * {@link #readRowsByte()} ,etc. In general this consumes more memory, but for interlaced images this is equally - * efficient, and more so if reading a small subset of rows.
- * 5. Read of the last row auyomatically loads the trailing chunks, and ends the reader.
- * 6. end() forcibly finishes/aborts the reading and closes the stream - */ -public class PngReader { - /** - * Basic image info - final and inmutable. - */ - public final ImageInfo imgInfo; - - /** - * not necesarily a filename, can be a description - merely informative - */ - protected final String filename; - - private ChunkLoadBehaviour chunkLoadBehaviour = ChunkLoadBehaviour.LOAD_CHUNK_ALWAYS; // see setter/getter - - private boolean shouldCloseStream = true; // true: closes stream after ending - see setter/getter - - // some performance/defensive limits - private long maxTotalBytesRead = 200 * 1024 * 1024; // 200MB - private int maxBytesMetadata = 5 * 1024 * 1024; // for ancillary chunks - see setter/getter - private int skipChunkMaxSize = 2 * 1024 * 1024; // chunks exceeding this size will be skipped (nor even CRC checked) - private String[] skipChunkIds = { "fdAT" }; // chunks with these ids will be skipped (nor even CRC checked) - private HashSet skipChunkIdsSet; // lazily created from skipChunksById - - protected final PngMetadata metadata; // this a wrapper over chunks - protected final ChunksList chunksList; - - protected ImageLine imgLine; - - // line as bytes, counting from 1 (index 0 is reserved for filter type) - protected byte[] rowb = null; - protected byte[] rowbprev = null; // rowb previous - protected byte[] rowbfilter = null; // current line 'filtered': exactly as in uncompressed stream - - // only set for interlaced PNG - private final boolean interlaced; - private final PngDeinterlacer deinterlacer; - - private boolean crcEnabled = true; - - // this only influences the 1-2-4 bitdepth format - private boolean unpackedMode = false; - /** - * Current chunk group, (0-6) already read or reading - *

- * see {@link ChunksList} - */ - protected int currentChunkGroup = -1; - - protected int rowNum = -1; // last read row number, starting from 0 - private long offset = 0; // offset in InputStream = bytes read - private int bytesChunksLoaded; // bytes loaded from anciallary chunks - - protected final InputStream inputStream; - protected InflaterInputStream idatIstream; - protected PngIDatChunkInputStream iIdatCstream; - - protected CRC32 crctest; // If set to non null, it gets a CRC of the unfiltered bytes, to check for images equality - - /** - * Constructs a PngReader from an InputStream. - *

- * See also FileHelper.createPngReader(File f) if available. - * - * Reads only the signature and first chunk (IDHR) - * - * @param filenameOrDescription - * : Optional, can be a filename or a description. Just for error/debug messages - * - */ - public PngReader(InputStream inputStream, String filenameOrDescription) { - this.filename = filenameOrDescription == null ? "" : filenameOrDescription; - this.inputStream = inputStream; - this.chunksList = new ChunksList(null); - this.metadata = new PngMetadata(chunksList); - // starts reading: signature - byte[] pngid = new byte[8]; - PngHelperInternal.readBytes(inputStream, pngid, 0, pngid.length); - offset += pngid.length; - if (!Arrays.equals(pngid, PngHelperInternal.getPngIdSignature())) - throw new PngjInputException("Bad PNG signature"); - // reads first chunk - currentChunkGroup = ChunksList.CHUNK_GROUP_0_IDHR; - int clen = PngHelperInternal.readInt4(inputStream); - offset += 4; - if (clen != 13) - throw new PngjInputException("IDHR chunk len != 13 ?? " + clen); - byte[] chunkid = new byte[4]; - PngHelperInternal.readBytes(inputStream, chunkid, 0, 4); - if (!Arrays.equals(chunkid, ChunkHelper.b_IHDR)) - throw new PngjInputException("IHDR not found as first chunk??? [" + ChunkHelper.toString(chunkid) + "]"); - offset += 4; - PngChunkIHDR ihdr = (PngChunkIHDR) readChunk(chunkid, clen, false); - boolean alpha = (ihdr.getColormodel() & 0x04) != 0; - boolean palette = (ihdr.getColormodel() & 0x01) != 0; - boolean grayscale = (ihdr.getColormodel() == 0 || ihdr.getColormodel() == 4); - // creates ImgInfo and imgLine, and allocates buffers - imgInfo = new ImageInfo(ihdr.getCols(), ihdr.getRows(), ihdr.getBitspc(), alpha, grayscale, palette); - // allocation: one extra byte for filter type one pixel - rowbfilter = new byte[imgInfo.bytesPerRow + 1]; - rowb = new byte[imgInfo.bytesPerRow + 1]; - rowbprev = new byte[rowb.length]; - interlaced = ihdr.getInterlaced() == 1; - deinterlacer = interlaced ? new PngDeinterlacer(imgInfo) : null; - // some checks - if (ihdr.getFilmeth() != 0 || ihdr.getCompmeth() != 0 || (ihdr.getInterlaced() & 0xFFFE) != 0) - throw new PngjInputException("compression method o filter method or interlaced unrecognized "); - if (ihdr.getColormodel() < 0 || ihdr.getColormodel() > 6 || ihdr.getColormodel() == 1 - || ihdr.getColormodel() == 5) - throw new PngjInputException("Invalid colormodel " + ihdr.getColormodel()); - if (ihdr.getBitspc() != 1 && ihdr.getBitspc() != 2 && ihdr.getBitspc() != 4 && ihdr.getBitspc() != 8 - && ihdr.getBitspc() != 16) - throw new PngjInputException("Invalid bit depth " + ihdr.getBitspc()); - } - - private boolean firstChunksNotYetRead() { - return currentChunkGroup < ChunksList.CHUNK_GROUP_1_AFTERIDHR; - } - - /** - * Reads last Internally called after having read the last line. It reads extra chunks after IDAT, if present. - */ - private void readLastAndClose() { - // offset = iIdatCstream.getOffset(); - if (currentChunkGroup < ChunksList.CHUNK_GROUP_5_AFTERIDAT) { - try { - idatIstream.close(); - } catch (Exception e) { - } - readLastChunks(); - } - close(); - } - - private void close() { - if (currentChunkGroup < ChunksList.CHUNK_GROUP_6_END) { // this could only happen if forced close - try { - idatIstream.close(); - } catch (Exception e) { - } - currentChunkGroup = ChunksList.CHUNK_GROUP_6_END; - } - if (shouldCloseStream) { - try { - inputStream.close(); - } catch (Exception e) { - throw new PngjInputException("error closing input stream!", e); - } - } - } - - // nbytes: NOT including the filter byte. leaves result in rowb - private void unfilterRow(int nbytes) { - int ftn = rowbfilter[0]; - FilterType ft = FilterType.getByVal(ftn); - if (ft == null) - throw new PngjInputException("Filter type " + ftn + " invalid"); - switch (ft) { - case FILTER_NONE: - unfilterRowNone(nbytes); - break; - case FILTER_SUB: - unfilterRowSub(nbytes); - break; - case FILTER_UP: - unfilterRowUp(nbytes); - break; - case FILTER_AVERAGE: - unfilterRowAverage(nbytes); - break; - case FILTER_PAETH: - unfilterRowPaeth(nbytes); - break; - default: - throw new PngjInputException("Filter type " + ftn + " not implemented"); - } - if (crctest != null) - crctest.update(rowb, 1, rowb.length - 1); - } - - private void unfilterRowAverage(final int nbytes) { - int i, j, x; - for (j = 1 - imgInfo.bytesPixel, i = 1; i <= nbytes; i++, j++) { - x = j > 0 ? (rowb[j] & 0xff) : 0; - rowb[i] = (byte) (rowbfilter[i] + (x + (rowbprev[i] & 0xFF)) / 2); - } - } - - private void unfilterRowNone(final int nbytes) { - for (int i = 1; i <= nbytes; i++) { - rowb[i] = (byte) (rowbfilter[i]); - } - } - - private void unfilterRowPaeth(final int nbytes) { - int i, j, x, y; - for (j = 1 - imgInfo.bytesPixel, i = 1; i <= nbytes; i++, j++) { - x = j > 0 ? (rowb[j] & 0xFF) : 0; - y = j > 0 ? (rowbprev[j] & 0xFF) : 0; - rowb[i] = (byte) (rowbfilter[i] + PngHelperInternal.filterPaethPredictor(x, rowbprev[i] & 0xFF, y)); - } - } - - private void unfilterRowSub(final int nbytes) { - int i, j; - for (i = 1; i <= imgInfo.bytesPixel; i++) { - rowb[i] = (byte) (rowbfilter[i]); - } - for (j = 1, i = imgInfo.bytesPixel + 1; i <= nbytes; i++, j++) { - rowb[i] = (byte) (rowbfilter[i] + rowb[j]); - } - } - - private void unfilterRowUp(final int nbytes) { - for (int i = 1; i <= nbytes; i++) { - rowb[i] = (byte) (rowbfilter[i] + rowbprev[i]); - } - } - - /** - * Reads chunks before first IDAT. Normally this is called automatically - *

- * Position before: after IDHR (crc included) Position after: just after the first IDAT chunk id - *

- * This can be called several times (tentatively), it does nothing if already run - *

- * (Note: when should this be called? in the constructor? hardly, because we loose the opportunity to call - * setChunkLoadBehaviour() and perhaps other settings before reading the first row? but sometimes we want to access - * some metadata (plte, phys) before. Because of this, this method can be called explicitly but is also called - * implicititly in some methods (getMetatada(), getChunksList()) - */ - private final void readFirstChunks() { - if (!firstChunksNotYetRead()) - return; - int clen = 0; - boolean found = false; - byte[] chunkid = new byte[4]; // it's important to reallocate in each iteration - currentChunkGroup = ChunksList.CHUNK_GROUP_1_AFTERIDHR; - while (!found) { - clen = PngHelperInternal.readInt4(inputStream); - offset += 4; - if (clen < 0) - break; - PngHelperInternal.readBytes(inputStream, chunkid, 0, 4); - offset += 4; - if (Arrays.equals(chunkid, ChunkHelper.b_IDAT)) { - found = true; - currentChunkGroup = ChunksList.CHUNK_GROUP_4_IDAT; - // add dummy idat chunk to list - chunksList.appendReadChunk(new PngChunkIDAT(imgInfo, clen, offset - 8), currentChunkGroup); - break; - } else if (Arrays.equals(chunkid, ChunkHelper.b_IEND)) { - throw new PngjInputException("END chunk found before image data (IDAT) at offset=" + offset); - } - if (Arrays.equals(chunkid, ChunkHelper.b_PLTE)) - currentChunkGroup = ChunksList.CHUNK_GROUP_2_PLTE; - readChunk(chunkid, clen, false); - if (Arrays.equals(chunkid, ChunkHelper.b_PLTE)) - currentChunkGroup = ChunksList.CHUNK_GROUP_3_AFTERPLTE; - } - int idatLen = found ? clen : -1; - if (idatLen < 0) - throw new PngjInputException("first idat chunk not found!"); - iIdatCstream = new PngIDatChunkInputStream(inputStream, idatLen, offset); - idatIstream = new InflaterInputStream(iIdatCstream); - if (!crcEnabled) - iIdatCstream.disableCrcCheck(); - } - - /** - * Reads (and processes) chunks after last IDAT. - **/ - void readLastChunks() { - // PngHelper.logdebug("idat ended? " + iIdatCstream.isEnded()); - currentChunkGroup = ChunksList.CHUNK_GROUP_5_AFTERIDAT; - if (!iIdatCstream.isEnded()) - iIdatCstream.forceChunkEnd(); - int clen = iIdatCstream.getLenLastChunk(); - byte[] chunkid = iIdatCstream.getIdLastChunk(); - boolean endfound = false; - boolean first = true; - boolean skip = false; - while (!endfound) { - skip = false; - if (!first) { - clen = PngHelperInternal.readInt4(inputStream); - offset += 4; - if (clen < 0) - throw new PngjInputException("bad chuck len " + clen); - PngHelperInternal.readBytes(inputStream, chunkid, 0, 4); - offset += 4; - } - first = false; - if (Arrays.equals(chunkid, ChunkHelper.b_IDAT)) { - skip = true; // extra dummy (empty?) idat chunk, it can happen, ignore it - } else if (Arrays.equals(chunkid, ChunkHelper.b_IEND)) { - currentChunkGroup = ChunksList.CHUNK_GROUP_6_END; - endfound = true; - } - readChunk(chunkid, clen, skip); - } - if (!endfound) - throw new PngjInputException("end chunk not found - offset=" + offset); - // PngHelper.logdebug("end chunk found ok offset=" + offset); - } - - /** - * Reads chunkd from input stream, adds to ChunksList, and returns it. If it's skipped, a PngChunkSkipped object is - * created - */ - private PngChunk readChunk(byte[] chunkid, int clen, boolean skipforced) { - if (clen < 0) - throw new PngjInputException("invalid chunk lenght: " + clen); - // skipChunksByIdSet is created lazyly, if fist IHDR has already been read - if (skipChunkIdsSet == null && currentChunkGroup > ChunksList.CHUNK_GROUP_0_IDHR) - skipChunkIdsSet = new HashSet(Arrays.asList(skipChunkIds)); - String chunkidstr = ChunkHelper.toString(chunkid); - boolean critical = ChunkHelper.isCritical(chunkidstr); - PngChunk pngChunk = null; - boolean skip = skipforced; - if (maxTotalBytesRead > 0 && clen + offset > maxTotalBytesRead) - throw new PngjInputException("Maximum total bytes to read exceeeded: " + maxTotalBytesRead + " offset:" - + offset + " clen=" + clen); - // an ancillary chunks can be skipped because of several reasons: - if (currentChunkGroup > ChunksList.CHUNK_GROUP_0_IDHR && !critical) - skip = skip || (skipChunkMaxSize > 0 && clen >= skipChunkMaxSize) || skipChunkIdsSet.contains(chunkidstr) - || (maxBytesMetadata > 0 && clen > maxBytesMetadata - bytesChunksLoaded) - || !ChunkHelper.shouldLoad(chunkidstr, chunkLoadBehaviour); - if (skip) { - PngHelperInternal.skipBytes(inputStream, clen); - PngHelperInternal.readInt4(inputStream); // skip - we dont call PngHelperInternal.skipBytes(inputStream, - // clen + 4) for risk of overflow - pngChunk = new PngChunkSkipped(chunkidstr, imgInfo, clen); - } else { - ChunkRaw chunk = new ChunkRaw(clen, chunkid, true); - chunk.readChunkData(inputStream, crcEnabled || critical); - pngChunk = PngChunk.factory(chunk, imgInfo); - if (!pngChunk.crit) - bytesChunksLoaded += chunk.len; - } - pngChunk.setOffset(offset - 8L); - chunksList.appendReadChunk(pngChunk, currentChunkGroup); - offset += clen + 4L; - return pngChunk; - } - - /** - * Logs/prints a warning. - *

- * The default behaviour is print to stderr, but it can be overriden. - *

- * This happens rarely - most errors are fatal. - */ - protected void logWarn(String warn) { - System.err.println(warn); - } - - /** - * @see #setChunkLoadBehaviour(ChunkLoadBehaviour) - */ - public ChunkLoadBehaviour getChunkLoadBehaviour() { - return chunkLoadBehaviour; - } - - /** - * Determines which ancillary chunks (metada) are to be loaded - * - * @param chunkLoadBehaviour - * {@link ChunkLoadBehaviour} - */ - public void setChunkLoadBehaviour(ChunkLoadBehaviour chunkLoadBehaviour) { - this.chunkLoadBehaviour = chunkLoadBehaviour; - } - - /** - * All loaded chunks (metada). If we have not yet end reading the image, this will include only the chunks before - * the pixels data (IDAT) - *

- * Critical chunks are included, except that all IDAT chunks appearance are replaced by a single dummy-marker IDAT - * chunk. These might be copied to the PngWriter - *

- * - * @see #getMetadata() - */ - public ChunksList getChunksList() { - if (firstChunksNotYetRead()) - readFirstChunks(); - return chunksList; - } - - int getCurrentChunkGroup() { - return currentChunkGroup; - } - - /** - * High level wrapper over chunksList - * - * @see #getChunksList() - */ - public PngMetadata getMetadata() { - if (firstChunksNotYetRead()) - readFirstChunks(); - return metadata; - } - - /** - * If called for first time, calls readRowInt. Elsewhere, it calls the appropiate readRowInt/readRowByte - *

- * In general, specifying the concrete readRowInt/readRowByte is preferrable - * - * @see #readRowInt(int) {@link #readRowByte(int)} - */ - public ImageLine readRow(int nrow) { - if (imgLine == null) - imgLine = new ImageLine(imgInfo, SampleType.INT, unpackedMode); - return imgLine.sampleType != SampleType.BYTE ? readRowInt(nrow) : readRowByte(nrow); - } - - /** - * Reads the row as INT, storing it in the {@link #imgLine} property and returning it. - * - * The row must be greater or equal than the last read row. - * - * @param nrow - * Row number, from 0 to rows-1. Increasing order. - * @return ImageLine object, also available as field. Data is in {@link ImageLine#scanline} (int) field. - */ - public ImageLine readRowInt(int nrow) { - if (imgLine == null) - imgLine = new ImageLine(imgInfo, SampleType.INT, unpackedMode); - if (imgLine.getRown() == nrow) // already read - return imgLine; - readRowInt(imgLine.scanline, nrow); - imgLine.setFilterUsed(FilterType.getByVal(rowbfilter[0])); - imgLine.setRown(nrow); - return imgLine; - } - - /** - * Reads the row as BYTES, storing it in the {@link #imgLine} property and returning it. - * - * The row must be greater or equal than the last read row. This method allows to pass the same row that was last - * read. - * - * @param nrow - * Row number, from 0 to rows-1. Increasing order. - * @return ImageLine object, also available as field. Data is in {@link ImageLine#scanlineb} (byte) field. - */ - public ImageLine readRowByte(int nrow) { - if (imgLine == null) - imgLine = new ImageLine(imgInfo, SampleType.BYTE, unpackedMode); - if (imgLine.getRown() == nrow) // already read - return imgLine; - readRowByte(imgLine.scanlineb, nrow); - imgLine.setFilterUsed(FilterType.getByVal(rowbfilter[0])); - imgLine.setRown(nrow); - return imgLine; - } - - /** - * @see #readRowInt(int[], int) - */ - public final int[] readRow(int[] buffer, final int nrow) { - return readRowInt(buffer, nrow); - } - - /** - * Reads a line and returns it as a int[] array. - *

- * You can pass (optionally) a prealocatted buffer. - *

- * If the bitdepth is less than 8, the bytes are packed - unless {@link #unpackedMode} is true. - * - * @param buffer - * Prealocated buffer, or null. - * @param nrow - * Row number (0 is top). Most be strictly greater than the last read row. - * - * @return The scanline in the same passwd buffer if it was allocated, a newly allocated one otherwise - */ - public final int[] readRowInt(int[] buffer, final int nrow) { - if (buffer == null) - buffer = new int[unpackedMode ? imgInfo.samplesPerRow : imgInfo.samplesPerRowPacked]; - if (!interlaced) { - if (nrow <= rowNum) - throw new PngjInputException("rows must be read in increasing order: " + nrow); - int bytesread = 0; - while (rowNum < nrow) - bytesread = readRowRaw(rowNum + 1); // read rows, perhaps skipping if necessary - decodeLastReadRowToInt(buffer, bytesread); - } else { // interlaced - if (deinterlacer.getImageInt() == null) - deinterlacer.setImageInt(readRowsInt().scanlines); // read all image and store it in deinterlacer - System.arraycopy(deinterlacer.getImageInt()[nrow], 0, buffer, 0, unpackedMode ? imgInfo.samplesPerRow - : imgInfo.samplesPerRowPacked); - } - return buffer; - } - - /** - * Reads a line and returns it as a byte[] array. - *

- * You can pass (optionally) a prealocatted buffer. - *

- * If the bitdepth is less than 8, the bytes are packed - unless {@link #unpackedMode} is true.
- * If the bitdepth is 16, the least significant byte is lost. - *

- * - * @param buffer - * Prealocated buffer, or null. - * @param nrow - * Row number (0 is top). Most be strictly greater than the last read row. - * - * @return The scanline in the same passwd buffer if it was allocated, a newly allocated one otherwise - */ - public final byte[] readRowByte(byte[] buffer, final int nrow) { - if (buffer == null) - buffer = new byte[unpackedMode ? imgInfo.samplesPerRow : imgInfo.samplesPerRowPacked]; - if (!interlaced) { - if (nrow <= rowNum) - throw new PngjInputException("rows must be read in increasing order: " + nrow); - int bytesread = 0; - while (rowNum < nrow) - bytesread = readRowRaw(rowNum + 1); // read rows, perhaps skipping if necessary - decodeLastReadRowToByte(buffer, bytesread); - } else { // interlaced - if (deinterlacer.getImageByte() == null) - deinterlacer.setImageByte(readRowsByte().scanlinesb); // read all image and store it in deinterlacer - System.arraycopy(deinterlacer.getImageByte()[nrow], 0, buffer, 0, unpackedMode ? imgInfo.samplesPerRow - : imgInfo.samplesPerRowPacked); - } - return buffer; - } - - /** - * @param nrow - * @deprecated Now {@link #readRow(int)} implements the same funcion. This method will be removed in future releases - */ - public ImageLine getRow(int nrow) { - return readRow(nrow); - } - - private void decodeLastReadRowToInt(int[] buffer, int bytesRead) { - if (imgInfo.bitDepth <= 8) - for (int i = 0, j = 1; i < bytesRead; i++) - buffer[i] = (rowb[j++] & 0xFF); // http://www.libpng.org/pub/png/spec/1.2/PNG-DataRep.html - else - for (int i = 0, j = 1; j <= bytesRead; i++) - buffer[i] = ((rowb[j++] & 0xFF) << 8) + (rowb[j++] & 0xFF); // 16 bitspc - if (imgInfo.packed && unpackedMode) - ImageLine.unpackInplaceInt(imgInfo, buffer, buffer, false); - } - - private void decodeLastReadRowToByte(byte[] buffer, int bytesRead) { - if (imgInfo.bitDepth <= 8) - System.arraycopy(rowb, 1, buffer, 0, bytesRead); - else - for (int i = 0, j = 1; j < bytesRead; i++, j += 2) - buffer[i] = rowb[j];// 16 bits in 1 byte: this discards the LSB!!! - if (imgInfo.packed && unpackedMode) - ImageLine.unpackInplaceByte(imgInfo, buffer, buffer, false); - } - - /** - * Reads a set of lines and returns it as a ImageLines object, which wraps matrix. Internally it reads all lines, - * but decodes and stores only the wanted ones. This starts and ends the reading, and cannot be combined with other - * reading methods. - *

- * This it's more efficient (speed an memory) that doing calling readRowInt() for each desired line only if the - * image is interlaced. - *

- * Notice that the columns in the matrix is not the pixel width of the image, but rather pixels x channels - * - * @see #readRowInt(int) to read about the format of each row - * - * @param rowOffset - * Number of rows to be skipped - * @param nRows - * Total number of rows to be read. -1: read all available - * @param rowStep - * Row increment. If 1, we read consecutive lines; if 2, we read even/odd lines, etc - * @return Set of lines as a ImageLines, which wraps a matrix - */ - public ImageLines readRowsInt(int rowOffset, int nRows, int rowStep) { - if (nRows < 0) - nRows = (imgInfo.rows - rowOffset) / rowStep; - if (rowStep < 1 || rowOffset < 0 || nRows * rowStep + rowOffset > imgInfo.rows) - throw new PngjInputException("bad args"); - ImageLines imlines = new ImageLines(imgInfo, SampleType.INT, unpackedMode, rowOffset, nRows, rowStep); - if (!interlaced) { - for (int j = 0; j < imgInfo.rows; j++) { - int bytesread = readRowRaw(j); // read and perhaps discards - int mrow = imlines.imageRowToMatrixRowStrict(j); - if (mrow >= 0) - decodeLastReadRowToInt(imlines.scanlines[mrow], bytesread); - } - } else { // and now, for something completely different (interlaced) - int[] buf = new int[unpackedMode ? imgInfo.samplesPerRow : imgInfo.samplesPerRowPacked]; - for (int p = 1; p <= 7; p++) { - deinterlacer.setPass(p); - for (int i = 0; i < deinterlacer.getRows(); i++) { - int bytesread = readRowRaw(i); - int j = deinterlacer.getCurrRowReal(); - int mrow = imlines.imageRowToMatrixRowStrict(j); - if (mrow >= 0) { - decodeLastReadRowToInt(buf, bytesread); - deinterlacer.deinterlaceInt(buf, imlines.scanlines[mrow], !unpackedMode); - } - } - } - } - end(); - return imlines; - } - - /** - * Same as readRowsInt(0, imgInfo.rows, 1) - * - * @see #readRowsInt(int, int, int) - */ - public ImageLines readRowsInt() { - return readRowsInt(0, imgInfo.rows, 1); - } - - /** - * Reads a set of lines and returns it as a ImageLines object, which wrapas a byte[][] matrix. Internally it reads - * all lines, but decodes and stores only the wanted ones. This starts and ends the reading, and cannot be combined - * with other reading methods. - *

- * This it's more efficient (speed an memory) that doing calling readRowByte() for each desired line only if the - * image is interlaced. - *

- * Notice that the columns in the matrix is not the pixel width of the image, but rather pixels x channels - * - * @see #readRowByte(int) to read about the format of each row. Notice that if the bitdepth is 16 this will lose - * information - * - * @param rowOffset - * Number of rows to be skipped - * @param nRows - * Total number of rows to be read. -1: read all available - * @param rowStep - * Row increment. If 1, we read consecutive lines; if 2, we read even/odd lines, etc - * @return Set of lines as a matrix - */ - public ImageLines readRowsByte(int rowOffset, int nRows, int rowStep) { - if (nRows < 0) - nRows = (imgInfo.rows - rowOffset) / rowStep; - if (rowStep < 1 || rowOffset < 0 || nRows * rowStep + rowOffset > imgInfo.rows) - throw new PngjInputException("bad args"); - ImageLines imlines = new ImageLines(imgInfo, SampleType.BYTE, unpackedMode, rowOffset, nRows, rowStep); - if (!interlaced) { - for (int j = 0; j < imgInfo.rows; j++) { - int bytesread = readRowRaw(j); // read and perhaps discards - int mrow = imlines.imageRowToMatrixRowStrict(j); - if (mrow >= 0) - decodeLastReadRowToByte(imlines.scanlinesb[mrow], bytesread); - } - } else { // and now, for something completely different (interlaced) - byte[] buf = new byte[unpackedMode ? imgInfo.samplesPerRow : imgInfo.samplesPerRowPacked]; - for (int p = 1; p <= 7; p++) { - deinterlacer.setPass(p); - for (int i = 0; i < deinterlacer.getRows(); i++) { - int bytesread = readRowRaw(i); - int j = deinterlacer.getCurrRowReal(); - int mrow = imlines.imageRowToMatrixRowStrict(j); - if (mrow >= 0) { - decodeLastReadRowToByte(buf, bytesread); - deinterlacer.deinterlaceByte(buf, imlines.scanlinesb[mrow], !unpackedMode); - } - } - } - } - end(); - return imlines; - } - - /** - * Same as readRowsByte(0, imgInfo.rows, 1) - * - * @see #readRowsByte(int, int, int) - */ - public ImageLines readRowsByte() { - return readRowsByte(0, imgInfo.rows, 1); - } - - /* - * For the interlaced case, nrow indicates the subsampled image - the pass must be set already. - * - * This must be called in strict order, both for interlaced or no interlaced. - * - * Updates rowNum. - * - * Leaves raw result in rowb - * - * Returns bytes actually read (not including the filter byte) - */ - private int readRowRaw(final int nrow) { - // - if (nrow == 0 && firstChunksNotYetRead()) - readFirstChunks(); - if (nrow == 0 && interlaced) - Arrays.fill(rowb, (byte) 0); // new subimage: reset filters: this is enough, see the swap that happens lines - // below - int bytesRead = imgInfo.bytesPerRow; // NOT including the filter byte - if (interlaced) { - if (nrow < 0 || nrow > deinterlacer.getRows() || (nrow != 0 && nrow != deinterlacer.getCurrRowSubimg() + 1)) - throw new PngjInputException("invalid row in interlaced mode: " + nrow); - deinterlacer.setRow(nrow); - bytesRead = (imgInfo.bitspPixel * deinterlacer.getPixelsToRead() + 7) / 8; - if (bytesRead < 1) - throw new PngjExceptionInternal("wtf??"); - } else { // check for non interlaced - if (nrow < 0 || nrow >= imgInfo.rows || nrow != rowNum + 1) - throw new PngjInputException("invalid row: " + nrow); - } - rowNum = nrow; - // swap buffers - byte[] tmp = rowb; - rowb = rowbprev; - rowbprev = tmp; - // loads in rowbfilter "raw" bytes, with filter - PngHelperInternal.readBytes(idatIstream, rowbfilter, 0, bytesRead + 1); - offset = iIdatCstream.getOffset(); - if (offset < 0) - throw new PngjExceptionInternal("bad offset ??" + offset); - if (maxTotalBytesRead > 0 && offset >= maxTotalBytesRead) - throw new PngjInputException("Reading IDAT: Maximum total bytes to read exceeeded: " + maxTotalBytesRead - + " offset:" + offset); - rowb[0] = 0; - unfilterRow(bytesRead); - rowb[0] = rowbfilter[0]; - if ((rowNum == imgInfo.rows - 1 && !interlaced) || (interlaced && deinterlacer.isAtLastRow())) - readLastAndClose(); - return bytesRead; - } - - /** - * Reads all the (remaining) file, skipping the pixels data. This is much more efficient that calling readRow(), - * specially for big files (about 10 times faster!), because it doesn't even decompress the IDAT stream and disables - * CRC check Use this if you are not interested in reading pixels,only metadata. - */ - public void readSkippingAllRows() { - if (firstChunksNotYetRead()) - readFirstChunks(); - // we read directly from the compressed stream, we dont decompress nor chec CRC - iIdatCstream.disableCrcCheck(); - try { - int r; - do { - r = iIdatCstream.read(rowbfilter, 0, rowbfilter.length); - } while (r >= 0); - } catch (IOException e) { - throw new PngjInputException("error in raw read of IDAT", e); - } - offset = iIdatCstream.getOffset(); - if (offset < 0) - throw new PngjExceptionInternal("bad offset ??" + offset); - if (maxTotalBytesRead > 0 && offset >= maxTotalBytesRead) - throw new PngjInputException("Reading IDAT: Maximum total bytes to read exceeeded: " + maxTotalBytesRead - + " offset:" + offset); - readLastAndClose(); - } - - /** - * Set total maximum bytes to read (0: unlimited; default: 200MB).
- * These are the bytes read (not loaded) in the input stream. If exceeded, an exception will be thrown. - */ - public void setMaxTotalBytesRead(long maxTotalBytesToRead) { - this.maxTotalBytesRead = maxTotalBytesToRead; - } - - /** - * @return Total maximum bytes to read. - */ - public long getMaxTotalBytesRead() { - return maxTotalBytesRead; - } - - /** - * Set total maximum bytes to load from ancillary chunks (0: unlimited; default: 5Mb).
- * If exceeded, some chunks will be skipped - */ - public void setMaxBytesMetadata(int maxBytesChunksToLoad) { - this.maxBytesMetadata = maxBytesChunksToLoad; - } - - /** - * @return Total maximum bytes to load from ancillary ckunks. - */ - public int getMaxBytesMetadata() { - return maxBytesMetadata; - } - - /** - * Set maximum size in bytes for individual ancillary chunks (0: unlimited; default: 2MB).
- * Chunks exceeding this length will be skipped (the CRC will not be checked) and the chunk will be saved as a - * PngChunkSkipped object. See also setSkipChunkIds - */ - public void setSkipChunkMaxSize(int skipChunksBySize) { - this.skipChunkMaxSize = skipChunksBySize; - } - - /** - * @return maximum size in bytes for individual ancillary chunks. - */ - public int getSkipChunkMaxSize() { - return skipChunkMaxSize; - } - - /** - * Chunks ids to be skipped.
- * These chunks will be skipped (the CRC will not be checked) and the chunk will be saved as a PngChunkSkipped - * object. See also setSkipChunkMaxSize - */ - public void setSkipChunkIds(String[] skipChunksById) { - this.skipChunkIds = skipChunksById == null ? new String[] {} : skipChunksById; - } - - /** - * @return Chunk-IDs to be skipped. - */ - public String[] getSkipChunkIds() { - return skipChunkIds; - } - - /** - * if true, input stream will be closed after ending read - *

- * default=true - */ - public void setShouldCloseStream(boolean shouldCloseStream) { - this.shouldCloseStream = shouldCloseStream; - } - - /** - * Normally this does nothing, but it can be used to force a premature closing. Its recommended practice to call it - * after reading the image pixels. - */ - public void end() { - if (currentChunkGroup < ChunksList.CHUNK_GROUP_6_END) - close(); - } - - /** - * Interlaced PNG is accepted -though not welcomed- now... - */ - public boolean isInterlaced() { - return interlaced; - } - - /** - * set/unset "unpackedMode"
- * If false (default) packed types (bitdepth=1,2 or 4) will keep several samples packed in one element (byte or int)
- * If true, samples will be unpacked on reading, and each element in the scanline will be sample. This implies more - * processing and memory, but it's the most efficient option if you intend to read individual pixels.
- * This option should only be set before start reading. - * - * @param unPackedMode - */ - public void setUnpackedMode(boolean unPackedMode) { - this.unpackedMode = unPackedMode; - } - - /** - * @see PngReader#setUnpackedMode(boolean) - */ - public boolean isUnpackedMode() { - return unpackedMode; - } - - /** - * Disables the CRC integrity check in IDAT chunks and ancillary chunks, this gives a slight increase in reading - * speed for big files - */ - public void setCrcCheckDisabled() { - crcEnabled = false; - } - - /** - * Just for testing. TO be called after ending reading, only if initCrctest() was called before start - * - * @return CRC of the raw pixels values - */ - long getCrctestVal() { - return crctest.getValue(); - } - - /** - * Inits CRC object and enables CRC calculation - */ - void initCrctest() { - this.crctest = new CRC32(); - } - - /** - * Basic info, for debugging. - */ - public String toString() { // basic info - return "filename=" + filename + " " + imgInfo.toString(); - } - -} +package jogamp.opengl.util.pngj; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.zip.CRC32; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; + +import jogamp.opengl.util.pngj.ImageLine.SampleType; +import jogamp.opengl.util.pngj.chunks.ChunkHelper; +import jogamp.opengl.util.pngj.chunks.ChunkLoadBehaviour; +import jogamp.opengl.util.pngj.chunks.ChunkRaw; +import jogamp.opengl.util.pngj.chunks.ChunksList; +import jogamp.opengl.util.pngj.chunks.PngChunk; +import jogamp.opengl.util.pngj.chunks.PngChunkIDAT; +import jogamp.opengl.util.pngj.chunks.PngChunkIHDR; +import jogamp.opengl.util.pngj.chunks.PngChunkSkipped; +import jogamp.opengl.util.pngj.chunks.PngMetadata; + +/** + * Reads a PNG image, line by line. + *

+ * The reading sequence is as follows:
+ * 1. At construction time, the header and IHDR chunk are read (basic image + * info)
+ * 2. Afterwards you can set some additional global options. Eg. + * {@link #setUnpackedMode(boolean)}, {@link #setCrcCheckDisabled()}.
+ * 3. Optional: If you call getMetadata() or getChunksLisk() before start + * reading the rows, all the chunks before IDAT are automatically loaded and + * available
+ * 4a. The rows are read onen by one of the readRowXXX methods: + * {@link #readRowInt(int)}, {@link PngReader#readRowByte(int)}, etc, in order, + * from 0 to nrows-1 (you can skip or repeat rows, but not go backwards)
+ * 4b. Alternatively, you can read all rows, or a subset, in a single call: + * {@link #readRowsInt()}, {@link #readRowsByte()} ,etc. In general this + * consumes more memory, but for interlaced images this is equally efficient, + * and more so if reading a small subset of rows.
+ * 5. Read of the last row auyomatically loads the trailing chunks, and ends the + * reader.
+ * 6. end() forcibly finishes/aborts the reading and closes the stream + */ +public class PngReader { + + /** + * Basic image info - final and inmutable. + */ + public final ImageInfo imgInfo; + /** + * not necesarily a filename, can be a description - merely informative + */ + protected final String filename; + private ChunkLoadBehaviour chunkLoadBehaviour = ChunkLoadBehaviour.LOAD_CHUNK_ALWAYS; // see setter/getter + private boolean shouldCloseStream = true; // true: closes stream after ending - see setter/getter + // some performance/defensive limits + private long maxTotalBytesRead = 200 * 1024 * 1024; // 200MB + private int maxBytesMetadata = 5 * 1024 * 1024; // for ancillary chunks - see setter/getter + private int skipChunkMaxSize = 2 * 1024 * 1024; // chunks exceeding this size will be skipped (nor even CRC checked) + private String[] skipChunkIds = { "fdAT" }; // chunks with these ids will be skipped (nor even CRC checked) + private HashSet skipChunkIdsSet; // lazily created from skipChunksById + protected final PngMetadata metadata; // this a wrapper over chunks + protected final ChunksList chunksList; + protected ImageLine imgLine; + // line as bytes, counting from 1 (index 0 is reserved for filter type) + protected final int buffersLen; // nominal length is imgInfo.bytesPerRow + 1 but it can be larger + protected byte[] rowb = null; + protected byte[] rowbprev = null; // rowb previous + protected byte[] rowbfilter = null; // current line 'filtered': exactly as in uncompressed stream + // only set for interlaced PNG + private final boolean interlaced; + private final PngDeinterlacer deinterlacer; + private boolean crcEnabled = true; + // this only influences the 1-2-4 bitdepth format + private boolean unpackedMode = false; + private Inflater inflater = null; // can be reused among several objects. see reuseBuffersFrom() + /** + * Current chunk group, (0-6) already read or reading + *

+ * see {@link ChunksList} + */ + protected int currentChunkGroup = -1; + protected int rowNum = -1; // last read row number, starting from 0 + private long offset = 0; // offset in InputStream = bytes read + private int bytesChunksLoaded; // bytes loaded from anciallary chunks + protected final InputStream inputStream; + protected InflaterInputStream idatIstream; + protected PngIDatChunkInputStream iIdatCstream; + protected CRC32 crctest; // If set to non null, it gets a CRC of the unfiltered bytes, to check for images equality + + /** + * Constructs a PngReader from an InputStream. + *

+ * See also FileHelper.createPngReader(File f) if available. + * + * Reads only the signature and first chunk (IDHR) + * + * @param filenameOrDescription + * : Optional, can be a filename or a description. Just for + * error/debug messages + * + */ + public PngReader(InputStream inputStream, String filenameOrDescription) { + this.filename = filenameOrDescription == null ? "" : filenameOrDescription; + this.inputStream = inputStream; + this.chunksList = new ChunksList(null); + this.metadata = new PngMetadata(chunksList); + // starts reading: signature + byte[] pngid = new byte[8]; + PngHelperInternal.readBytes(inputStream, pngid, 0, pngid.length); + offset += pngid.length; + if (!Arrays.equals(pngid, PngHelperInternal.getPngIdSignature())) + throw new PngjInputException("Bad PNG signature"); + // reads first chunk + currentChunkGroup = ChunksList.CHUNK_GROUP_0_IDHR; + int clen = PngHelperInternal.readInt4(inputStream); + offset += 4; + if (clen != 13) + throw new PngjInputException("IDHR chunk len != 13 ?? " + clen); + byte[] chunkid = new byte[4]; + PngHelperInternal.readBytes(inputStream, chunkid, 0, 4); + if (!Arrays.equals(chunkid, ChunkHelper.b_IHDR)) + throw new PngjInputException("IHDR not found as first chunk??? [" + ChunkHelper.toString(chunkid) + "]"); + offset += 4; + PngChunkIHDR ihdr = (PngChunkIHDR) readChunk(chunkid, clen, false); + boolean alpha = (ihdr.getColormodel() & 0x04) != 0; + boolean palette = (ihdr.getColormodel() & 0x01) != 0; + boolean grayscale = (ihdr.getColormodel() == 0 || ihdr.getColormodel() == 4); + // creates ImgInfo and imgLine, and allocates buffers + imgInfo = new ImageInfo(ihdr.getCols(), ihdr.getRows(), ihdr.getBitspc(), alpha, grayscale, palette); + interlaced = ihdr.getInterlaced() == 1; + deinterlacer = interlaced ? new PngDeinterlacer(imgInfo) : null; + buffersLen = imgInfo.bytesPerRow + 1; + // some checks + if (ihdr.getFilmeth() != 0 || ihdr.getCompmeth() != 0 || (ihdr.getInterlaced() & 0xFFFE) != 0) + throw new PngjInputException("compression method o filter method or interlaced unrecognized "); + if (ihdr.getColormodel() < 0 || ihdr.getColormodel() > 6 || ihdr.getColormodel() == 1 + || ihdr.getColormodel() == 5) + throw new PngjInputException("Invalid colormodel " + ihdr.getColormodel()); + if (ihdr.getBitspc() != 1 && ihdr.getBitspc() != 2 && ihdr.getBitspc() != 4 && ihdr.getBitspc() != 8 + && ihdr.getBitspc() != 16) + throw new PngjInputException("Invalid bit depth " + ihdr.getBitspc()); + } + + private boolean firstChunksNotYetRead() { + return currentChunkGroup < ChunksList.CHUNK_GROUP_1_AFTERIDHR; + } + + private void allocateBuffers() { // only if needed + if (rowbfilter == null || rowbfilter.length < buffersLen) { + rowbfilter = new byte[buffersLen]; + rowb = new byte[buffersLen]; + rowbprev = new byte[buffersLen]; + } + } + + /** + * Reads last Internally called after having read the last line. It reads + * extra chunks after IDAT, if present. + */ + private void readLastAndClose() { + // offset = iIdatCstream.getOffset(); + if (currentChunkGroup < ChunksList.CHUNK_GROUP_5_AFTERIDAT) { + try { + idatIstream.close(); + } catch (Exception e) { + } + readLastChunks(); + } + close(); + } + + private void close() { + if (currentChunkGroup < ChunksList.CHUNK_GROUP_6_END) { // this could only happen if forced close + try { + idatIstream.close(); + } catch (Exception e) { + } + currentChunkGroup = ChunksList.CHUNK_GROUP_6_END; + } + if (shouldCloseStream) { + try { + inputStream.close(); + } catch (Exception e) { + throw new PngjInputException("error closing input stream!", e); + } + } + } + + // nbytes: NOT including the filter byte. leaves result in rowb + private void unfilterRow(int nbytes) { + int ftn = rowbfilter[0]; + FilterType ft = FilterType.getByVal(ftn); + if (ft == null) + throw new PngjInputException("Filter type " + ftn + " invalid"); + switch (ft) { + case FILTER_NONE: + unfilterRowNone(nbytes); + break; + case FILTER_SUB: + unfilterRowSub(nbytes); + break; + case FILTER_UP: + unfilterRowUp(nbytes); + break; + case FILTER_AVERAGE: + unfilterRowAverage(nbytes); + break; + case FILTER_PAETH: + unfilterRowPaeth(nbytes); + break; + default: + throw new PngjInputException("Filter type " + ftn + " not implemented"); + } + if (crctest != null) + crctest.update(rowb, 1, buffersLen - 1); + } + + private void unfilterRowAverage(final int nbytes) { + int i, j, x; + for (j = 1 - imgInfo.bytesPixel, i = 1; i <= nbytes; i++, j++) { + x = j > 0 ? (rowb[j] & 0xff) : 0; + rowb[i] = (byte) (rowbfilter[i] + (x + (rowbprev[i] & 0xFF)) / 2); + } + } + + private void unfilterRowNone(final int nbytes) { + for (int i = 1; i <= nbytes; i++) { + rowb[i] = (byte) (rowbfilter[i]); + } + } + + private void unfilterRowPaeth(final int nbytes) { + int i, j, x, y; + for (j = 1 - imgInfo.bytesPixel, i = 1; i <= nbytes; i++, j++) { + x = j > 0 ? (rowb[j] & 0xFF) : 0; + y = j > 0 ? (rowbprev[j] & 0xFF) : 0; + rowb[i] = (byte) (rowbfilter[i] + PngHelperInternal.filterPaethPredictor(x, rowbprev[i] & 0xFF, y)); + } + } + + private void unfilterRowSub(final int nbytes) { + int i, j; + for (i = 1; i <= imgInfo.bytesPixel; i++) { + rowb[i] = (byte) (rowbfilter[i]); + } + for (j = 1, i = imgInfo.bytesPixel + 1; i <= nbytes; i++, j++) { + rowb[i] = (byte) (rowbfilter[i] + rowb[j]); + } + } + + private void unfilterRowUp(final int nbytes) { + for (int i = 1; i <= nbytes; i++) { + rowb[i] = (byte) (rowbfilter[i] + rowbprev[i]); + } + } + + /** + * Reads chunks before first IDAT. Normally this is called automatically + *

+ * Position before: after IDHR (crc included) Position after: just after the + * first IDAT chunk id + *

+ * This can be called several times (tentatively), it does nothing if + * already run + *

+ * (Note: when should this be called? in the constructor? hardly, because we + * loose the opportunity to call setChunkLoadBehaviour() and perhaps other + * settings before reading the first row? but sometimes we want to access + * some metadata (plte, phys) before. Because of this, this method can be + * called explicitly but is also called implicititly in some methods + * (getMetatada(), getChunksList()) + */ + private final void readFirstChunks() { + if (!firstChunksNotYetRead()) + return; + int clen = 0; + boolean found = false; + byte[] chunkid = new byte[4]; // it's important to reallocate in each iteration + currentChunkGroup = ChunksList.CHUNK_GROUP_1_AFTERIDHR; + while (!found) { + clen = PngHelperInternal.readInt4(inputStream); + offset += 4; + if (clen < 0) + break; + PngHelperInternal.readBytes(inputStream, chunkid, 0, 4); + offset += 4; + if (Arrays.equals(chunkid, ChunkHelper.b_IDAT)) { + found = true; + currentChunkGroup = ChunksList.CHUNK_GROUP_4_IDAT; + // add dummy idat chunk to list + chunksList.appendReadChunk(new PngChunkIDAT(imgInfo, clen, offset - 8), currentChunkGroup); + break; + } else if (Arrays.equals(chunkid, ChunkHelper.b_IEND)) { + throw new PngjInputException("END chunk found before image data (IDAT) at offset=" + offset); + } + if (Arrays.equals(chunkid, ChunkHelper.b_PLTE)) + currentChunkGroup = ChunksList.CHUNK_GROUP_2_PLTE; + readChunk(chunkid, clen, false); + if (Arrays.equals(chunkid, ChunkHelper.b_PLTE)) + currentChunkGroup = ChunksList.CHUNK_GROUP_3_AFTERPLTE; + } + int idatLen = found ? clen : -1; + if (idatLen < 0) + throw new PngjInputException("first idat chunk not found!"); + iIdatCstream = new PngIDatChunkInputStream(inputStream, idatLen, offset); + if(inflater == null) { + inflater = new Inflater(); + } else { + inflater.reset(); + } + idatIstream = new InflaterInputStream(iIdatCstream, inflater); + if (!crcEnabled) + iIdatCstream.disableCrcCheck(); + } + + /** + * Reads (and processes) chunks after last IDAT. + **/ + void readLastChunks() { + // PngHelper.logdebug("idat ended? " + iIdatCstream.isEnded()); + currentChunkGroup = ChunksList.CHUNK_GROUP_5_AFTERIDAT; + if (!iIdatCstream.isEnded()) + iIdatCstream.forceChunkEnd(); + int clen = iIdatCstream.getLenLastChunk(); + byte[] chunkid = iIdatCstream.getIdLastChunk(); + boolean endfound = false; + boolean first = true; + boolean skip = false; + while (!endfound) { + skip = false; + if (!first) { + clen = PngHelperInternal.readInt4(inputStream); + offset += 4; + if (clen < 0) + throw new PngjInputException("bad chuck len " + clen); + PngHelperInternal.readBytes(inputStream, chunkid, 0, 4); + offset += 4; + } + first = false; + if (Arrays.equals(chunkid, ChunkHelper.b_IDAT)) { + skip = true; // extra dummy (empty?) idat chunk, it can happen, ignore it + } else if (Arrays.equals(chunkid, ChunkHelper.b_IEND)) { + currentChunkGroup = ChunksList.CHUNK_GROUP_6_END; + endfound = true; + } + readChunk(chunkid, clen, skip); + } + if (!endfound) + throw new PngjInputException("end chunk not found - offset=" + offset); + // PngHelper.logdebug("end chunk found ok offset=" + offset); + } + + /** + * Reads chunkd from input stream, adds to ChunksList, and returns it. If + * it's skipped, a PngChunkSkipped object is created + */ + private PngChunk readChunk(byte[] chunkid, int clen, boolean skipforced) { + if (clen < 0) + throw new PngjInputException("invalid chunk lenght: " + clen); + // skipChunksByIdSet is created lazyly, if fist IHDR has already been read + if (skipChunkIdsSet == null && currentChunkGroup > ChunksList.CHUNK_GROUP_0_IDHR) + skipChunkIdsSet = new HashSet(Arrays.asList(skipChunkIds)); + String chunkidstr = ChunkHelper.toString(chunkid); + boolean critical = ChunkHelper.isCritical(chunkidstr); + PngChunk pngChunk = null; + boolean skip = skipforced; + if (maxTotalBytesRead > 0 && clen + offset > maxTotalBytesRead) + throw new PngjInputException("Maximum total bytes to read exceeeded: " + maxTotalBytesRead + " offset:" + + offset + " clen=" + clen); + // an ancillary chunks can be skipped because of several reasons: + if (currentChunkGroup > ChunksList.CHUNK_GROUP_0_IDHR && !critical) + skip = skip || (skipChunkMaxSize > 0 && clen >= skipChunkMaxSize) || skipChunkIdsSet.contains(chunkidstr) + || (maxBytesMetadata > 0 && clen > maxBytesMetadata - bytesChunksLoaded) + || !ChunkHelper.shouldLoad(chunkidstr, chunkLoadBehaviour); + if (skip) { + PngHelperInternal.skipBytes(inputStream, clen); + PngHelperInternal.readInt4(inputStream); // skip - we dont call PngHelperInternal.skipBytes(inputStream, + // clen + 4) for risk of overflow + pngChunk = new PngChunkSkipped(chunkidstr, imgInfo, clen); + } else { + ChunkRaw chunk = new ChunkRaw(clen, chunkid, true); + chunk.readChunkData(inputStream, crcEnabled || critical); + pngChunk = PngChunk.factory(chunk, imgInfo); + if (!pngChunk.crit) + bytesChunksLoaded += chunk.len; + } + pngChunk.setOffset(offset - 8L); + chunksList.appendReadChunk(pngChunk, currentChunkGroup); + offset += clen + 4L; + return pngChunk; + } + + /** + * Logs/prints a warning. + *

+ * The default behaviour is print to stderr, but it can be overriden. + *

+ * This happens rarely - most errors are fatal. + */ + protected void logWarn(String warn) { + System.err.println(warn); + } + + /** + * @see #setChunkLoadBehaviour(ChunkLoadBehaviour) + */ + public ChunkLoadBehaviour getChunkLoadBehaviour() { + return chunkLoadBehaviour; + } + + /** + * Determines which ancillary chunks (metada) are to be loaded + * + * @param chunkLoadBehaviour + * {@link ChunkLoadBehaviour} + */ + public void setChunkLoadBehaviour(ChunkLoadBehaviour chunkLoadBehaviour) { + this.chunkLoadBehaviour = chunkLoadBehaviour; + } + + /** + * All loaded chunks (metada). If we have not yet end reading the image, + * this will include only the chunks before the pixels data (IDAT) + *

+ * Critical chunks are included, except that all IDAT chunks appearance are + * replaced by a single dummy-marker IDAT chunk. These might be copied to + * the PngWriter + *

+ * + * @see #getMetadata() + */ + public ChunksList getChunksList() { + if (firstChunksNotYetRead()) + readFirstChunks(); + return chunksList; + } + + int getCurrentChunkGroup() { + return currentChunkGroup; + } + + /** + * High level wrapper over chunksList + * + * @see #getChunksList() + */ + public PngMetadata getMetadata() { + if (firstChunksNotYetRead()) + readFirstChunks(); + return metadata; + } + + /** + * If called for first time, calls readRowInt. Elsewhere, it calls the + * appropiate readRowInt/readRowByte + *

+ * In general, specifying the concrete readRowInt/readRowByte is preferrable + * + * @see #readRowInt(int) {@link #readRowByte(int)} + */ + public ImageLine readRow(int nrow) { + if (imgLine == null) + imgLine = new ImageLine(imgInfo, SampleType.INT, unpackedMode); + return imgLine.sampleType != SampleType.BYTE ? readRowInt(nrow) : readRowByte(nrow); + } + + /** + * Reads the row as INT, storing it in the {@link #imgLine} property and + * returning it. + * + * The row must be greater or equal than the last read row. + * + * @param nrow + * Row number, from 0 to rows-1. Increasing order. + * @return ImageLine object, also available as field. Data is in + * {@link ImageLine#scanline} (int) field. + */ + public ImageLine readRowInt(int nrow) { + if (imgLine == null) + imgLine = new ImageLine(imgInfo, SampleType.INT, unpackedMode); + if (imgLine.getRown() == nrow) // already read + return imgLine; + readRowInt(imgLine.scanline, nrow); + imgLine.setFilterUsed(FilterType.getByVal(rowbfilter[0])); + imgLine.setRown(nrow); + return imgLine; + } + + /** + * Reads the row as BYTES, storing it in the {@link #imgLine} property and + * returning it. + * + * The row must be greater or equal than the last read row. This method + * allows to pass the same row that was last read. + * + * @param nrow + * Row number, from 0 to rows-1. Increasing order. + * @return ImageLine object, also available as field. Data is in + * {@link ImageLine#scanlineb} (byte) field. + */ + public ImageLine readRowByte(int nrow) { + if (imgLine == null) + imgLine = new ImageLine(imgInfo, SampleType.BYTE, unpackedMode); + if (imgLine.getRown() == nrow) // already read + return imgLine; + readRowByte(imgLine.scanlineb, nrow); + imgLine.setFilterUsed(FilterType.getByVal(rowbfilter[0])); + imgLine.setRown(nrow); + return imgLine; + } + + /** + * @see #readRowInt(int[], int) + */ + public final int[] readRow(int[] buffer, final int nrow) { + return readRowInt(buffer, nrow); + } + + /** + * Reads a line and returns it as a int[] array. + *

+ * You can pass (optionally) a prealocatted buffer. + *

+ * If the bitdepth is less than 8, the bytes are packed - unless + * {@link #unpackedMode} is true. + * + * @param buffer + * Prealocated buffer, or null. + * @param nrow + * Row number (0 is top). Most be strictly greater than the last + * read row. + * + * @return The scanline in the same passwd buffer if it was allocated, a + * newly allocated one otherwise + */ + public final int[] readRowInt(int[] buffer, final int nrow) { + if (buffer == null) + buffer = new int[unpackedMode ? imgInfo.samplesPerRow : imgInfo.samplesPerRowPacked]; + if (!interlaced) { + if (nrow <= rowNum) + throw new PngjInputException("rows must be read in increasing order: " + nrow); + int bytesread = 0; + while (rowNum < nrow) + bytesread = readRowRaw(rowNum + 1); // read rows, perhaps skipping if necessary + decodeLastReadRowToInt(buffer, bytesread); + } else { // interlaced + if (deinterlacer.getImageInt() == null) + deinterlacer.setImageInt(readRowsInt().scanlines); // read all image and store it in deinterlacer + System.arraycopy(deinterlacer.getImageInt()[nrow], 0, buffer, 0, unpackedMode ? imgInfo.samplesPerRow + : imgInfo.samplesPerRowPacked); + } + return buffer; + } + + /** + * Reads a line and returns it as a byte[] array. + *

+ * You can pass (optionally) a prealocatted buffer. + *

+ * If the bitdepth is less than 8, the bytes are packed - unless + * {@link #unpackedMode} is true.
+ * If the bitdepth is 16, the least significant byte is lost. + *

+ * + * @param buffer + * Prealocated buffer, or null. + * @param nrow + * Row number (0 is top). Most be strictly greater than the last + * read row. + * + * @return The scanline in the same passwd buffer if it was allocated, a + * newly allocated one otherwise + */ + public final byte[] readRowByte(byte[] buffer, final int nrow) { + if (buffer == null) + buffer = new byte[unpackedMode ? imgInfo.samplesPerRow : imgInfo.samplesPerRowPacked]; + if (!interlaced) { + if (nrow <= rowNum) + throw new PngjInputException("rows must be read in increasing order: " + nrow); + int bytesread = 0; + while (rowNum < nrow) + bytesread = readRowRaw(rowNum + 1); // read rows, perhaps skipping if necessary + decodeLastReadRowToByte(buffer, bytesread); + } else { // interlaced + if (deinterlacer.getImageByte() == null) + deinterlacer.setImageByte(readRowsByte().scanlinesb); // read all image and store it in deinterlacer + System.arraycopy(deinterlacer.getImageByte()[nrow], 0, buffer, 0, unpackedMode ? imgInfo.samplesPerRow + : imgInfo.samplesPerRowPacked); + } + return buffer; + } + + /** + * @param nrow + * @deprecated Now {@link #readRow(int)} implements the same funcion. This + * method will be removed in future releases + */ + public ImageLine getRow(int nrow) { + return readRow(nrow); + } + + private void decodeLastReadRowToInt(int[] buffer, int bytesRead) { + if (imgInfo.bitDepth <= 8) + for (int i = 0, j = 1; i < bytesRead; i++) + buffer[i] = (rowb[j++] & 0xFF); // http://www.libpng.org/pub/png/spec/1.2/PNG-DataRep.html + else + for (int i = 0, j = 1; j <= bytesRead; i++) + buffer[i] = ((rowb[j++] & 0xFF) << 8) + (rowb[j++] & 0xFF); // 16 bitspc + if (imgInfo.packed && unpackedMode) + ImageLine.unpackInplaceInt(imgInfo, buffer, buffer, false); + } + + private void decodeLastReadRowToByte(byte[] buffer, int bytesRead) { + if (imgInfo.bitDepth <= 8) + System.arraycopy(rowb, 1, buffer, 0, bytesRead); + else + for (int i = 0, j = 1; j < bytesRead; i++, j += 2) + buffer[i] = rowb[j];// 16 bits in 1 byte: this discards the LSB!!! + if (imgInfo.packed && unpackedMode) + ImageLine.unpackInplaceByte(imgInfo, buffer, buffer, false); + } + + /** + * Reads a set of lines and returns it as a ImageLines object, which wraps + * matrix. Internally it reads all lines, but decodes and stores only the + * wanted ones. This starts and ends the reading, and cannot be combined + * with other reading methods. + *

+ * This it's more efficient (speed an memory) that doing calling + * readRowInt() for each desired line only if the image is interlaced. + *

+ * Notice that the columns in the matrix is not the pixel width of the + * image, but rather pixels x channels + * + * @see #readRowInt(int) to read about the format of each row + * + * @param rowOffset + * Number of rows to be skipped + * @param nRows + * Total number of rows to be read. -1: read all available + * @param rowStep + * Row increment. If 1, we read consecutive lines; if 2, we read + * even/odd lines, etc + * @return Set of lines as a ImageLines, which wraps a matrix + */ + public ImageLines readRowsInt(int rowOffset, int nRows, int rowStep) { + if (nRows < 0) + nRows = (imgInfo.rows - rowOffset) / rowStep; + if (rowStep < 1 || rowOffset < 0 || nRows * rowStep + rowOffset > imgInfo.rows) + throw new PngjInputException("bad args"); + ImageLines imlines = new ImageLines(imgInfo, SampleType.INT, unpackedMode, rowOffset, nRows, rowStep); + if (!interlaced) { + for (int j = 0; j < imgInfo.rows; j++) { + int bytesread = readRowRaw(j); // read and perhaps discards + int mrow = imlines.imageRowToMatrixRowStrict(j); + if (mrow >= 0) + decodeLastReadRowToInt(imlines.scanlines[mrow], bytesread); + } + } else { // and now, for something completely different (interlaced) + int[] buf = new int[unpackedMode ? imgInfo.samplesPerRow : imgInfo.samplesPerRowPacked]; + for (int p = 1; p <= 7; p++) { + deinterlacer.setPass(p); + for (int i = 0; i < deinterlacer.getRows(); i++) { + int bytesread = readRowRaw(i); + int j = deinterlacer.getCurrRowReal(); + int mrow = imlines.imageRowToMatrixRowStrict(j); + if (mrow >= 0) { + decodeLastReadRowToInt(buf, bytesread); + deinterlacer.deinterlaceInt(buf, imlines.scanlines[mrow], !unpackedMode); + } + } + } + } + end(); + return imlines; + } + + /** + * Same as readRowsInt(0, imgInfo.rows, 1) + * + * @see #readRowsInt(int, int, int) + */ + public ImageLines readRowsInt() { + return readRowsInt(0, imgInfo.rows, 1); + } + + /** + * Reads a set of lines and returns it as a ImageLines object, which wrapas + * a byte[][] matrix. Internally it reads all lines, but decodes and stores + * only the wanted ones. This starts and ends the reading, and cannot be + * combined with other reading methods. + *

+ * This it's more efficient (speed an memory) that doing calling + * readRowByte() for each desired line only if the image is interlaced. + *

+ * Notice that the columns in the matrix is not the pixel width of the + * image, but rather pixels x channels + * + * @see #readRowByte(int) to read about the format of each row. Notice that + * if the bitdepth is 16 this will lose information + * + * @param rowOffset + * Number of rows to be skipped + * @param nRows + * Total number of rows to be read. -1: read all available + * @param rowStep + * Row increment. If 1, we read consecutive lines; if 2, we read + * even/odd lines, etc + * @return Set of lines as a matrix + */ + public ImageLines readRowsByte(int rowOffset, int nRows, int rowStep) { + if (nRows < 0) + nRows = (imgInfo.rows - rowOffset) / rowStep; + if (rowStep < 1 || rowOffset < 0 || nRows * rowStep + rowOffset > imgInfo.rows) + throw new PngjInputException("bad args"); + ImageLines imlines = new ImageLines(imgInfo, SampleType.BYTE, unpackedMode, rowOffset, nRows, rowStep); + if (!interlaced) { + for (int j = 0; j < imgInfo.rows; j++) { + int bytesread = readRowRaw(j); // read and perhaps discards + int mrow = imlines.imageRowToMatrixRowStrict(j); + if (mrow >= 0) + decodeLastReadRowToByte(imlines.scanlinesb[mrow], bytesread); + } + } else { // and now, for something completely different (interlaced) + byte[] buf = new byte[unpackedMode ? imgInfo.samplesPerRow : imgInfo.samplesPerRowPacked]; + for (int p = 1; p <= 7; p++) { + deinterlacer.setPass(p); + for (int i = 0; i < deinterlacer.getRows(); i++) { + int bytesread = readRowRaw(i); + int j = deinterlacer.getCurrRowReal(); + int mrow = imlines.imageRowToMatrixRowStrict(j); + if (mrow >= 0) { + decodeLastReadRowToByte(buf, bytesread); + deinterlacer.deinterlaceByte(buf, imlines.scanlinesb[mrow], !unpackedMode); + } + } + } + } + end(); + return imlines; + } + + /** + * Same as readRowsByte(0, imgInfo.rows, 1) + * + * @see #readRowsByte(int, int, int) + */ + public ImageLines readRowsByte() { + return readRowsByte(0, imgInfo.rows, 1); + } + + /* + * For the interlaced case, nrow indicates the subsampled image - the pass must be set already. + * + * This must be called in strict order, both for interlaced or no interlaced. + * + * Updates rowNum. + * + * Leaves raw result in rowb + * + * Returns bytes actually read (not including the filter byte) + */ + private int readRowRaw(final int nrow) { + if (nrow == 0) { + if (firstChunksNotYetRead()) + readFirstChunks(); + allocateBuffers(); + if (interlaced) + Arrays.fill(rowb, (byte) 0); // new subimage: reset filters: this is enough, see the swap that happens lines + } + // below + int bytesRead = imgInfo.bytesPerRow; // NOT including the filter byte + if (interlaced) { + if (nrow < 0 || nrow > deinterlacer.getRows() || (nrow != 0 && nrow != deinterlacer.getCurrRowSubimg() + 1)) + throw new PngjInputException("invalid row in interlaced mode: " + nrow); + deinterlacer.setRow(nrow); + bytesRead = (imgInfo.bitspPixel * deinterlacer.getPixelsToRead() + 7) / 8; + if (bytesRead < 1) + throw new PngjExceptionInternal("wtf??"); + } else { // check for non interlaced + if (nrow < 0 || nrow >= imgInfo.rows || nrow != rowNum + 1) + throw new PngjInputException("invalid row: " + nrow); + } + rowNum = nrow; + // swap buffers + byte[] tmp = rowb; + rowb = rowbprev; + rowbprev = tmp; + // loads in rowbfilter "raw" bytes, with filter + PngHelperInternal.readBytes(idatIstream, rowbfilter, 0, bytesRead + 1); + offset = iIdatCstream.getOffset(); + if (offset < 0) + throw new PngjExceptionInternal("bad offset ??" + offset); + if (maxTotalBytesRead > 0 && offset >= maxTotalBytesRead) + throw new PngjInputException("Reading IDAT: Maximum total bytes to read exceeeded: " + maxTotalBytesRead + + " offset:" + offset); + rowb[0] = 0; + unfilterRow(bytesRead); + rowb[0] = rowbfilter[0]; + if ((rowNum == imgInfo.rows - 1 && !interlaced) || (interlaced && deinterlacer.isAtLastRow())) + readLastAndClose(); + return bytesRead; + } + + /** + * Reads all the (remaining) file, skipping the pixels data. This is much + * more efficient that calling readRow(), specially for big files (about 10 + * times faster!), because it doesn't even decompress the IDAT stream and + * disables CRC check Use this if you are not interested in reading + * pixels,only metadata. + */ + public void readSkippingAllRows() { + if (firstChunksNotYetRead()) + readFirstChunks(); + // we read directly from the compressed stream, we dont decompress nor chec CRC + iIdatCstream.disableCrcCheck(); + allocateBuffers(); + try { + int r; + do { + r = iIdatCstream.read(rowbfilter, 0, buffersLen); + } while (r >= 0); + } catch (IOException e) { + throw new PngjInputException("error in raw read of IDAT", e); + } + offset = iIdatCstream.getOffset(); + if (offset < 0) + throw new PngjExceptionInternal("bad offset ??" + offset); + if (maxTotalBytesRead > 0 && offset >= maxTotalBytesRead) + throw new PngjInputException("Reading IDAT: Maximum total bytes to read exceeeded: " + maxTotalBytesRead + + " offset:" + offset); + readLastAndClose(); + } + + /** + * Set total maximum bytes to read (0: unlimited; default: 200MB).
+ * These are the bytes read (not loaded) in the input stream. If exceeded, + * an exception will be thrown. + */ + public void setMaxTotalBytesRead(long maxTotalBytesToRead) { + this.maxTotalBytesRead = maxTotalBytesToRead; + } + + /** + * @return Total maximum bytes to read. + */ + public long getMaxTotalBytesRead() { + return maxTotalBytesRead; + } + + /** + * Set total maximum bytes to load from ancillary chunks (0: unlimited; + * default: 5Mb).
+ * If exceeded, some chunks will be skipped + */ + public void setMaxBytesMetadata(int maxBytesChunksToLoad) { + this.maxBytesMetadata = maxBytesChunksToLoad; + } + + /** + * @return Total maximum bytes to load from ancillary ckunks. + */ + public int getMaxBytesMetadata() { + return maxBytesMetadata; + } + + /** + * Set maximum size in bytes for individual ancillary chunks (0: unlimited; + * default: 2MB).
+ * Chunks exceeding this length will be skipped (the CRC will not be + * checked) and the chunk will be saved as a PngChunkSkipped object. See + * also setSkipChunkIds + */ + public void setSkipChunkMaxSize(int skipChunksBySize) { + this.skipChunkMaxSize = skipChunksBySize; + } + + /** + * @return maximum size in bytes for individual ancillary chunks. + */ + public int getSkipChunkMaxSize() { + return skipChunkMaxSize; + } + + /** + * Chunks ids to be skipped.
+ * These chunks will be skipped (the CRC will not be checked) and the chunk + * will be saved as a PngChunkSkipped object. See also setSkipChunkMaxSize + */ + public void setSkipChunkIds(String[] skipChunksById) { + this.skipChunkIds = skipChunksById == null ? new String[] {} : skipChunksById; + } + + /** + * @return Chunk-IDs to be skipped. + */ + public String[] getSkipChunkIds() { + return skipChunkIds; + } + + /** + * if true, input stream will be closed after ending read + *

+ * default=true + */ + public void setShouldCloseStream(boolean shouldCloseStream) { + this.shouldCloseStream = shouldCloseStream; + } + + /** + * Normally this does nothing, but it can be used to force a premature + * closing. Its recommended practice to call it after reading the image + * pixels. + */ + public void end() { + if (currentChunkGroup < ChunksList.CHUNK_GROUP_6_END) + close(); + } + + /** + * Interlaced PNG is accepted -though not welcomed- now... + */ + public boolean isInterlaced() { + return interlaced; + } + + /** + * set/unset "unpackedMode"
+ * If false (default) packed types (bitdepth=1,2 or 4) will keep several + * samples packed in one element (byte or int)
+ * If true, samples will be unpacked on reading, and each element in the + * scanline will be sample. This implies more processing and memory, but + * it's the most efficient option if you intend to read individual pixels.
+ * This option should only be set before start reading. + * + * @param unPackedMode + */ + public void setUnpackedMode(boolean unPackedMode) { + this.unpackedMode = unPackedMode; + } + + /** + * @see PngReader#setUnpackedMode(boolean) + */ + public boolean isUnpackedMode() { + return unpackedMode; + } + + /** + * Tries to reuse the allocated buffers from other already used PngReader + * object. This will have no effect if the buffers are smaller than necessary. + * It also reuses the inflater. + * + * @param other A PngReader that has already finished reading pixels. Can be null. + */ + public void reuseBuffersFrom(PngReader other) { + if(other==null) return; + if (other.currentChunkGroup < ChunksList.CHUNK_GROUP_5_AFTERIDAT) + throw new PngjInputException("PngReader to be reused have not yet ended reading pixels"); + if (other.rowbfilter != null && other.rowbfilter.length >= buffersLen) { + rowbfilter = other.rowbfilter; + rowb = other.rowb; + rowbprev = other.rowbprev; + } + inflater = other.inflater; + } + + /** + * Disables the CRC integrity check in IDAT chunks and ancillary chunks, + * this gives a slight increase in reading speed for big files + */ + public void setCrcCheckDisabled() { + crcEnabled = false; + } + + /** + * Just for testing. TO be called after ending reading, only if + * initCrctest() was called before start + * + * @return CRC of the raw pixels values + */ + long getCrctestVal() { + return crctest.getValue(); + } + + /** + * Inits CRC object and enables CRC calculation + */ + void initCrctest() { + this.crctest = new CRC32(); + } + + /** + * Basic info, for debugging. + */ + public String toString() { // basic info + return "filename=" + filename + " " + imgInfo.toString(); + } +} diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkHelper.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkHelper.java index ed091d35a..a995e4481 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkHelper.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/ChunkHelper.java @@ -1,253 +1,297 @@ -package jogamp.opengl.util.pngj.chunks; - -// see http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html -// http://www.w3.org/TR/PNG/#5Chunk-naming-conventions -// http://www.w3.org/TR/PNG/#table53 -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.InflaterInputStream; - -import jogamp.opengl.util.pngj.PngHelperInternal; -import jogamp.opengl.util.pngj.PngjException; - - -public class ChunkHelper { - public static final String IHDR = "IHDR"; - public static final String PLTE = "PLTE"; - public static final String IDAT = "IDAT"; - public static final String IEND = "IEND"; - public static final byte[] b_IHDR = toBytes(IHDR); - public static final byte[] b_PLTE = toBytes(PLTE); - public static final byte[] b_IDAT = toBytes(IDAT); - public static final byte[] b_IEND = toBytes(IEND); - - public static final String cHRM = "cHRM"; - public static final String gAMA = "gAMA"; - public static final String iCCP = "iCCP"; - public static final String sBIT = "sBIT"; - public static final String sRGB = "sRGB"; - public static final String bKGD = "bKGD"; - public static final String hIST = "hIST"; - public static final String tRNS = "tRNS"; - public static final String pHYs = "pHYs"; - public static final String sPLT = "sPLT"; - public static final String tIME = "tIME"; - public static final String iTXt = "iTXt"; - public static final String tEXt = "tEXt"; - public static final String zTXt = "zTXt"; - - /** - * Converts to bytes using Latin1 (ISO-8859-1) - */ - public static byte[] toBytes(String x) { - return x.getBytes(PngHelperInternal.charsetLatin1); - } - - /** - * Converts to String using Latin1 (ISO-8859-1) - */ - public static String toString(byte[] x) { - return new String(x, PngHelperInternal.charsetLatin1); - } - - /** - * Converts to String using Latin1 (ISO-8859-1) - */ - public static String toString(byte[] x, int offset, int len) { - return new String(x, offset, len, PngHelperInternal.charsetLatin1); - } - - /** - * Converts to bytes using UTF-8 - */ - public static byte[] toBytesUTF8(String x) { - return x.getBytes(PngHelperInternal.charsetUTF8); - } - - /** - * Converts to string using UTF-8 - */ - public static String toStringUTF8(byte[] x) { - return new String(x, PngHelperInternal.charsetUTF8); - } - - /** - * Converts to string using UTF-8 - */ - public static String toStringUTF8(byte[] x, int offset, int len) { - return new String(x, offset, len, PngHelperInternal.charsetUTF8); - } - - /** - * critical chunk : first letter is uppercase - */ - public static boolean isCritical(String id) { - return (Character.isUpperCase(id.charAt(0))); - } - - /** - * public chunk: second letter is uppercase - */ - public static boolean isPublic(String id) { // - return (Character.isUpperCase(id.charAt(1))); - } - - /** - * Safe to copy chunk: fourth letter is lower case - */ - public static boolean isSafeToCopy(String id) { - return (!Character.isUpperCase(id.charAt(3))); - } - - /** - * "Unknown" just means that our chunk factory (even when it has been augmented by client code) did not recognize - * its id - */ - public static boolean isUnknown(PngChunk c) { - return c instanceof PngChunkUNKNOWN; - } - - /** - * Finds position of null byte in array - * - * @param b - * @return -1 if not found - */ - public static int posNullByte(byte[] b) { - for (int i = 0; i < b.length; i++) - if (b[i] == 0) - return i; - return -1; - } - - /** - * Decides if a chunk should be loaded, according to a ChunkLoadBehaviour - * - * @param id - * @param behav - * @return true/false - */ - public static boolean shouldLoad(String id, ChunkLoadBehaviour behav) { - if (isCritical(id)) - return true; - boolean kwown = PngChunk.isKnown(id); - switch (behav) { - case LOAD_CHUNK_ALWAYS: - return true; - case LOAD_CHUNK_IF_SAFE: - return kwown || isSafeToCopy(id); - case LOAD_CHUNK_KNOWN: - return kwown; - case LOAD_CHUNK_NEVER: - return false; - } - return false; // should not reach here - } - - public final static byte[] compressBytes(byte[] ori, boolean compress) { - return compressBytes(ori, 0, ori.length, compress); - } - - public static byte[] compressBytes(byte[] ori, int offset, int len, boolean compress) { - try { - ByteArrayInputStream inb = new ByteArrayInputStream(ori, offset, len); - InputStream in = compress ? inb : new InflaterInputStream(inb); - ByteArrayOutputStream outb = new ByteArrayOutputStream(); - OutputStream out = compress ? new DeflaterOutputStream(outb) : outb; - shovelInToOut(in, out); - in.close(); - out.close(); - return outb.toByteArray(); - } catch (Exception e) { - throw new PngjException(e); - } - } - - /** - * Shovels all data from an input stream to an output stream. - */ - private static void shovelInToOut(InputStream in, OutputStream out) throws IOException { - byte[] buffer = new byte[1024]; - int len; - while ((len = in.read(buffer)) > 0) { - out.write(buffer, 0, len); - } - } - - public static boolean maskMatch(int v, int mask) { - return (v & mask) != 0; - } - - /** - * Returns only the chunks that "match" the predicate - * - * See also trimList() - */ - public static List filterList(List target, ChunkPredicate predicateKeep) { - List result = new ArrayList(); - for (PngChunk element : target) { - if (predicateKeep.match(element)) { - result.add(element); - } - } - return result; - } - - /** - * Remove (in place) the chunks that "match" the predicate - * - * See also filterList - */ - public static int trimList(List target, ChunkPredicate predicateRemove) { - Iterator it = target.iterator(); - int cont = 0; - while (it.hasNext()) { - PngChunk c = it.next(); - if (predicateRemove.match(c)) { - it.remove(); - cont++; - } - } - return cont; - } - - /** - * MY adhoc criteria: two chunks are "equivalent" ("practically equal") if they have same id and (perhaps, if - * multiple are allowed) if the match also in some "internal key" (eg: key for string values, palette for sPLT, etc) - * - * Notice that the use of this is optional, and that the PNG standard allows Text chunks that have same key - * - * @return true if "equivalent" - */ - public static final boolean equivalent(PngChunk c1, PngChunk c2) { - if (c1 == c2) - return true; - if (c1 == null || c2 == null || !c1.id.equals(c2.id)) - return false; - // same id - if (c1.getClass() != c2.getClass()) - return false; // should not happen - if (!c2.allowsMultiple()) - return true; - if (c1 instanceof PngChunkTextVar) { - return ((PngChunkTextVar) c1).getKey().equals(((PngChunkTextVar) c2).getKey()); - } - if (c1 instanceof PngChunkSPLT) { - return ((PngChunkSPLT) c1).getPalName().equals(((PngChunkSPLT) c2).getPalName()); - } - // unknown chunks that allow multiple? consider they don't match - return false; - } - - public static boolean isText(PngChunk c) { - return c instanceof PngChunkTextVar; - } - -} +package jogamp.opengl.util.pngj.chunks; + + +// see http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html +// http://www.w3.org/TR/PNG/#5Chunk-naming-conventions +// http://www.w3.org/TR/PNG/#table53 +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; + +import jogamp.opengl.util.pngj.PngHelperInternal; +import jogamp.opengl.util.pngj.PngjException; + + +public class ChunkHelper { + public static final String IHDR = "IHDR"; + public static final String PLTE = "PLTE"; + public static final String IDAT = "IDAT"; + public static final String IEND = "IEND"; + public static final byte[] b_IHDR = toBytes(IHDR); + public static final byte[] b_PLTE = toBytes(PLTE); + public static final byte[] b_IDAT = toBytes(IDAT); + public static final byte[] b_IEND = toBytes(IEND); + + public static final String cHRM = "cHRM"; + public static final String gAMA = "gAMA"; + public static final String iCCP = "iCCP"; + public static final String sBIT = "sBIT"; + public static final String sRGB = "sRGB"; + public static final String bKGD = "bKGD"; + public static final String hIST = "hIST"; + public static final String tRNS = "tRNS"; + public static final String pHYs = "pHYs"; + public static final String sPLT = "sPLT"; + public static final String tIME = "tIME"; + public static final String iTXt = "iTXt"; + public static final String tEXt = "tEXt"; + public static final String zTXt = "zTXt"; + + private static final ThreadLocal inflaterProvider = new ThreadLocal() { + protected Inflater initialValue() { + return new Inflater(); + } + }; + + private static final ThreadLocal deflaterProvider = new ThreadLocal() { + protected Deflater initialValue() { + return new Deflater(); + } + }; + + /* + * static auxiliary buffer. any method that uses this should synchronize against this + */ + private static byte[] tmpbuffer = new byte[4096]; + + /** + * Converts to bytes using Latin1 (ISO-8859-1) + */ + public static byte[] toBytes(String x) { + return x.getBytes(PngHelperInternal.charsetLatin1); + } + + /** + * Converts to String using Latin1 (ISO-8859-1) + */ + public static String toString(byte[] x) { + return new String(x, PngHelperInternal.charsetLatin1); + } + + /** + * Converts to String using Latin1 (ISO-8859-1) + */ + public static String toString(byte[] x, int offset, int len) { + return new String(x, offset, len, PngHelperInternal.charsetLatin1); + } + + /** + * Converts to bytes using UTF-8 + */ + public static byte[] toBytesUTF8(String x) { + return x.getBytes(PngHelperInternal.charsetUTF8); + } + + /** + * Converts to string using UTF-8 + */ + public static String toStringUTF8(byte[] x) { + return new String(x, PngHelperInternal.charsetUTF8); + } + + /** + * Converts to string using UTF-8 + */ + public static String toStringUTF8(byte[] x, int offset, int len) { + return new String(x, offset, len, PngHelperInternal.charsetUTF8); + } + + /** + * critical chunk : first letter is uppercase + */ + public static boolean isCritical(String id) { + return (Character.isUpperCase(id.charAt(0))); + } + + /** + * public chunk: second letter is uppercase + */ + public static boolean isPublic(String id) { // + return (Character.isUpperCase(id.charAt(1))); + } + + /** + * Safe to copy chunk: fourth letter is lower case + */ + public static boolean isSafeToCopy(String id) { + return (!Character.isUpperCase(id.charAt(3))); + } + + /** + * "Unknown" just means that our chunk factory (even when it has been + * augmented by client code) did not recognize its id + */ + public static boolean isUnknown(PngChunk c) { + return c instanceof PngChunkUNKNOWN; + } + + /** + * Finds position of null byte in array + * + * @param b + * @return -1 if not found + */ + public static int posNullByte(byte[] b) { + for (int i = 0; i < b.length; i++) + if (b[i] == 0) + return i; + return -1; + } + + /** + * Decides if a chunk should be loaded, according to a ChunkLoadBehaviour + * + * @param id + * @param behav + * @return true/false + */ + public static boolean shouldLoad(String id, ChunkLoadBehaviour behav) { + if (isCritical(id)) + return true; + boolean kwown = PngChunk.isKnown(id); + switch (behav) { + case LOAD_CHUNK_ALWAYS: + return true; + case LOAD_CHUNK_IF_SAFE: + return kwown || isSafeToCopy(id); + case LOAD_CHUNK_KNOWN: + return kwown; + case LOAD_CHUNK_NEVER: + return false; + } + return false; // should not reach here + } + + public final static byte[] compressBytes(byte[] ori, boolean compress) { + return compressBytes(ori, 0, ori.length, compress); + } + + public static byte[] compressBytes(byte[] ori, int offset, int len, boolean compress) { + try { + ByteArrayInputStream inb = new ByteArrayInputStream(ori, offset, len); + InputStream in = compress ? inb : new InflaterInputStream(inb, getInflater()); + ByteArrayOutputStream outb = new ByteArrayOutputStream(); + OutputStream out = compress ? new DeflaterOutputStream(outb) : outb; + shovelInToOut(in, out); + in.close(); + out.close(); + return outb.toByteArray(); + } catch (Exception e) { + throw new PngjException(e); + } + } + + /** + * Shovels all data from an input stream to an output stream. + */ + private static void shovelInToOut(InputStream in, OutputStream out) throws IOException { + synchronized (tmpbuffer) { + int len; + while ((len = in.read(tmpbuffer)) > 0) { + out.write(tmpbuffer, 0, len); + } + } + } + + public static boolean maskMatch(int v, int mask) { + return (v & mask) != 0; + } + + /** + * Returns only the chunks that "match" the predicate + * + * See also trimList() + */ + public static List filterList(List target, ChunkPredicate predicateKeep) { + List result = new ArrayList(); + for (PngChunk element : target) { + if (predicateKeep.match(element)) { + result.add(element); + } + } + return result; + } + + /** + * Remove (in place) the chunks that "match" the predicate + * + * See also filterList + */ + public static int trimList(List target, ChunkPredicate predicateRemove) { + Iterator it = target.iterator(); + int cont = 0; + while (it.hasNext()) { + PngChunk c = it.next(); + if (predicateRemove.match(c)) { + it.remove(); + cont++; + } + } + return cont; + } + + /** + * MY adhoc criteria: two chunks are "equivalent" ("practically equal") if + * they have same id and (perhaps, if multiple are allowed) if the match + * also in some "internal key" (eg: key for string values, palette for sPLT, + * etc) + * + * Notice that the use of this is optional, and that the PNG standard allows + * Text chunks that have same key + * + * @return true if "equivalent" + */ + public static final boolean equivalent(PngChunk c1, PngChunk c2) { + if (c1 == c2) + return true; + if (c1 == null || c2 == null || !c1.id.equals(c2.id)) + return false; + // same id + if (c1.getClass() != c2.getClass()) + return false; // should not happen + if (!c2.allowsMultiple()) + return true; + if (c1 instanceof PngChunkTextVar) { + return ((PngChunkTextVar) c1).getKey().equals(((PngChunkTextVar) c2).getKey()); + } + if (c1 instanceof PngChunkSPLT) { + return ((PngChunkSPLT) c1).getPalName().equals(((PngChunkSPLT) c2).getPalName()); + } + // unknown chunks that allow multiple? consider they don't match + return false; + } + + public static boolean isText(PngChunk c) { + return c instanceof PngChunkTextVar; + } + + /** + * thread-local inflater, just reset : this should be only used for short + * individual chunks compression + */ + public static Inflater getInflater() { + Inflater inflater = inflaterProvider.get(); + inflater.reset(); + return inflater; + } + + /** + * thread-local deflater, just reset : this should be only used for short + * individual chunks decompression + */ + public static Deflater getDeflater() { + Deflater deflater = deflaterProvider.get(); + deflater.reset(); + return deflater; + } + +} diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkTRNS.java b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkTRNS.java index 1de5c0833..b68776477 100644 --- a/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkTRNS.java +++ b/src/jogl/classes/jogamp/opengl/util/pngj/chunks/PngChunkTRNS.java @@ -1,143 +1,141 @@ -package jogamp.opengl.util.pngj.chunks; - -import jogamp.opengl.util.pngj.ImageInfo; -import jogamp.opengl.util.pngj.PngHelperInternal; -import jogamp.opengl.util.pngj.PngjException; - -/** - * tRNS chunk. - *

- * see http://www.w3.org/TR/PNG/#11tRNS - *

- * this chunk structure depends on the image type - */ -public class PngChunkTRNS extends PngChunkSingle { - public final static String ID = ChunkHelper.tRNS; - - // http://www.w3.org/TR/PNG/#11tRNS - - // only one of these is meaningful, depending on the image type - private int gray; - private int red, green, blue; - private int[] paletteAlpha = new int[] {}; - - public PngChunkTRNS(ImageInfo info) { - super(ID, info); - } - - @Override - public ChunkOrderingConstraint getOrderingConstraint() { - return ChunkOrderingConstraint.AFTER_PLTE_BEFORE_IDAT; - } - - @Override - public ChunkRaw createRawChunk() { - ChunkRaw c = null; - if (imgInfo.greyscale) { - c = createEmptyChunk(2, true); - PngHelperInternal.writeInt2tobytes(gray, c.data, 0); - } else if (imgInfo.indexed) { - c = createEmptyChunk(paletteAlpha.length, true); - for (int n = 0; n < c.len; n++) { - c.data[n] = (byte) paletteAlpha[n]; - } - } else { - c = createEmptyChunk(6, true); - PngHelperInternal.writeInt2tobytes(red, c.data, 0); - PngHelperInternal.writeInt2tobytes(green, c.data, 0); - PngHelperInternal.writeInt2tobytes(blue, c.data, 0); - } - return c; - } - - @Override - public void parseFromRaw(ChunkRaw c) { - if (imgInfo.greyscale) { - gray = PngHelperInternal.readInt2fromBytes(c.data, 0); - } else if (imgInfo.indexed) { - int nentries = c.data.length; - paletteAlpha = new int[nentries]; - for (int n = 0; n < nentries; n++) { - paletteAlpha[n] = (int) (c.data[n] & 0xff); - } - } else { - red = PngHelperInternal.readInt2fromBytes(c.data, 0); - green = PngHelperInternal.readInt2fromBytes(c.data, 2); - blue = PngHelperInternal.readInt2fromBytes(c.data, 4); - } - } - - @Override - public void cloneDataFromRead(PngChunk other) { - PngChunkTRNS otherx = (PngChunkTRNS) other; - gray = otherx.gray; - red = otherx.red; - green = otherx.red; - blue = otherx.red; - if (otherx.paletteAlpha != null) { - paletteAlpha = new int[otherx.paletteAlpha.length]; - System.arraycopy(otherx.paletteAlpha, 0, paletteAlpha, 0, paletteAlpha.length); - } - } - - /** - * Set rgb values - * - */ - public void setRGB(int r, int g, int b) { - if (imgInfo.greyscale || imgInfo.indexed) - throw new PngjException("only rgb or rgba images support this"); - red = r; - green = g; - blue = b; - } - - public int[] getRGB() { - if (imgInfo.greyscale || imgInfo.indexed) - throw new PngjException("only rgb or rgba images support this"); - return new int[] { red, green, blue }; - } - - public void setGray(int g) { - if (!imgInfo.greyscale) - throw new PngjException("only grayscale images support this"); - gray = g; - } - - public int getGray() { - if (!imgInfo.greyscale) - throw new PngjException("only grayscale images support this"); - return gray; - } - - /** - * WARNING: non deep copy - */ - public void setPalletteAlpha(int[] palAlpha) { - if (!imgInfo.indexed) - throw new PngjException("only indexed images support this"); - paletteAlpha = palAlpha; - } - - /** - * to use when only one pallete index is set as totally transparent - */ - public void setIndexEntryAsTransparent(int palAlphaIndex) { - if (!imgInfo.indexed) - throw new PngjException("only indexed images support this"); - paletteAlpha = new int[] { palAlphaIndex + 1 }; - for (int i = 0; i < palAlphaIndex; i++) - paletteAlpha[i] = 255; - paletteAlpha[palAlphaIndex] = 0; - } - - /** - * WARNING: non deep copy - */ - public int[] getPalletteAlpha() { - if (!imgInfo.indexed) - throw new PngjException("only indexed images support this"); - return paletteAlpha; - } - -} +package jogamp.opengl.util.pngj.chunks; + +import jogamp.opengl.util.pngj.ImageInfo; +import jogamp.opengl.util.pngj.PngHelperInternal; +import jogamp.opengl.util.pngj.PngjException; + +/** + * tRNS chunk. + *

+ * see http://www.w3.org/TR/PNG/#11tRNS + *

+ * this chunk structure depends on the image type + */ +public class PngChunkTRNS extends PngChunkSingle { + public final static String ID = ChunkHelper.tRNS; + + // http://www.w3.org/TR/PNG/#11tRNS + + // only one of these is meaningful, depending on the image type + private int gray; + private int red, green, blue; + private int[] paletteAlpha = new int[] {}; + + public PngChunkTRNS(ImageInfo info) { + super(ID, info); + } + + @Override + public ChunkOrderingConstraint getOrderingConstraint() { + return ChunkOrderingConstraint.AFTER_PLTE_BEFORE_IDAT; + } + + @Override + public ChunkRaw createRawChunk() { + ChunkRaw c = null; + if (imgInfo.greyscale) { + c = createEmptyChunk(2, true); + PngHelperInternal.writeInt2tobytes(gray, c.data, 0); + } else if (imgInfo.indexed) { + c = createEmptyChunk(paletteAlpha.length, true); + for (int n = 0; n < c.len; n++) { + c.data[n] = (byte) paletteAlpha[n]; + } + } else { + c = createEmptyChunk(6, true); + PngHelperInternal.writeInt2tobytes(red, c.data, 0); + PngHelperInternal.writeInt2tobytes(green, c.data, 0); + PngHelperInternal.writeInt2tobytes(blue, c.data, 0); + } + return c; + } + + @Override + public void parseFromRaw(ChunkRaw c) { + if (imgInfo.greyscale) { + gray = PngHelperInternal.readInt2fromBytes(c.data, 0); + } else if (imgInfo.indexed) { + int nentries = c.data.length; + paletteAlpha = new int[nentries]; + for (int n = 0; n < nentries; n++) { + paletteAlpha[n] = (int) (c.data[n] & 0xff); + } + } else { + red = PngHelperInternal.readInt2fromBytes(c.data, 0); + green = PngHelperInternal.readInt2fromBytes(c.data, 2); + blue = PngHelperInternal.readInt2fromBytes(c.data, 4); + } + } + + @Override + public void cloneDataFromRead(PngChunk other) { + PngChunkTRNS otherx = (PngChunkTRNS) other; + gray = otherx.gray; + red = otherx.red; + green = otherx.green; + blue = otherx.blue; + if (otherx.paletteAlpha != null) { + paletteAlpha = new int[otherx.paletteAlpha.length]; + System.arraycopy(otherx.paletteAlpha, 0, paletteAlpha, 0, paletteAlpha.length); + } + } + + /** + * Set rgb values + * + */ + public void setRGB(int r, int g, int b) { + if (imgInfo.greyscale || imgInfo.indexed) + throw new PngjException("only rgb or rgba images support this"); + red = r; + green = g; + blue = b; + } + + public int[] getRGB() { + if (imgInfo.greyscale || imgInfo.indexed) + throw new PngjException("only rgb or rgba images support this"); + return new int[] { red, green, blue }; + } + + public void setGray(int g) { + if (!imgInfo.greyscale) + throw new PngjException("only grayscale images support this"); + gray = g; + } + + public int getGray() { + if (!imgInfo.greyscale) + throw new PngjException("only grayscale images support this"); + return gray; + } + + /** + * WARNING: non deep copy + */ + public void setPalletteAlpha(int[] palAlpha) { + if (!imgInfo.indexed) + throw new PngjException("only indexed images support this"); + paletteAlpha = palAlpha; + } + + /** + * to use when only one pallete index is set as totally transparent + */ + public void setIndexEntryAsTransparent(int palAlphaIndex) { + if (!imgInfo.indexed) + throw new PngjException("only indexed images support this"); + paletteAlpha = new int[] { palAlphaIndex + 1 }; + for (int i = 0; i < palAlphaIndex; i++) + paletteAlpha[i] = 255; + paletteAlpha[palAlphaIndex] = 0; + } + + /** + * WARNING: non deep copy + */ + public int[] getPalletteAlpha() { + return paletteAlpha; + } + +} -- cgit v1.2.3 From e92e561df9673ce77783d6fa3815a942a39a53c0 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 16 Jul 2013 07:23:07 +0200 Subject: FFMPEGMediaPlayer: Use GL_RED instead of deprecated GL_ALPHA, otherwise won't work w/ core >= GL3 profiles --- .../jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/jogl/classes/jogamp/opengl/util') diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java index a4178967c..1264d8986 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java @@ -193,9 +193,9 @@ public class FFMPEGMediaPlayer extends EGLMediaPlayerImpl { System.out.println("setURL: p2 "+this); int tf, tif=GL.GL_RGBA; // texture format and internal format switch(vBytesPerPixelPerPlane) { - case 1: tf = GL2ES2.GL_ALPHA; tif=GL.GL_ALPHA; break; - case 3: tf = GL2ES2.GL_RGB; tif=GL.GL_RGB; break; - case 4: tf = GL2ES2.GL_RGBA; tif=GL.GL_RGBA; break; + case 1: tf = GL2ES2.GL_RED; tif=GL2ES2.GL_RED; break; // RED shall be supported on ES2, ES3 and GL3-core! + case 3: tf = GL2ES2.GL_RGB; tif=GL.GL_RGB; break; + case 4: tf = GL2ES2.GL_RGBA; tif=GL.GL_RGBA; break; default: throw new RuntimeException("Unsupported bytes-per-pixel / plane "+vBytesPerPixelPerPlane); } setTextureFormat(tif, tf); @@ -307,9 +307,9 @@ public class FFMPEGMediaPlayer extends EGLMediaPlayerImpl { " vec2 v_off = vec2("+tc_w_1+", 0.5);\n"+ " vec2 tc_half = texCoord*0.5;\n"+ " float y,u,v,r,g,b;\n"+ - " y = texture2D(image, texCoord).a;\n"+ - " u = texture2D(image, u_off+tc_half).a;\n"+ - " v = texture2D(image, v_off+tc_half).a;\n"+ + " y = texture2D(image, texCoord).r;\n"+ + " u = texture2D(image, u_off+tc_half).r;\n"+ + " v = texture2D(image, v_off+tc_half).r;\n"+ " y = 1.1643*(y-0.0625);\n"+ " u = u-0.5;\n"+ " v = v-0.5;\n"+ -- cgit v1.2.3 From dba2faf8520a43a809eb756869c6c97a0a2ef2cd Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 16 Jul 2013 10:18:54 +0200 Subject: Fix FFMPEGMediaPlayer: Only use RED for GL3ES3 profiles, otherwise stick w/ ALPHA (regression of e92e561df9673ce77783d6fa3815a942a39a53c0) GLES2 does not and GL2 may not support RED! --- make/scripts/tests.sh | 4 ++-- .../classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/jogl/classes/jogamp/opengl/util') diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 9e7be06d9..bb8d2463f 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -291,7 +291,7 @@ function testawtswt() { #testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelsAWT $* #testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT $* #testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestLandscapeES2NewtCanvasAWT $* -testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestLandscapeES2NEWT $* #testawtswt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasSWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestElektronenMultipliziererNEWT $* @@ -312,7 +312,7 @@ testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $* # av demos # #testnoawt jogamp.opengl.openal.av.ALDummyUsage $* -#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube $* +testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieSimple $* # diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java index 1264d8986..f416bb1f8 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java @@ -193,7 +193,13 @@ public class FFMPEGMediaPlayer extends EGLMediaPlayerImpl { System.out.println("setURL: p2 "+this); int tf, tif=GL.GL_RGBA; // texture format and internal format switch(vBytesPerPixelPerPlane) { - case 1: tf = GL2ES2.GL_RED; tif=GL2ES2.GL_RED; break; // RED shall be supported on ES2, ES3 and GL3-core! + case 1: + if( gl.isGL3ES3() ) { + tf = GL2ES2.GL_RED; tif=GL2ES2.GL_RED; // RED is supported on ES3 and >= GL3 [core]; ALPHA is deprecated on core! + } else { + tf = GL2ES2.GL_ALPHA; tif=GL2ES2.GL_ALPHA; // ALPHA is supported on ES2 and GL2 + } + break; case 3: tf = GL2ES2.GL_RGB; tif=GL.GL_RGB; break; case 4: tf = GL2ES2.GL_RGBA; tif=GL.GL_RGBA; break; default: throw new RuntimeException("Unsupported bytes-per-pixel / plane "+vBytesPerPixelPerPlane); -- cgit v1.2.3 From 8ac3f344aded383ca9a3083a877af7bfdf6e1e48 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 17 Jul 2013 04:27:13 +0200 Subject: Remedy for Bug 782: Issue Debug.initSingleton() or Debug.debug(..) before calling 'PropertyAccess.isPropertyDefined(propName, default)' through Debug class. Calling 'Debug.isPropertyDefined(propName, default)' may be 'optimized' to 'PropertyAccess.isPropertyDefined(propName, default)', which would skip the modules Debug's class initialization. Iff that happens, an AccessControlException may happen, due to requesting an insecure property, since modules own Debug class has not been added it's trusted prefixes from within it's init block yet. This seems to be a bug of the JVM .. to me, however .. the above description is the only able to explain the issue at hand. +++ Fix calls Debug class own static methods, either Debug.initSingleton() or Debug.debug(), before calling 'isPropertyDefined(propName, default)'. +++ Also mark Debug class static methods final! +++ --- src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java | 13 ++++++++++--- .../classes/com/jogamp/opengl/util/awt/TextRenderer.java | 7 ++++++- .../classes/com/jogamp/opengl/util/glsl/ShaderState.java | 9 +++++++-- .../javax/media/opengl/DefaultGLCapabilitiesChooser.java | 7 ++++++- src/jogl/classes/javax/media/opengl/GLContext.java | 8 ++++---- src/jogl/classes/javax/media/opengl/awt/GLJPanel.java | 12 +++++++++--- src/jogl/classes/jogamp/opengl/Debug.java | 9 ++++++--- src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java | 10 ++++++++-- src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java | 8 +++++++- src/jogl/classes/jogamp/opengl/GLDrawableHelper.java | 7 ++++++- src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java | 10 ++++++++-- src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java | 7 ++++++- .../opengl/util/glsl/fixedfunc/FixedFuncPipeline.java | 8 +++++++- src/jogl/classes/jogamp/opengl/windows/wgl/WGLUtil.java | 1 + .../jogamp/opengl/windows/wgl/WindowsWGLDrawable.java | 8 +++++++- .../media/nativewindow/DefaultCapabilitiesChooser.java | 7 ++++++- src/nativewindow/classes/jogamp/nativewindow/Debug.java | 9 ++++++--- .../classes/jogamp/nativewindow/x11/X11Util.java | 3 ++- src/newt/classes/jogamp/newt/Debug.java | 9 ++++++--- src/newt/classes/jogamp/newt/ScreenImpl.java | 7 ++++++- src/newt/classes/jogamp/newt/WindowImpl.java | 11 +++++++---- src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java | 5 ++++- 22 files changed, 135 insertions(+), 40 deletions(-) (limited to 'src/jogl/classes/jogamp/opengl/util') diff --git a/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java b/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java index 27ce7d8ec..dc96cb5f2 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java +++ b/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java @@ -48,9 +48,16 @@ import com.jogamp.opengl.util.glsl.ShaderState; *

*/ public class ImmModeSink { - protected static final boolean DEBUG_BEGIN_END = Debug.isPropertyDefined("jogl.debug.ImmModeSink.BeginEnd", true); - protected static final boolean DEBUG_DRAW = Debug.isPropertyDefined("jogl.debug.ImmModeSink.Draw", true); - protected static final boolean DEBUG_BUFFER = Debug.isPropertyDefined("jogl.debug.ImmModeSink.Buffer", true); + protected static final boolean DEBUG_BEGIN_END; + protected static final boolean DEBUG_DRAW; + protected static final boolean DEBUG_BUFFER; + + static { + Debug.initSingleton(); + DEBUG_BEGIN_END = Debug.isPropertyDefined("jogl.debug.ImmModeSink.BeginEnd", true); + DEBUG_DRAW = Debug.isPropertyDefined("jogl.debug.ImmModeSink.Draw", true); + DEBUG_BUFFER = Debug.isPropertyDefined("jogl.debug.ImmModeSink.Buffer", true); + } public static final int GL_QUADS = 0x0007; // Needs data manipulation on ES1/ES2 public static final int GL_QUAD_STRIP = 0x0008; diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java index 1735fcddd..c67141525 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java @@ -128,7 +128,12 @@ import jogamp.opengl.Debug; @author Kenneth Russell */ public class TextRenderer { - private static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.TextRenderer", true); + private static final boolean DEBUG; + + static { + Debug.initSingleton(); + DEBUG = Debug.isPropertyDefined("jogl.debug.TextRenderer", true); + } // These are occasionally useful for more in-depth debugging private static final boolean DISABLE_GLYPH_CACHE = false; diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java index 968391976..8e7781f07 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java @@ -55,8 +55,13 @@ import com.jogamp.opengl.util.GLArrayDataEditable; * and can be retrieved via {@link #getShaderState(GL)}. *

*/ -public class ShaderState { - public static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.GLSLState", true); +public class ShaderState { + public static final boolean DEBUG; + + static { + Debug.initSingleton(); + DEBUG = Debug.isPropertyDefined("jogl.debug.GLSLState", true); + } public ShaderState() { } diff --git a/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java b/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java index b052769ca..b0f3da8e4 100644 --- a/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java +++ b/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java @@ -85,8 +85,13 @@ import jogamp.opengl.Debug; */ public class DefaultGLCapabilitiesChooser implements GLCapabilitiesChooser { - private static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.CapabilitiesChooser", true); + private static final boolean DEBUG; + static { + Debug.initSingleton(); + DEBUG = Debug.isPropertyDefined("jogl.debug.CapabilitiesChooser", true); + } + private final static int NO_SCORE = -9999999; private final static int DOUBLE_BUFFER_MISMATCH_PENALTY = 1000; private final static int OPAQUE_MISMATCH_PENALTY = 750; diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index f36061c13..aa5fca2c2 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -73,6 +73,10 @@ import com.jogamp.opengl.GLRendererQuirks; refer to a given context. */ public abstract class GLContext { + public static final boolean DEBUG = Debug.debug("GLContext"); + public static final boolean TRACE_SWITCH = Debug.isPropertyDefined("jogl.debug.GLContext.TraceSwitch", true); + public static final boolean DEBUG_TRACE_SWITCH = DEBUG || TRACE_SWITCH; + /** * If true (default), bootstrapping the available GL profiles * will use the highest compatible GL context for each profile, @@ -102,10 +106,6 @@ public abstract class GLContext { protected static final boolean FORCE_NO_FBO_SUPPORT = Debug.isPropertyDefined("jogl.fbo.force.none", true); protected static final boolean FORCE_MIN_FBO_SUPPORT = Debug.isPropertyDefined("jogl.fbo.force.min", true); - public static final boolean DEBUG = Debug.debug("GLContext"); - public static final boolean TRACE_SWITCH = Debug.isPropertyDefined("jogl.debug.GLContext.TraceSwitch", true); - public static final boolean DEBUG_TRACE_SWITCH = DEBUG || TRACE_SWITCH; - /** Reflects property jogl.debug.DebugGL. If true, the debug pipeline is enabled at context creation. */ public static final boolean DEBUG_GL = Debug.isPropertyDefined("jogl.debug.DebugGL", true); /** Reflects property jogl.debug.TraceGL. If true, the trace pipeline is enabled at context creation. */ diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index d3f20b2e5..2a23defbe 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -138,9 +138,9 @@ import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.SingleAWTGLPixelBufferProvide @SuppressWarnings("serial") public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol { - private static final boolean DEBUG = Debug.debug("GLJPanel"); - private static final boolean DEBUG_VIEWPORT = Debug.isPropertyDefined("jogl.debug.GLJPanel.Viewport", true); - private static final boolean USE_GLSL_TEXTURE_RASTERIZER = !Debug.isPropertyDefined("jogl.gljpanel.noglsl", true); + private static final boolean DEBUG; + private static final boolean DEBUG_VIEWPORT; + private static final boolean USE_GLSL_TEXTURE_RASTERIZER; /** Indicates whether the Java 2D OpenGL pipeline is requested by user. */ private static final boolean java2dOGLEnabledByProp; @@ -152,11 +152,17 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private static boolean java2DGLPipelineOK; static { + Debug.initSingleton(); + DEBUG = Debug.debug("GLJPanel"); + DEBUG_VIEWPORT = Debug.isPropertyDefined("jogl.debug.GLJPanel.Viewport", true); + USE_GLSL_TEXTURE_RASTERIZER = !Debug.isPropertyDefined("jogl.gljpanel.noglsl", true); + boolean enabled = false; final String sVal = System.getProperty("sun.java2d.opengl"); if( null != sVal ) { enabled = Boolean.valueOf(sVal); } + Debug.initSingleton(); java2dOGLEnabledByProp = enabled && !Debug.isPropertyDefined("jogl.gljpanel.noogl", true); enabled = false; diff --git a/src/jogl/classes/jogamp/opengl/Debug.java b/src/jogl/classes/jogamp/opengl/Debug.java index f87f1bb3f..b88a09b71 100644 --- a/src/jogl/classes/jogamp/opengl/Debug.java +++ b/src/jogl/classes/jogamp/opengl/Debug.java @@ -68,16 +68,19 @@ public class Debug extends PropertyAccess { System.err.println("JOGL implementation vendor " + p.getImplementationVendor()); } } + + /** Ensures static init block has been issues, i.e. if calling through to {@link PropertyAccess#isPropertyDefined(String, boolean)}. */ + public static final void initSingleton() {} - public static boolean verbose() { + public static final boolean verbose() { return verbose; } - public static boolean debugAll() { + public static final boolean debugAll() { return debugAll; } - public static boolean debug(String subcomponent) { + public static final boolean debug(String subcomponent) { return debugAll() || isPropertyDefined("jogl.debug." + subcomponent, true); } } diff --git a/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java b/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java index 78ab7cc93..17646cc7b 100644 --- a/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java +++ b/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java @@ -87,6 +87,13 @@ import com.jogamp.common.util.IntLongHashMap; */ public class GLBufferSizeTracker { + protected static final boolean DEBUG; + + static { + Debug.initSingleton(); + DEBUG = Debug.isPropertyDefined("jogl.debug.GLBufferSizeTracker", true); + } + // Map from buffer names to sizes. // Note: should probably have some way of shrinking this map, but // can't just make it a WeakHashMap because nobody holds on to the @@ -95,8 +102,7 @@ public class GLBufferSizeTracker { // pattern of buffer objects indicates that the fact that this map // never shrinks is probably not that bad. private IntLongHashMap bufferSizeMap; - protected static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.GLBufferSizeTracker", true); - + public GLBufferSizeTracker() { bufferSizeMap = new IntLongHashMap(); bufferSizeMap.setKeyNotFoundValue(0xFFFFFFFFFFFFFFFFL); diff --git a/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java b/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java index 7f5316fbd..890c82c90 100644 --- a/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java +++ b/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java @@ -76,7 +76,13 @@ import com.jogamp.common.util.IntIntHashMap; */ public class GLBufferStateTracker { - protected static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.GLBufferStateTracker", true); + protected static final boolean DEBUG; + + static { + Debug.initSingleton(); + DEBUG = Debug.isPropertyDefined("jogl.debug.GLBufferStateTracker", true); + } + // Maps binding targets to buffer objects. A null value indicates // that the binding is unknown. A zero value indicates that it is // known that no buffer is bound to the target, according to the diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index 8be910c1a..5418fbaf3 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -62,8 +62,13 @@ import javax.media.opengl.GLRunnable; methods to be able to share it between GLAutoDrawable implementations like GLAutoDrawableBase, GLCanvas and GLJPanel. */ public class GLDrawableHelper { /** true if property jogl.debug.GLDrawable.PerfStats is defined. */ - private static final boolean PERF_STATS = Debug.isPropertyDefined("jogl.debug.GLDrawable.PerfStats", true); + private static final boolean PERF_STATS; + static { + Debug.initSingleton(); + PERF_STATS = Debug.isPropertyDefined("jogl.debug.GLDrawable.PerfStats", true); + } + protected static final boolean DEBUG = GLDrawableImpl.DEBUG; private final Object listenersLock = new Object(); private final ArrayList listeners = new ArrayList(); diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java index 27024d4e1..3833e6852 100644 --- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java @@ -37,8 +37,14 @@ import com.jogamp.opengl.JoglVersion; * @see GLDrawableImpl#getDefaultReadFramebuffer() */ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { - protected static final boolean DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject"); - protected static final boolean DEBUG_SWAP = Debug.isPropertyDefined("jogl.debug.FBObject.Swap", true); + protected static final boolean DEBUG; + protected static final boolean DEBUG_SWAP; + + static { + Debug.initSingleton(); + DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject"); + DEBUG_SWAP = Debug.isPropertyDefined("jogl.debug.FBObject.Swap", true); + } private final GLDrawableImpl parent; private GLCapabilitiesImmutable origParentChosenCaps; diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index 9c1cc7fc4..5d99e3eba 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -84,7 +84,12 @@ import com.jogamp.opengl.GLRendererQuirks; public class EGLDrawableFactory extends GLDrawableFactoryImpl { protected static final boolean DEBUG = GLDrawableFactoryImpl.DEBUG; // allow package access - /* package */ static final boolean QUERY_EGL_ES_NATIVE_TK = Debug.isPropertyDefined("jogl.debug.EGLDrawableFactory.QueryNativeTK", true); + /* package */ static final boolean QUERY_EGL_ES_NATIVE_TK; + + static { + Debug.initSingleton(); + QUERY_EGL_ES_NATIVE_TK = Debug.isPropertyDefined("jogl.debug.EGLDrawableFactory.QueryNativeTK", true); + } private static GLDynamicLookupHelper eglES1DynamicLookupHelper = null; private static GLDynamicLookupHelper eglES2DynamicLookupHelper = null; diff --git a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncPipeline.java b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncPipeline.java index f4f20ac7c..2e924cbfb 100644 --- a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncPipeline.java +++ b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncPipeline.java @@ -66,7 +66,13 @@ import com.jogamp.opengl.util.glsl.fixedfunc.ShaderSelectionMode; *

*/ public class FixedFuncPipeline { - protected static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.FixedFuncPipeline", true); + protected static final boolean DEBUG; + + static { + Debug.initSingleton(); + DEBUG = Debug.isPropertyDefined("jogl.debug.FixedFuncPipeline", true); + } + /** The maximum texture units which could be used, depending on {@link ShaderSelectionMode}. */ public static final int MAX_TEXTURE_UNITS = 8; public static final int MAX_LIGHTS = 8; diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WGLUtil.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WGLUtil.java index f1598d580..3e788d286 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WGLUtil.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WGLUtil.java @@ -51,6 +51,7 @@ public class WGLUtil { public static final boolean USE_WGLVersion_Of_5WGLGDIFuncSet; static { + Debug.initSingleton(); USE_WGLVersion_Of_5WGLGDIFuncSet = Debug.isPropertyDefined("jogl.windows.useWGLVersionOf5WGLGDIFuncSet", true); if(USE_WGLVersion_Of_5WGLGDIFuncSet) { System.err.println("Use WGL version of 5 WGL/GDI functions."); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java index 8b8cb2052..741e671eb 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java @@ -51,7 +51,13 @@ import jogamp.opengl.GLDynamicLookupHelper; public abstract class WindowsWGLDrawable extends GLDrawableImpl { - private static final boolean PROFILING = Debug.isPropertyDefined("jogl.debug.GLDrawable.profiling", true); + private static final boolean PROFILING; + + static { + Debug.initSingleton(); + PROFILING = Debug.isPropertyDefined("jogl.debug.GLDrawable.profiling", true); + } + private static final int PROFILING_TICKS = 200; private int profilingSwapBuffersTicks; private long profilingSwapBuffersTime; diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultCapabilitiesChooser.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultCapabilitiesChooser.java index 744c7e6d5..4f07bca9b 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultCapabilitiesChooser.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultCapabilitiesChooser.java @@ -66,8 +66,13 @@ import jogamp.nativewindow.Debug; */ public class DefaultCapabilitiesChooser implements CapabilitiesChooser { - private static final boolean DEBUG = Debug.isPropertyDefined("nativewindow.debug.CapabilitiesChooser", true); + private static final boolean DEBUG; + static { + Debug.initSingleton(); + DEBUG = Debug.isPropertyDefined("nativewindow.debug.CapabilitiesChooser", true); + } + private final static int NO_SCORE = -9999999; private final static int COLOR_MISMATCH_PENALTY_SCALE = 36; diff --git a/src/nativewindow/classes/jogamp/nativewindow/Debug.java b/src/nativewindow/classes/jogamp/nativewindow/Debug.java index 95547c971..c5e316364 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/Debug.java +++ b/src/nativewindow/classes/jogamp/nativewindow/Debug.java @@ -69,15 +69,18 @@ public class Debug extends PropertyAccess { } } - public static boolean verbose() { + /** Ensures static init block has been issues, i.e. if calling through to {@link PropertyAccess#isPropertyDefined(String, boolean)}. */ + public static final void initSingleton() {} + + public static final boolean verbose() { return verbose; } - public static boolean debugAll() { + public static final boolean debugAll() { return debugAll; } - public static boolean debug(String subcomponent) { + public static final boolean debug(String subcomponent) { return debugAll() || isPropertyDefined("nativewindow.debug." + subcomponent, true); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index bbc58b73a..78e432b7f 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -53,6 +53,8 @@ import com.jogamp.nativewindow.x11.X11GraphicsDevice; * Contains a thread safe X11 utility to retrieve display connections. */ public class X11Util implements ToolkitProperties { + public static final boolean DEBUG = Debug.debug("X11Util"); + /** * See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515 *

@@ -92,7 +94,6 @@ public class X11Util implements ToolkitProperties { */ public static final boolean ATI_HAS_MULTITHREADING_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_MULTITHREADING_BUG", true); - public static final boolean DEBUG = Debug.debug("X11Util"); public static final boolean XSYNC_ENABLED = Debug.isPropertyDefined("nativewindow.debug.X11Util.XSync", true); public static final boolean XERROR_STACKDUMP = DEBUG || Debug.isPropertyDefined("nativewindow.debug.X11Util.XErrorStackDump", true); private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.isPropertyDefined("nativewindow.debug.X11Util.TraceDisplayLifecycle", true); diff --git a/src/newt/classes/jogamp/newt/Debug.java b/src/newt/classes/jogamp/newt/Debug.java index 676d9b758..4b0a98216 100644 --- a/src/newt/classes/jogamp/newt/Debug.java +++ b/src/newt/classes/jogamp/newt/Debug.java @@ -69,15 +69,18 @@ public class Debug extends PropertyAccess { } } - public static boolean verbose() { + /** Ensures static init block has been issues, i.e. if calling through to {@link PropertyAccess#isPropertyDefined(String, boolean)}. */ + public static final void initSingleton() {} + + public static final boolean verbose() { return verbose; } - public static boolean debugAll() { + public static final boolean debugAll() { return debugAll; } - public static boolean debug(String subcomponent) { + public static final boolean debug(String subcomponent) { return debugAll() || isPropertyDefined("newt.debug." + subcomponent, true); } } diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index fe9e91b57..5ffa2ebbf 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -55,7 +55,12 @@ import com.jogamp.newt.event.MonitorModeListener; import com.jogamp.newt.util.MonitorModeUtil; public abstract class ScreenImpl extends Screen implements MonitorModeListener { - protected static final boolean DEBUG_TEST_SCREENMODE_DISABLED = Debug.isPropertyDefined("newt.test.Screen.disableScreenMode", true); + protected static final boolean DEBUG_TEST_SCREENMODE_DISABLED; + + static { + Debug.initSingleton(); + DEBUG_TEST_SCREENMODE_DISABLED = Debug.isPropertyDefined("newt.test.Screen.disableScreenMode", true); + } public static final int default_sm_bpp = 32; public static final int default_sm_widthmm = 519; diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 2c3c903f1..caa461e41 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -81,14 +81,17 @@ import jogamp.nativewindow.SurfaceUpdatedHelper; public abstract class WindowImpl implements Window, NEWTEventConsumer { - public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); - - protected static final ArrayList> windowList = new ArrayList>(); + public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE; static { + Debug.initSingleton(); + DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); + ScreenImpl.initSingleton(); } - + + protected static final ArrayList> windowList = new ArrayList>(); + /** Maybe utilized at a shutdown hook, impl. does not block. */ public static final void shutdownAll() { final int wCount = windowList.size(); diff --git a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java index 1335f5697..f37556dd7 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java @@ -55,9 +55,12 @@ import com.jogamp.newt.MonitorDevice; import com.jogamp.newt.MonitorMode; public class ScreenDriver extends ScreenImpl { - protected static final boolean DEBUG_TEST_RANDR13_DISABLED = Debug.isPropertyDefined("newt.test.Screen.disableRandR13", true); + protected static final boolean DEBUG_TEST_RANDR13_DISABLED; static { + Debug.initSingleton(); + DEBUG_TEST_RANDR13_DISABLED = Debug.isPropertyDefined("newt.test.Screen.disableRandR13", true); + DisplayDriver.initSingleton(); } -- cgit v1.2.3