commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From chtom...@apache.org
Subject [36/50] [abbrv] commons-imaging git commit: Allow PCX's RLE compression to span multiple lines when reading and when writing. This should not only allow us to read such images, but also compress the images we write better.
Date Wed, 24 May 2017 18:41:24 GMT
Allow PCX's RLE compression to span multiple lines when reading and
when writing. This should not only allow us to read such images, but also
compress the images we write better.

Patch by: me


git-svn-id: https://svn.apache.org/repos/asf/commons/proper/imaging/trunk@1781770 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/commons-imaging/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-imaging/commit/2c61aaa6
Tree: http://git-wip-us.apache.org/repos/asf/commons-imaging/tree/2c61aaa6
Diff: http://git-wip-us.apache.org/repos/asf/commons-imaging/diff/2c61aaa6

Branch: refs/heads/master
Commit: 2c61aaa61a74551573a7946cbf5f35727d405a59
Parents: 231f378
Author: Damjan Jovanovic <damjan@apache.org>
Authored: Sun Feb 5 14:50:40 2017 +0000
Committer: Damjan Jovanovic <damjan@apache.org>
Committed: Sun Feb 5 14:50:40 2017 +0000

----------------------------------------------------------------------
 .../imaging/formats/pcx/PcxImageParser.java     | 58 +++++------------
 .../commons/imaging/formats/pcx/PcxWriter.java  | 62 +++++-------------
 .../commons/imaging/formats/pcx/RleReader.java  | 65 +++++++++++++++++++
 .../commons/imaging/formats/pcx/RleWriter.java  | 68 ++++++++++++++++++++
 4 files changed, 164 insertions(+), 89 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-imaging/blob/2c61aaa6/src/main/java/org/apache/commons/imaging/formats/pcx/PcxImageParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/imaging/formats/pcx/PcxImageParser.java b/src/main/java/org/apache/commons/imaging/formats/pcx/PcxImageParser.java
index 6566078..909371e 100644
--- a/src/main/java/org/apache/commons/imaging/formats/pcx/PcxImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/pcx/PcxImageParser.java
@@ -17,7 +17,6 @@
 package org.apache.commons.imaging.formats.pcx;
 
 import static org.apache.commons.imaging.ImagingConstants.PARAM_KEY_STRICT;
-import static org.apache.commons.imaging.common.BinaryFunctions.readByte;
 import static org.apache.commons.imaging.common.BinaryFunctions.readBytes;
 import static org.apache.commons.imaging.common.BinaryFunctions.skipBytes;
 import static org.apache.commons.imaging.common.ByteConversions.toUInt16;
@@ -299,43 +298,6 @@ public class PcxImageParser extends ImageParser {
         return true;
     }
 
