aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/opengl/util/pngj/PngDeinterlacer.java
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2012-12-31 16:39:15 +0100
committerSven Gothel <[email protected]>2012-12-31 16:39:15 +0100
commit921b33825340d27deec2883ded21cb7434decc94 (patch)
tree164ce843d4939144f63fd7d7db24124c86a332d4 /src/jogl/classes/jogamp/opengl/util/pngj/PngDeinterlacer.java
parent96f8f55a8db5f430fc17ce9ea1bf45e4728ab6ac (diff)
Update PNGJ 0.85 -> 1.12 (w/ interlace read support) ; Added PNG Interlace read tests (TestPNGTextureFromFileNEWT)
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/util/pngj/PngDeinterlacer.java')
-rw-r--r--src/jogl/classes/jogamp/opengl/util/pngj/PngDeinterlacer.java277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/jogl/classes/jogamp/opengl/util/pngj/PngDeinterlacer.java b/src/jogl/classes/jogamp/opengl/util/pngj/PngDeinterlacer.java
new file mode 100644
index 000000000..e099c4f6a
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/util/pngj/PngDeinterlacer.java
@@ -0,0 +1,277 @@
+package jogamp.opengl.util.pngj;
+
+import java.util.Random;
+
+// you really dont' want to peek inside this
+class PngDeinterlacer {
+ private final ImageInfo imi;
+ private int pass; // 1-7
+ private int rows, cols, dY, dX, oY, oX, oXsamples, dXsamples; // at current pass
+ // current row in the virtual subsampled image; this incrementes from 0 to cols/dy 7 times
+ private int currRowSubimg = -1;
+ // in the real image, this will cycle from 0 to im.rows in different steps, 7 times
+ private int currRowReal = -1;
+
+ private final int packedValsPerPixel;
+ private final int packedMask;
+ private final int packedShift;
+
+ private int[][] imageInt; // FULL image -only used for PngWriter as temporary storage
+ private short[][] imageShort;
+ private byte[][] imageByte;
+
+ PngDeinterlacer(ImageInfo iminfo) {
+ this.imi = iminfo;
+ pass = 0;
+ if (imi.packed) {
+ packedValsPerPixel = 8 / imi.bitDepth;
+ packedShift = imi.bitDepth;
+ if (imi.bitDepth == 1)
+ packedMask = 0x80;
+ else if (imi.bitDepth == 2)
+ packedMask = 0xc0;
+ else
+ packedMask = 0xf0;
+ } else {
+ packedMask = packedShift = packedValsPerPixel = 1;// dont care
+ }
+ setPass(1);
+ setRow(0);
+ }
+
+ /** this refers to the row currRowSubimg */
+ void setRow(int n) {
+ currRowSubimg = n;
+ currRowReal = n * dY + oY;
+ if (currRowReal < 0 || currRowReal >= imi.rows)
+ throw new PngjExceptionInternal("bad row - this should not happen");
+ }
+
+ void setPass(int p) {
+ if (this.pass == p)
+ return;
+ pass = p;
+ switch (pass) {
+ case 1:
+ dY = dX = 8;
+ oX = oY = 0;
+ break;
+ case 2:
+ dY = dX = 8;
+ oX = 4;
+ oY = 0;
+ break;
+ case 3:
+ dX = 4;
+ dY = 8;
+ oX = 0;
+ oY = 4;
+ break;
+ case 4:
+ dX = dY = 4;
+ oX = 2;
+ oY = 0;
+ break;
+ case 5:
+ dX = 2;
+ dY = 4;
+ oX = 0;
+ oY = 2;
+ break;
+ case 6:
+ dX = dY = 2;
+ oX = 1;
+ oY = 0;
+ break;
+ case 7:
+ dX = 1;
+ dY = 2;
+ oX = 0;
+ oY = 1;
+ break;
+ default:
+ throw new PngjExceptionInternal("bad interlace pass" + pass);
+ }
+ rows = (imi.rows - oY) / dY + 1;
+ if ((rows - 1) * dY + oY >= imi.rows)
+ rows--; // can be 0
+ cols = (imi.cols - oX) / dX + 1;
+ if ((cols - 1) * dX + oX >= imi.cols)
+ cols--; // can be 0
+ if (cols == 0)
+ rows = 0; // really...
+ dXsamples = dX * imi.channels;
+ oXsamples = oX * imi.channels;
+ }
+
+ // notice that this is a "partial" deinterlace, it will be called several times for the same row!
+ void deinterlaceInt(int[] src, int[] dst, boolean readInPackedFormat) {
+ if (!(imi.packed && readInPackedFormat))
+ for (int i = 0, j = oXsamples; i < cols * imi.channels; i += imi.channels, j += dXsamples)
+ for (int k = 0; k < imi.channels; k++)
+ dst[j + k] = src[i + k];
+ else
+ deinterlaceIntPacked(src, dst);
+ }
+
+ // interlaced+packed = monster; this is very clumsy!
+ private void deinterlaceIntPacked(int[] src, int[] dst) {
+ int spos, smod, smask; // source byte position, bits to shift to left (01,2,3,4
+ int tpos, tmod, p, d;
+ spos = 0;
+ smask = packedMask;
+ smod = -1;
+ // can this really work?
+ for (int i = 0, j = oX; i < cols; i++, j += dX) {
+ spos = i / packedValsPerPixel;
+ smod += 1;
+ if (smod >= packedValsPerPixel)
+ smod = 0;
+ smask >>= packedShift; // the source mask cycles
+ if (smod == 0)
+ smask = packedMask;
+ tpos = j / packedValsPerPixel;
+ tmod = j % packedValsPerPixel;
+ p = src[spos] & smask;
+ d = tmod - smod;
+ if (d > 0)
+ p >>= (d * packedShift);
+ else if (d < 0)
+ p <<= ((-d) * packedShift);
+ dst[tpos] |= p;
+ }
+ }
+
+ // yes, duplication of code is evil, normally
+ void deinterlaceByte(byte[] src, byte[] dst, boolean readInPackedFormat) {
+ if (!(imi.packed && readInPackedFormat))
+ for (int i = 0, j = oXsamples; i < cols * imi.channels; i += imi.channels, j += dXsamples)
+ for (int k = 0; k < imi.channels; k++)
+ dst[j + k] = src[i + k];
+ else
+ deinterlacePackedByte(src, dst);
+ }
+
+ private void deinterlacePackedByte(byte[] src, byte[] dst) {
+ int spos, smod, smask; // source byte position, bits to shift to left (01,2,3,4
+ int tpos, tmod, p, d;
+ // what the heck are you reading here? I told you would not enjoy this. Try Dostoyevsky or Simone Weil instead
+ spos = 0;
+ smask = packedMask;
+ smod = -1;
+ // Arrays.fill(dst, 0);
+ for (int i = 0, j = oX; i < cols; i++, j += dX) {
+ spos = i / packedValsPerPixel;
+ smod += 1;
+ if (smod >= packedValsPerPixel)
+ smod = 0;
+ smask >>= packedShift; // the source mask cycles
+ if (smod == 0)
+ smask = packedMask;
+ tpos = j / packedValsPerPixel;
+ tmod = j % packedValsPerPixel;
+ p = src[spos] & smask;
+ d = tmod - smod;
+ if (d > 0)
+ p >>= (d * packedShift);
+ else if (d < 0)
+ p <<= ((-d) * packedShift);
+ dst[tpos] |= p;
+ }
+ }
+
+ /**
+ * Is current row the last row for the lass pass??
+ */
+ boolean isAtLastRow() {
+ return pass == 7 && currRowSubimg == rows - 1;
+ }
+
+ /**
+ * current row number inside the "sub image"
+ */
+ int getCurrRowSubimg() {
+ return currRowSubimg;
+ }
+
+ /**
+ * current row number inside the "real image"
+ */
+ int getCurrRowReal() {
+ return currRowReal;
+ }
+
+ /**
+ * current pass number (1-7)
+ */
+ int getPass() {
+ return pass;
+ }
+
+ /**
+ * How many rows has the current pass?
+ **/
+ int getRows() {
+ return rows;
+ }
+
+ /**
+ * How many columns (pixels) are there in the current row
+ */
+ int getCols() {
+ return cols;
+ }
+
+ public int getPixelsToRead() {
+ return getCols();
+ }
+
+ int[][] getImageInt() {
+ return imageInt;
+ }
+
+ void setImageInt(int[][] imageInt) {
+ this.imageInt = imageInt;
+ }
+
+ short[][] getImageShort() {
+ return imageShort;
+ }
+
+ void setImageShort(short[][] imageShort) {
+ this.imageShort = imageShort;
+ }
+
+ byte[][] getImageByte() {
+ return imageByte;
+ }
+
+ void setImageByte(byte[][] imageByte) {
+ this.imageByte = imageByte;
+ }
+
+ static void test() {
+ Random rand = new Random();
+ PngDeinterlacer ih = new PngDeinterlacer(new ImageInfo(rand.nextInt(35) + 1, rand.nextInt(52) + 1, 8, true));
+ int np = ih.imi.cols * ih.imi.rows;
+ System.out.println(ih.imi);
+ for (int p = 1; p <= 7; p++) {
+ ih.setPass(p);
+ for (int row = 0; row < ih.getRows(); row++) {
+ ih.setRow(row);
+ int b = ih.getCols();
+ np -= b;
+ System.out.printf("Read %d pixels. Pass:%d Realline:%d cols=%d dX=%d oX=%d last:%b\n", b, ih.pass,
+ ih.currRowReal, ih.cols, ih.dX, ih.oX, ih.isAtLastRow());
+
+ }
+ }
+ if (np != 0)
+ throw new PngjExceptionInternal("wtf??" + ih.imi);
+ }
+
+ public static void main(String[] args) {
+ test();
+ }
+
+}