From 05eef46e33f41f5c234ffb1563fd8f641208fe85 Mon Sep 17 00:00:00 2001
From: Sven Gothel
false
.
- */
+ * {@inheritDoc}
+ *
+ * Returns false
.
+ *
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 Listtrue
.
+ *
+ */
@Override
- public boolean shallLookupGlobal() { return true; }
+ public final boolean shallLookupGlobal() {
+ return true;
+ }
@Override
public final List- * 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
- * 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
- * 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
- * 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
* 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
* See also
- * 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
- * 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
- * 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
*
* @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.
- * Short lived object, to be created while serialing/deserializing Do not reuse it for different chunks.
- * 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 extends PngChunk> 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
* 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()),
- * 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
- * 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 extends PngChunk> 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
- * 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
- * The reading sequence is as follows:
- * 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
- * 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
- * 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.
- *
- * @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).
- * 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"
+ * The reading sequence is as follows:
+ * 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
+ * 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
+ * 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.
+ *
+ * @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).
+ * 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"
- * 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
@@ -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 ArrayListint
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)
* 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.
* int[]
* 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.
*
FileHelper.createPngWriter()
if available.
*
@@ -418,13 +419,15 @@ public class PngWriter {
/**
* Copies first (pre IDAT) ancillary chunks from a PngReader.
* 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.
* 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.
* 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
*
- * 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.
* 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
- * 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
* factoryMap
+ * A chunk is known if we recognize its class, according with
+ * factoryMap
*
- * 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 HashSetFileHelper.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
- *
- * If the bitdepth is 16, the least significant byte is lost.
- *
- * 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
- *
- * 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.
+ *
+ * 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 HashSetFileHelper.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
+ *
+ * If the bitdepth is 16, the least significant byte is lost.
+ *
+ * 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
+ *
+ * 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 Listtrue
(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