-    private void readScanLine(final PcxHeader pcxHeader, final InputStream is,
-            final byte[] samples) throws IOException, ImageReadException {
-        if (pcxHeader.encoding == PcxHeader.ENCODING_UNCOMPRESSED) {
-            int r;
-            for (int bytesRead = 0; bytesRead < samples.length; bytesRead += r) {
-                r = is.read(samples, bytesRead, samples.length - bytesRead);
-                if (r < 0) {
-                    throw new ImageReadException(
-                            "Premature end of file reading image data");
-                }
-            }
-        } else {
-            if (pcxHeader.encoding == PcxHeader.ENCODING_RLE) {
-                for (int bytesRead = 0; bytesRead < samples.length;) {
-                    final byte b = readByte("Pixel", is, "Error reading image data");
-                    int count;
-                    byte sample;
-                    if ((b & 0xc0) == 0xc0) {
-                        count = b & 0x3f;
-                        sample = readByte("Pixel", is,
-                                "Error reading image data");
-                    } else {
-                        count = 1;
-                        sample = b;
-                    }
-                    for (int i = 0; i < count && bytesRead + i < samples.length;
i++) {
-                        samples[bytesRead + i] = sample;
-                    }
-                    bytesRead += count;
-                }
-            } else {
-                throw new ImageReadException("Invalid PCX encoding "
-                        + pcxHeader.encoding);
-            }
-        }
-    }
-
     private int[] read256ColorPalette(final InputStream stream) throws IOException {
         final byte[] paletteBytes = readBytes("Palette", stream, 769,
                 "Error reading palette");
@@ -371,7 +333,17 @@ public class PcxImageParser extends ImageParser {
         if (ySize < 0) {
             throw new ImageReadException("Image height is negative");
         }
-
+        if (pcxHeader.nPlanes <= 0 || 4 < pcxHeader.nPlanes) {
+            throw new ImageReadException("Unsupported/invalid image with " + pcxHeader.nPlanes
+ " planes");
+        }
+        final RleReader rleReader;
+        if (pcxHeader.encoding == PcxHeader.ENCODING_UNCOMPRESSED) {
+            rleReader = new RleReader(false);
+        } else if (pcxHeader.encoding == PcxHeader.ENCODING_RLE) {
+            rleReader = new RleReader(true);
+        } else {
+            throw new ImageReadException("Unsupported/invalid image encoding " + pcxHeader.encoding);
+        }
         final int scanlineLength = pcxHeader.bytesPerLine * pcxHeader.nPlanes;
         final byte[] scanline = new byte[scanlineLength];
         if ((pcxHeader.bitsPerPixel == 1 || pcxHeader.bitsPerPixel == 2
@@ -380,7 +352,7 @@ public class PcxImageParser extends ImageParser {
             final int bytesPerImageRow = (xSize * pcxHeader.bitsPerPixel + 7) / 8;
             final byte[] image = new byte[ySize * bytesPerImageRow];
             for (int y = 0; y < ySize; y++) {
-                readScanLine(pcxHeader, is, scanline);
+                rleReader.read(is, scanline);
                 System.arraycopy(scanline, 0, image, y * bytesPerImageRow,
                         bytesPerImageRow);
             }
@@ -429,7 +401,7 @@ public class PcxImageParser extends ImageParser {
                     BufferedImage.TYPE_BYTE_BINARY, colorModel);
             final byte[] unpacked = new byte[xSize];
             for (int y = 0; y < ySize; y++) {
-                readScanLine(pcxHeader, is, scanline);
+                rleReader.read(is, scanline);
                 int nextByte = 0;
                 Arrays.fill(unpacked, (byte) 0);
                 for (int plane = 0; plane < pcxHeader.nPlanes; plane++) {
@@ -449,7 +421,7 @@ public class PcxImageParser extends ImageParser {
             image[1] = new byte[xSize * ySize];
             image[2] = new byte[xSize * ySize];
             for (int y = 0; y < ySize; y++) {
-                readScanLine(pcxHeader, is, scanline);
+                rleReader.read(is, scanline);
                 System.arraycopy(scanline, 0, image[0], y * xSize, xSize);
                 System.arraycopy(scanline, pcxHeader.bytesPerLine, image[1], y
                         * xSize, xSize);
@@ -471,7 +443,7 @@ public class PcxImageParser extends ImageParser {
             final int rowLength = 3 * xSize;
             final byte[] image = new byte[rowLength * ySize];
             for (int y = 0; y < ySize; y++) {
-                readScanLine(pcxHeader, is, scanline);
+                rleReader.read(is, scanline);
                 if (pcxHeader.bitsPerPixel == 24) {
                     System.arraycopy(scanline, 0, image, y * rowLength,
                             rowLength);

http://git-wip-us.apache.org/repos/asf/commons-imaging/blob/2c61aaa6/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java b/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java
index 0bc9baa..8b758a5 100644
--- a/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java
+++ b/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java
@@ -34,6 +34,7 @@ class PcxWriter {
     private int encoding;
     private int bitDepth = -1;
     private PixelDensity pixelDensity;
+    private final RleWriter rleWriter;
 
     public PcxWriter(Map<String, Object> params) throws ImageWriteException {
         // make copy of params; we'll clear keys as we consume them.
@@ -60,6 +61,11 @@ class PcxWriter {
                 }
             }
         }
+        if (encoding == PcxImageParser.PcxHeader.ENCODING_UNCOMPRESSED) {
+            rleWriter = new RleWriter(false);
+        } else {
+            rleWriter = new RleWriter(true);
+        }
 
         if (params.containsKey(PcxConstants.PARAM_KEY_PCX_BIT_DEPTH)) {
             final Object value = params.remove(PcxConstants.PARAM_KEY_PCX_BIT_DEPTH);
@@ -93,47 +99,6 @@ class PcxWriter {
         }
     }
 
-    private void writeScanLine(final BinaryOutputStream bos, final byte[] scanline)
-            throws IOException, ImageWriteException {
-        if (encoding == PcxImageParser.PcxHeader.ENCODING_UNCOMPRESSED) {
-            bos.write(scanline);
-        } else {
-            if (encoding == PcxImageParser.PcxHeader.ENCODING_RLE) {
-                int previousByte = -1;
-                int repeatCount = 0;
-                for (final byte element : scanline) {
-                    if ((element & 0xff) == previousByte
-                            && repeatCount < 63) {
-                        ++repeatCount;
-                    } else {
-                        if (repeatCount > 0) {
-                            if (repeatCount == 1
-                                    && (previousByte & 0xc0) != 0xc0) {
-                                bos.write(previousByte);
-                            } else {
-                                bos.write(0xc0 | repeatCount);
-                                bos.write(previousByte);
-                            }
-                        }
-                        previousByte = 0xff & element;
-                        repeatCount = 1;
-                    }
-                }
-                if (repeatCount > 0) {
-                    if (repeatCount == 1 && (previousByte & 0xc0) != 0xc0) {
-                        bos.write(previousByte);
-                    } else {
-                        bos.write(0xc0 | repeatCount);
-                        bos.write(previousByte);
-                    }
-                }
-            } else {
-                throw new ImageWriteException("Invalid PCX encoding "
-                        + encoding);
-            }
-        }
-    }
-
     public void writeImage(final BufferedImage src, final OutputStream os)
             throws ImageWriteException, IOException {
         final PaletteFactory paletteFactory = new PaletteFactory();
@@ -206,8 +171,9 @@ class PcxWriter {
                 rgbBytes[4 * x + 2] = (byte) ((rgbs[x] >> 16) & 0xff);
                 rgbBytes[4 * x + 3] = 0;
             }
-            writeScanLine(bos, rgbBytes);
+            rleWriter.write(bos, rgbBytes);
         }
+        rleWriter.flush(bos);
     }
 
     private void write24BppPCX(final BufferedImage src, final BinaryOutputStream bos)
@@ -243,8 +209,9 @@ class PcxWriter {
                 rgbBytes[bytesPerLine + x] = (byte) ((rgbs[x] >> 8) & 0xff);
                 rgbBytes[2 * bytesPerLine + x] = (byte) (rgbs[x] & 0xff);
             }
-            writeScanLine(bos, rgbBytes);
+            rleWriter.write(bos, rgbBytes);
         }
+        rleWriter.flush(bos);
     }
 
     private void writeBlackAndWhitePCX(final BufferedImage src,
@@ -292,8 +259,9 @@ class PcxWriter {
                 }
                 row[x / 8] |= (bit << (7 - (x % 8)));
             }
-            writeScanLine(bos, row);
+            rleWriter.write(bos, row);
         }
+        rleWriter.flush(bos);
     }
 
     private void write16ColorPCX(final BufferedImage src, final SimplePalette palette,
@@ -344,8 +312,9 @@ class PcxWriter {
                 final int index = palette.getPaletteIndex(0xffffff & argb);
                 indeces[x / 2] |= (index << 4 * (1 - (x % 2)));
             }
-            writeScanLine(bos, indeces);
+            rleWriter.write(bos, indeces);
         }
+        rleWriter.flush(bos);
     }
 
     private void write256ColorPCX(final BufferedImage src, final SimplePalette palette,
@@ -379,8 +348,9 @@ class PcxWriter {
                 final int index = palette.getPaletteIndex(0xffffff & argb);
                 indeces[x] = (byte) index;
             }
-            writeScanLine(bos, indeces);
+            rleWriter.write(bos, indeces);
         }
+        rleWriter.flush(bos);
         // palette
         bos.write(12);
         for (int i = 0; i < 256; i++) {

http://git-wip-us.apache.org/repos/asf/commons-imaging/blob/2c61aaa6/src/main/java/org/apache/commons/imaging/formats/pcx/RleReader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/imaging/formats/pcx/RleReader.java b/src/main/java/org/apache/commons/imaging/formats/pcx/RleReader.java
new file mode 100644
index 0000000..735a205
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/pcx/RleReader.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.pcx;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+import org.apache.commons.imaging.ImageReadException;
+import org.apache.commons.imaging.common.BinaryFunctions;
+
+class RleReader {
+    private final boolean isCompressed;
+    private int count;
+    private byte sample;
+    
+    RleReader(final boolean isCompressed) {
+        this.isCompressed = isCompressed;
+    }
+    
+    void read(final InputStream is, final byte[] samples) throws IOException, ImageReadException
{
+        if (isCompressed) {
+            final int prefill = Math.min(count, samples.length);
+            Arrays.fill(samples, 0, prefill, sample);
+            count -= prefill;
+            
+            for (int bytesRead = prefill; bytesRead < samples.length;) {
+                final byte b = BinaryFunctions.readByte("RleByte", is, "Error reading image
data");
+                if ((b & 0xc0) == 0xc0) {
+                    count = b & 0x3f;
+                    sample = BinaryFunctions.readByte("RleValue", is, "Error reading image
data");
+                } else {
+                    count = 1;
+                    sample = b;
+                }
+                final int samplesToAdd = Math.min(count, samples.length - bytesRead);
+                Arrays.fill(samples, bytesRead, bytesRead + samplesToAdd, sample);
+                bytesRead += samplesToAdd;
+                count -= samplesToAdd;
+            }
+        } else {
+            int r;
+            for (int bytesRead = 0; bytesRead < samples.length; bytesRead += r) {
+                r = is.read(samples, bytesRead, samples.length - bytesRead);
+                if (r < 0) {
+                    throw new ImageReadException(
+                            "Premature end of file reading image data");
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-imaging/blob/2c61aaa6/src/main/java/org/apache/commons/imaging/formats/pcx/RleWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/imaging/formats/pcx/RleWriter.java b/src/main/java/org/apache/commons/imaging/formats/pcx/RleWriter.java
new file mode 100644
index 0000000..ce4e3ea
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/pcx/RleWriter.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.pcx;
+
+import java.io.IOException;
+
+import org.apache.commons.imaging.ImageWriteException;
+import org.apache.commons.imaging.common.BinaryOutputStream;
+
+class RleWriter {
+    private final boolean isCompressed;
+    private int previousByte = -1;
+    private int repeatCount = 0;
+
+    RleWriter(final boolean isCompressed) {
+        this.isCompressed = isCompressed;
+    }
+    
+    void write(final BinaryOutputStream bos, final byte[] samples)
+            throws IOException, ImageWriteException {
+        if (isCompressed) {
+            for (final byte element : samples) {
+                if ((element & 0xff) == previousByte
+                        && repeatCount < 63) {
+                    ++repeatCount;
+                } else {
+                    if (repeatCount > 0) {
+                        if (repeatCount == 1
+                                && (previousByte & 0xc0) != 0xc0) {
+                            bos.write(previousByte);
+                        } else {
+                            bos.write(0xc0 | repeatCount);
+                            bos.write(previousByte);
+                        }
+                    }
+                    previousByte = 0xff & element;
+                    repeatCount = 1;
+                }
+            }
+        } else {
+            bos.write(samples);
+        }
+    }
+    
+    void flush(final BinaryOutputStream bos) throws IOException {
+        if (repeatCount > 0) {
+            if (repeatCount == 1 && (previousByte & 0xc0) != 0xc0) {
+                bos.write(previousByte);
+            } else {
+                bos.write(0xc0 | repeatCount);
+                bos.write(previousByte);
+            }
+        }
+    }
+}


Mime
View raw message