From 16b8d35395d619668c2f848c10160115f544d7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Sun, 15 Feb 2015 16:20:43 +0100 Subject: [PATCH 01/24] Added example for bitmap with negative height --- src/test/data/images/bmp/5/WhatIsThis.txt | 3 +++ .../images/bmp/5/monochrome-negative-height.bmp | Bin 0 -> 162 bytes 2 files changed, 3 insertions(+) create mode 100644 src/test/data/images/bmp/5/WhatIsThis.txt create mode 100644 src/test/data/images/bmp/5/monochrome-negative-height.bmp diff --git a/src/test/data/images/bmp/5/WhatIsThis.txt b/src/test/data/images/bmp/5/WhatIsThis.txt new file mode 100644 index 0000000000..d1fca95c72 --- /dev/null +++ b/src/test/data/images/bmp/5/WhatIsThis.txt @@ -0,0 +1,3 @@ +This is a monochrome 4x8 bitmap with negative height value. This image was taken from http://issues.apache.org/jira/browse/IMAGING-162. The original name was monochrome-negative-height.bmp. + +Added 2015 by Michael Grosss, mgmechanics@mgmechanics.de diff --git a/src/test/data/images/bmp/5/monochrome-negative-height.bmp b/src/test/data/images/bmp/5/monochrome-negative-height.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b7885c487d01690bba94e04d1fa28b4262442ec4 GIT binary patch literal 162 zcmZ?rUBmzZO+YFKh*^O6$N&HT85tPC5(+?4m>YtbfNT(Uat|s7QX~P8K4bv20+|bE P3jkRPKG0K literal 0 HcmV?d00001 From e780954a7dc98215448eaae0a8c84fa028e28905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Sun, 15 Feb 2015 16:50:23 +0100 Subject: [PATCH 02/24] moved info to info.txt --- src/test/data/images/bmp/5/WhatIsThis.txt | 3 --- src/test/data/images/info.txt | 7 ++++++- 2 files changed, 6 insertions(+), 4 deletions(-) delete mode 100644 src/test/data/images/bmp/5/WhatIsThis.txt diff --git a/src/test/data/images/bmp/5/WhatIsThis.txt b/src/test/data/images/bmp/5/WhatIsThis.txt deleted file mode 100644 index d1fca95c72..0000000000 --- a/src/test/data/images/bmp/5/WhatIsThis.txt +++ /dev/null @@ -1,3 +0,0 @@ -This is a monochrome 4x8 bitmap with negative height value. This image was taken from http://issues.apache.org/jira/browse/IMAGING-162. The original name was monochrome-negative-height.bmp. - -Added 2015 by Michael Grosss, mgmechanics@mgmechanics.de diff --git a/src/test/data/images/info.txt b/src/test/data/images/info.txt index c281d195e5..de04a62e4f 100644 --- a/src/test/data/images/info.txt +++ b/src/test/data/images/info.txt @@ -13,7 +13,7 @@ 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. - +Changed 2015 by Michael Grosss, mgmechanics@mgmechanics.de @@ -37,6 +37,11 @@ bmp/4/rle4deltaXY.asm bmp/4/rle4deltaXY.bmp Contributed by Damjan Jovanovic. 4 bit RLE compression with an encoded-mode delta-Y + +bmp/5/monochrome-negative-height.bmp + Monochrome 4x8 bitmap with negative height value. + This image was taken from http://issues.apache.org/jira/browse/IMAGING-162. + It was attached there by Myroslav Golub. dcx/1/Oregon Scientific DS6639 - DSC_0307 - small.dcx Charles Matthew Chen's reference photo, converted by Damjan Jovanovic. From ba340c5234ede99d32935a5cbc5adb1941a821d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Sun, 15 Feb 2015 17:31:41 +0100 Subject: [PATCH 03/24] moved image file to get it out of automatic use in existing tests because it lets these tests fail --- src/test/data/images/info.txt | 13 ++++---- .../bmp/1}/monochrome-negative-height.bmp | Bin src/test/data/specificTests/info.txt | 28 ++++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) rename src/test/data/{images/bmp/5 => specificTests/bmp/1}/monochrome-negative-height.bmp (100%) create mode 100644 src/test/data/specificTests/info.txt diff --git a/src/test/data/images/info.txt b/src/test/data/images/info.txt index de04a62e4f..61223be82f 100644 --- a/src/test/data/images/info.txt +++ b/src/test/data/images/info.txt @@ -13,8 +13,14 @@ 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. -Changed 2015 by Michael Grosss, mgmechanics@mgmechanics.de +Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de +Adding any image file to this folder means that this file will used immediately +in various tests. These tests use certain functions of this library for all +image files in this folder. +For example, consider an bmp image file which shall bring up an exception. +Adding this file here will cause some existing tests to fail while the same tests +pass for all other bmp images in this folder. bmp/1/Oregon Scientific DS6639 - DSC_0307 - small.bmp @@ -38,11 +44,6 @@ bmp/4/rle4deltaXY.bmp Contributed by Damjan Jovanovic. 4 bit RLE compression with an encoded-mode delta-Y -bmp/5/monochrome-negative-height.bmp - Monochrome 4x8 bitmap with negative height value. - This image was taken from http://issues.apache.org/jira/browse/IMAGING-162. - It was attached there by Myroslav Golub. - dcx/1/Oregon Scientific DS6639 - DSC_0307 - small.dcx Charles Matthew Chen's reference photo, converted by Damjan Jovanovic. diff --git a/src/test/data/images/bmp/5/monochrome-negative-height.bmp b/src/test/data/specificTests/bmp/1/monochrome-negative-height.bmp similarity index 100% rename from src/test/data/images/bmp/5/monochrome-negative-height.bmp rename to src/test/data/specificTests/bmp/1/monochrome-negative-height.bmp diff --git a/src/test/data/specificTests/info.txt b/src/test/data/specificTests/info.txt new file mode 100644 index 0000000000..ff176b452f --- /dev/null +++ b/src/test/data/specificTests/info.txt @@ -0,0 +1,28 @@ +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You 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. + +Added 2015 by Michael Gross, mgmechanics@mgmechanics.de + +Adding a file to this folder has no effect to any existing test. If you want to +use a just added file you need to add test which uses this file. + +For example, this folder can be used to keep images which cause an exception. + +bmp/1/monochrome-negative-height.bmp + Monochrome 4x8 bitmap with negative height value. + This image was taken from http://issues.apache.org/jira/browse/IMAGING-162. + It was attached there by Myroslav Golub. + + From ac982293cc5e62e6a7e6762f2bd7516effee7e69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Sun, 15 Feb 2015 17:56:53 +0100 Subject: [PATCH 04/24] added tests to reproduce IMAGING-162 --- .../commons/imaging/ImagingTestConstants.java | 14 ++-- .../bmp/specific/BmpReadSpecificTest.java | 68 +++++++++++++++++++ 2 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java diff --git a/src/test/java/org/apache/commons/imaging/ImagingTestConstants.java b/src/test/java/org/apache/commons/imaging/ImagingTestConstants.java index 7efcae78ba..c46a119c8e 100644 --- a/src/test/java/org/apache/commons/imaging/ImagingTestConstants.java +++ b/src/test/java/org/apache/commons/imaging/ImagingTestConstants.java @@ -13,6 +13,8 @@ * 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. + * + * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging; @@ -24,13 +26,13 @@ public interface ImagingTestConstants { static final File PHIL_HARVEY_TEST_IMAGE_FOLDER = new File( - FilenameUtils - .separatorsToSystem("src\\test\\data\\images\\exif\\philHarvey\\")); + FilenameUtils.separatorsToSystem("src\\test\\data\\images\\exif\\philHarvey\\") + ); static final File SOURCE_FOLDER = new File("src"); static final File TEST_SOURCE_FOLDER = new File(SOURCE_FOLDER, "test"); - static final File TEST_DATA_SOURCE_FOLDER = new File(TEST_SOURCE_FOLDER, - "data"); - static final File TEST_IMAGE_FOLDER = new File(TEST_DATA_SOURCE_FOLDER, - "images"); + static final File TEST_DATA_SOURCE_FOLDER = new File(TEST_SOURCE_FOLDER, "data"); + static final File TEST_IMAGE_FOLDER = new File(TEST_DATA_SOURCE_FOLDER, "images"); + // folder for files fo specific tests, see info.txt in the named folder + static final File TEST_SPECIFIC_FOLDER = new File(TEST_DATA_SOURCE_FOLDER, "specificTests"); } diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java new file mode 100644 index 0000000000..d41f3b0bf7 --- /dev/null +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + * Added 2015 by Michael Gross, mgmechanics@mgmechanics.de + * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de + */ + +package org.apache.commons.imaging.formats.bmp.specific; + +import org.apache.commons.imaging.formats.bmp.*; +import static org.junit.Assert.assertNotNull; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import org.apache.commons.imaging.ImageInfo; +import org.apache.commons.imaging.ImageReadException; +import org.apache.commons.imaging.Imaging; +import org.junit.Test; + +/** + * This test class contains some specific tests i.e. reading an image with negative height. + */ +public class BmpReadSpecificTest extends BmpBaseTest { + /** + * Get image info for a bmp with negative height + * @throws ImageReadException + * @throws IOException + */ + @Test + public void testImageInfoNegativeHeight() throws ImageReadException, IOException { + final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-negative-height.bmp"); + final Map params = Collections.emptyMap(); + final ImageInfo imageInfo = Imaging.getImageInfo(imageFile, params); + assertNotNull(imageInfo); + // TODO assert more + } + + /** + * Get a buffered image for a bmp with negative height + * @throws ImageReadException + * @throws IOException + */ + @Test + public void testBufferedImageNegativeHeight() throws Exception { + final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-negative-height.bmp"); + final BufferedImage image = Imaging.getBufferedImage(imageFile); + assertNotNull(image); + // TODO assert more + } + +} From 609fc9c23120eaa2b67bfc9d2de8dbc23494e0ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Sun, 15 Feb 2015 18:47:13 +0100 Subject: [PATCH 05/24] image info is correct even for bitmaps with negative height - one test fails --- .../imaging/formats/bmp/BmpHeaderInfo.java | 11 ++++++++ .../imaging/formats/bmp/BmpImageParser.java | 25 +++++++++++-------- .../bmp/specific/BmpReadSpecificTest.java | 25 ++++++++++++------- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java index 62785d8cc9..47100cb289 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java @@ -13,6 +13,8 @@ * 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. + * + * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; @@ -32,7 +34,14 @@ class BmpHeaderInfo { public final int bitmapHeaderSize; public final int width; + /** + * raw image height, may be negative + */ public final int height; + /** + * absolute image height + */ + public final int heightAbsolute; public final int planes; public final int bitsPerPixel; public final int compression; @@ -86,6 +95,8 @@ public BmpHeaderInfo(final byte identifier1, final byte identifier2, final int f this.bitmapHeaderSize = bitmapHeaderSize; this.width = width; this.height = height; + this.heightAbsolute = (this.height < 0) ? this.height * -1 : this.height; + this.planes = planes; this.bitsPerPixel = bitsPerPixel; this.compression = compression; diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index 79ec0d93b8..f078bf8ba0 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -13,6 +13,8 @@ * 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. + * + * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; @@ -388,8 +390,9 @@ private ImageContents readImageContents(final InputStream is, System.out.println("ColorTable: " + ((colorTable == null) ? "null" : Integer.toString(colorTable.length))); } - - final int pixelCount = bhi.width * bhi.height; + + // since image height can be negative use the absolute height here + final int pixelCount = bhi.width * bhi.heightAbsolute; int imageLineLength = (((bhi.bitsPerPixel) * bhi.width) + 7) / 8; @@ -401,6 +404,7 @@ private ImageContents readImageContents(final InputStream is, // this.debugNumber("ExtraBitsPerPixel", ExtraBitsPerPixel, 4); debugNumber("bhi.Width", bhi.width, 4); debugNumber("bhi.Height", bhi.height, 4); + debugNumber("bhi.HeightAbsolute", bhi.heightAbsolute, 4); debugNumber("ImageLineLength", imageLineLength, 4); // this.debugNumber("imageDataSize", imageDataSize, 4); debugNumber("PixelCount", pixelCount, 4); @@ -429,8 +433,9 @@ private ImageContents readImageContents(final InputStream is, } else if (extraBytes > 0) { readBytes("BitmapDataOffset", is, extraBytes, "Not a Valid BMP File"); } - - final int imageDataSize = bhi.height * imageLineLength; + + // since image height can be negative use the absolute height here + final int imageDataSize = bhi.heightAbsolute * imageLineLength; if (verbose) { debugNumber("imageDataSize", imageDataSize, 4); @@ -513,8 +518,8 @@ public Dimension getImageSize(final ByteSource byteSource, Map p if (bhi == null) { throw new ImageReadException("BMP: couldn't read header"); } - - return new Dimension(bhi.width, bhi.height); + // since image height can be negative use the absolute height here + return new Dimension(bhi.width, bhi.heightAbsolute); } @@ -586,8 +591,8 @@ public ImageInfo getImageInfo(final ByteSource byteSource, Map p if (bhi == null) { throw new ImageReadException("BMP: couldn't read header"); } - - final int height = bhi.height; + // since image height can be negative use the absolute height here + final int heightAbsolute = bhi.heightAbsolute; final int width = bhi.width; final List comments = new ArrayList(); @@ -608,7 +613,7 @@ public ImageInfo getImageInfo(final ByteSource byteSource, Map p final float physicalWidthInch = (float) ((double) width / (double) physicalWidthDpi); // int physicalHeightDpi = 72; final int physicalHeightDpi = (int) (bhi.vResolution * .0254); - final float physicalHeightInch = (float) ((double) height / (double) physicalHeightDpi); + final float physicalHeightInch = (float) ((double) heightAbsolute / (double) physicalHeightDpi); final String formatDetails = "Bmp (" + (char) bhi.identifier1 + (char) bhi.identifier2 + ": " @@ -621,7 +626,7 @@ public ImageInfo getImageInfo(final ByteSource byteSource, Map p final ImageInfo.CompressionAlgorithm compressionAlgorithm = ImageInfo.CompressionAlgorithm.RLE; return new ImageInfo(formatDetails, bitsPerPixel, comments, - format, name, height, mimeType, numberOfImages, + format, name, heightAbsolute, mimeType, numberOfImages, physicalHeightDpi, physicalHeightInch, physicalWidthDpi, physicalWidthInch, width, progressive, transparent, usesPalette, colorType, compressionAlgorithm); diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java index d41f3b0bf7..3d7afbfd61 100644 --- a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java @@ -22,16 +22,18 @@ import org.apache.commons.imaging.formats.bmp.*; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertEquals; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.util.Collections; +import java.util.HashMap; import java.util.Map; import org.apache.commons.imaging.ImageInfo; import org.apache.commons.imaging.ImageReadException; import org.apache.commons.imaging.Imaging; +import org.apache.commons.imaging.ImagingConstants; import org.junit.Test; /** @@ -39,17 +41,25 @@ */ public class BmpReadSpecificTest extends BmpBaseTest { /** - * Get image info for a bmp with negative height + * Get image info for a bmp with negative height. + * Expected result: Even if the height of bitmap a negative number all information about + * the size of the image shall be positive. The original negative height shall be used only + * to get the image data. * @throws ImageReadException * @throws IOException */ @Test public void testImageInfoNegativeHeight() throws ImageReadException, IOException { final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-negative-height.bmp"); - final Map params = Collections.emptyMap(); + + final Map params = new HashMap(); + params.put(ImagingConstants.PARAM_KEY_VERBOSE, false); + final ImageInfo imageInfo = Imaging.getImageInfo(imageFile, params); assertNotNull(imageInfo); - // TODO assert more + assertEquals(8, imageInfo.getHeight()); + assertEquals(72, imageInfo.getPhysicalHeightDpi()); + assertEquals(0.11111111f, imageInfo.getPhysicalHeightInch(), 0.1f); } /** @@ -57,12 +67,9 @@ public void testImageInfoNegativeHeight() throws ImageReadException, IOException * @throws ImageReadException * @throws IOException */ - @Test + @Test(expected=ImageReadException.class) public void testBufferedImageNegativeHeight() throws Exception { final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-negative-height.bmp"); - final BufferedImage image = Imaging.getBufferedImage(imageFile); - assertNotNull(image); - // TODO assert more + Imaging.getBufferedImage(imageFile); } - } From 61528990e6a5ee15416f367169b98aa6e313b7d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Sun, 15 Feb 2015 19:07:53 +0100 Subject: [PATCH 06/24] added exception in case of someone tries to read an image with negative height --- .../imaging/formats/bmp/BmpImageParser.java | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index f078bf8ba0..7e1df201e4 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -712,17 +712,34 @@ public BufferedImage getBufferedImage(final InputStream inputStream, Map Date: Sun, 15 Feb 2015 19:12:36 +0100 Subject: [PATCH 07/24] typo --- .../org/apache/commons/imaging/formats/bmp/BmpImageParser.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index 7e1df201e4..5facfad78c 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -732,8 +732,7 @@ public BufferedImage getBufferedImage(final InputStream inputStream, Map Date: Sun, 15 Feb 2015 21:19:30 +0100 Subject: [PATCH 08/24] corrected use of wrong kind of height --- .../apache/commons/imaging/formats/bmp/BmpImageParser.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index 5facfad78c..d8b6fec627 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -737,8 +737,9 @@ public BufferedImage getBufferedImage(final InputStream inputStream, Map Date: Sun, 15 Feb 2015 21:39:37 +0100 Subject: [PATCH 09/24] further distinct between raw and absolute height --- .../imaging/formats/bmp/BmpHeaderInfo.java | 51 ++++++++++++++++--- .../imaging/formats/bmp/BmpImageParser.java | 28 +++++----- .../imaging/formats/bmp/PixelParserRle.java | 2 +- .../formats/bmp/PixelParserSimple.java | 2 +- 4 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java index 47100cb289..621e10acac 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java @@ -35,11 +35,13 @@ class BmpHeaderInfo { public final int bitmapHeaderSize; public final int width; /** - * raw image height, may be negative + * Image height as read from image file header (therefore called + * {@literal "raw height"}, may be negative i.e. for BMP files */ - public final int height; + public final int heightRaw; /** - * absolute image height + * Absolute image height, is never negative. + * Use this to calculate the correct size of the image. */ public final int heightAbsolute; public final int planes; @@ -77,10 +79,45 @@ static class ColorSpace { ColorSpaceCoordinate green; ColorSpaceCoordinate blue; } - + + /** + * Constructor + * @param identifier1 + * @param identifier2 + * @param fileSize + * @param reserved + * @param bitmapDataOffset + * @param bitmapHeaderSize + * @param width + * @param heightRaw The height as read from image file header. + * For some file formats, for example BMP, the image file header may provide + * a negative number for height (for BMP it means that image data are ordered + * top-down instead bottom-up). + * @param planes + * @param bitsPerPixel + * @param compression + * @param bitmapDataSize + * @param hResolution + * @param vResolution + * @param colorsUsed + * @param colorsImportant + * @param redMask + * @param greenMask + * @param blueMask + * @param alphaMask + * @param colorSpaceType + * @param colorSpace + * @param gammaRed + * @param gammaGreen + * @param gammaBlue + * @param intent + * @param profileData + * @param profileSize + * @param reservedV5 + */ public BmpHeaderInfo(final byte identifier1, final byte identifier2, final int fileSize, final int reserved, final int bitmapDataOffset, final int bitmapHeaderSize, - final int width, final int height, final int planes, final int bitsPerPixel, + final int width, final int heightRaw, final int planes, final int bitsPerPixel, final int compression, final int bitmapDataSize, final int hResolution, final int vResolution, final int colorsUsed, final int colorsImportant, final int redMask, final int greenMask, final int blueMask, final int alphaMask, final int colorSpaceType, @@ -94,8 +131,8 @@ public BmpHeaderInfo(final byte identifier1, final byte identifier2, final int f this.bitmapHeaderSize = bitmapHeaderSize; this.width = width; - this.height = height; - this.heightAbsolute = (this.height < 0) ? this.height * -1 : this.height; + this.heightRaw = heightRaw; + this.heightAbsolute = (this.heightRaw < 0) ? this.heightRaw * -1 : this.heightRaw; this.planes = planes; this.bitsPerPixel = bitsPerPixel; diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index d8b6fec627..181f47b833 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -103,7 +103,7 @@ private BmpHeaderInfo readBmpHeaderInfo(final InputStream is, final int bitmapHeaderSize = read4Bytes("Bitmap Header Size", is, "Not a Valid BMP File", getByteOrder()); int width = 0; - int height = 0; + int heightRaw = 0; int planes = 0; int bitsPerPixel = 0; int compression = 0; @@ -132,7 +132,7 @@ private BmpHeaderInfo readBmpHeaderInfo(final InputStream is, if (bitmapHeaderSize >= 40) { // BITMAPINFOHEADER width = read4Bytes("Width", is, "Not a Valid BMP File", getByteOrder()); - height = read4Bytes("Height", is, "Not a Valid BMP File", getByteOrder()); + heightRaw = read4Bytes("HeightRaw", is, "Not a Valid BMP File", getByteOrder()); planes = read2Bytes("Planes", is, "Not a Valid BMP File", getByteOrder()); bitsPerPixel = read2Bytes("Bits Per Pixel", is, "Not a Valid BMP File", getByteOrder()); compression = read4Bytes("Compression", is, "Not a Valid BMP File", getByteOrder()); @@ -189,7 +189,7 @@ private BmpHeaderInfo readBmpHeaderInfo(final InputStream is, debugNumber("bitmapDataOffset", bitmapDataOffset, 4); debugNumber("bitmapHeaderSize", bitmapHeaderSize, 4); debugNumber("width", width, 4); - debugNumber("height", height, 4); + debugNumber("heightRaw", heightRaw, 4); debugNumber("planes", planes, 2); debugNumber("bitsPerPixel", bitsPerPixel, 2); debugNumber("compression", compression, 4); @@ -231,7 +231,7 @@ private BmpHeaderInfo readBmpHeaderInfo(final InputStream is, return new BmpHeaderInfo(identifier1, identifier2, fileSize, reserved, bitmapDataOffset, bitmapHeaderSize, width, - height, planes, bitsPerPixel, compression, bitmapDataSize, + heightRaw, planes, bitsPerPixel, compression, bitmapDataSize, hResolution, vResolution, colorsUsed, colorsImportant, redMask, greenMask, blueMask, alphaMask, colorSpaceType, colorSpace, gammaRed, gammaGreen, gammaBlue, intent, profileData, @@ -391,7 +391,7 @@ private ImageContents readImageContents(final InputStream is, + ((colorTable == null) ? "null" : Integer.toString(colorTable.length))); } - // since image height can be negative use the absolute height here + // since image heightRaw can be negative use the absolute heightRaw here final int pixelCount = bhi.width * bhi.heightAbsolute; int imageLineLength = (((bhi.bitsPerPixel) * bhi.width) + 7) / 8; @@ -403,7 +403,7 @@ private ImageContents readImageContents(final InputStream is, // ((ExtraBitsPerPixel + bhi.BitsPerPixel) * bhi.Width), 4); // this.debugNumber("ExtraBitsPerPixel", ExtraBitsPerPixel, 4); debugNumber("bhi.Width", bhi.width, 4); - debugNumber("bhi.Height", bhi.height, 4); + debugNumber("bhi.HeightRaw", bhi.heightRaw, 4); debugNumber("bhi.HeightAbsolute", bhi.heightAbsolute, 4); debugNumber("ImageLineLength", imageLineLength, 4); // this.debugNumber("imageDataSize", imageDataSize, 4); @@ -434,7 +434,7 @@ private ImageContents readImageContents(final InputStream is, readBytes("BitmapDataOffset", is, extraBytes, "Not a Valid BMP File"); } - // since image height can be negative use the absolute height here + // since image heightRaw can be negative use the absolute heightRaw here final int imageDataSize = bhi.heightAbsolute * imageLineLength; if (verbose) { @@ -518,7 +518,7 @@ public Dimension getImageSize(final ByteSource byteSource, Map p if (bhi == null) { throw new ImageReadException("BMP: couldn't read header"); } - // since image height can be negative use the absolute height here + // since image heightRaw can be negative use the absolute heightRaw here return new Dimension(bhi.width, bhi.heightAbsolute); } @@ -591,7 +591,7 @@ public ImageInfo getImageInfo(final ByteSource byteSource, Map p if (bhi == null) { throw new ImageReadException("BMP: couldn't read header"); } - // since image height can be negative use the absolute height here + // since image heightRaw can be negative use the absolute heightRaw here final int heightAbsolute = bhi.heightAbsolute; final int width = bhi.width; @@ -712,11 +712,11 @@ public BufferedImage getBufferedImage(final InputStream inputStream, Map= 0; y--) { + for (int y = bhi.heightRaw - 1; y >= 0; y--) { for (int x = 0; x < bhi.width; x++) { final int rgb = getNextRGB(); From 89d0d7fd650ea5ca9e1f7c578fc467c5e5960a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Sun, 15 Feb 2015 22:18:57 +0100 Subject: [PATCH 10/24] added test which should return OK once reading bitmaps with negative height is implemented --- .../imaging/formats/bmp/BmpImageParser.java | 2 +- .../bmp/specific/BmpReadSpecificTest.java | 35 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index 181f47b833..7425127317 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -729,7 +729,7 @@ public BufferedImage getBufferedImage(final InputStream inputStream, Map Date: Mon, 16 Feb 2015 07:37:38 +0100 Subject: [PATCH 11/24] reverted recent changes in sources but not in tests --- .../imaging/formats/bmp/BmpHeaderInfo.java | 56 ++-------------- .../imaging/formats/bmp/BmpImageParser.java | 66 +++++++------------ .../imaging/formats/bmp/PixelParserRle.java | 2 +- .../formats/bmp/PixelParserSimple.java | 2 +- 4 files changed, 28 insertions(+), 98 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java index 621e10acac..62785d8cc9 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java @@ -13,8 +13,6 @@ * 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. - * - * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; @@ -34,16 +32,7 @@ class BmpHeaderInfo { public final int bitmapHeaderSize; public final int width; - /** - * Image height as read from image file header (therefore called - * {@literal "raw height"}, may be negative i.e. for BMP files - */ - public final int heightRaw; - /** - * Absolute image height, is never negative. - * Use this to calculate the correct size of the image. - */ - public final int heightAbsolute; + public final int height; public final int planes; public final int bitsPerPixel; public final int compression; @@ -79,45 +68,10 @@ static class ColorSpace { ColorSpaceCoordinate green; ColorSpaceCoordinate blue; } - - /** - * Constructor - * @param identifier1 - * @param identifier2 - * @param fileSize - * @param reserved - * @param bitmapDataOffset - * @param bitmapHeaderSize - * @param width - * @param heightRaw The height as read from image file header. - * For some file formats, for example BMP, the image file header may provide - * a negative number for height (for BMP it means that image data are ordered - * top-down instead bottom-up). - * @param planes - * @param bitsPerPixel - * @param compression - * @param bitmapDataSize - * @param hResolution - * @param vResolution - * @param colorsUsed - * @param colorsImportant - * @param redMask - * @param greenMask - * @param blueMask - * @param alphaMask - * @param colorSpaceType - * @param colorSpace - * @param gammaRed - * @param gammaGreen - * @param gammaBlue - * @param intent - * @param profileData - * @param profileSize - * @param reservedV5 - */ + public BmpHeaderInfo(final byte identifier1, final byte identifier2, final int fileSize, final int reserved, final int bitmapDataOffset, final int bitmapHeaderSize, - final int width, final int heightRaw, final int planes, final int bitsPerPixel, + final int width, final int height, final int planes, final int bitsPerPixel, final int compression, final int bitmapDataSize, final int hResolution, final int vResolution, final int colorsUsed, final int colorsImportant, final int redMask, final int greenMask, final int blueMask, final int alphaMask, final int colorSpaceType, @@ -131,9 +85,7 @@ public BmpHeaderInfo(final byte identifier1, final byte identifier2, final int f this.bitmapHeaderSize = bitmapHeaderSize; this.width = width; - this.heightRaw = heightRaw; - this.heightAbsolute = (this.heightRaw < 0) ? this.heightRaw * -1 : this.heightRaw; - + this.height = height; this.planes = planes; this.bitsPerPixel = bitsPerPixel; this.compression = compression; diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index 7425127317..79ec0d93b8 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -13,8 +13,6 @@ * 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. - * - * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; @@ -103,7 +101,7 @@ private BmpHeaderInfo readBmpHeaderInfo(final InputStream is, final int bitmapHeaderSize = read4Bytes("Bitmap Header Size", is, "Not a Valid BMP File", getByteOrder()); int width = 0; - int heightRaw = 0; + int height = 0; int planes = 0; int bitsPerPixel = 0; int compression = 0; @@ -132,7 +130,7 @@ private BmpHeaderInfo readBmpHeaderInfo(final InputStream is, if (bitmapHeaderSize >= 40) { // BITMAPINFOHEADER width = read4Bytes("Width", is, "Not a Valid BMP File", getByteOrder()); - heightRaw = read4Bytes("HeightRaw", is, "Not a Valid BMP File", getByteOrder()); + height = read4Bytes("Height", is, "Not a Valid BMP File", getByteOrder()); planes = read2Bytes("Planes", is, "Not a Valid BMP File", getByteOrder()); bitsPerPixel = read2Bytes("Bits Per Pixel", is, "Not a Valid BMP File", getByteOrder()); compression = read4Bytes("Compression", is, "Not a Valid BMP File", getByteOrder()); @@ -189,7 +187,7 @@ private BmpHeaderInfo readBmpHeaderInfo(final InputStream is, debugNumber("bitmapDataOffset", bitmapDataOffset, 4); debugNumber("bitmapHeaderSize", bitmapHeaderSize, 4); debugNumber("width", width, 4); - debugNumber("heightRaw", heightRaw, 4); + debugNumber("height", height, 4); debugNumber("planes", planes, 2); debugNumber("bitsPerPixel", bitsPerPixel, 2); debugNumber("compression", compression, 4); @@ -231,7 +229,7 @@ private BmpHeaderInfo readBmpHeaderInfo(final InputStream is, return new BmpHeaderInfo(identifier1, identifier2, fileSize, reserved, bitmapDataOffset, bitmapHeaderSize, width, - heightRaw, planes, bitsPerPixel, compression, bitmapDataSize, + height, planes, bitsPerPixel, compression, bitmapDataSize, hResolution, vResolution, colorsUsed, colorsImportant, redMask, greenMask, blueMask, alphaMask, colorSpaceType, colorSpace, gammaRed, gammaGreen, gammaBlue, intent, profileData, @@ -390,9 +388,8 @@ private ImageContents readImageContents(final InputStream is, System.out.println("ColorTable: " + ((colorTable == null) ? "null" : Integer.toString(colorTable.length))); } - - // since image heightRaw can be negative use the absolute heightRaw here - final int pixelCount = bhi.width * bhi.heightAbsolute; + + final int pixelCount = bhi.width * bhi.height; int imageLineLength = (((bhi.bitsPerPixel) * bhi.width) + 7) / 8; @@ -403,8 +400,7 @@ private ImageContents readImageContents(final InputStream is, // ((ExtraBitsPerPixel + bhi.BitsPerPixel) * bhi.Width), 4); // this.debugNumber("ExtraBitsPerPixel", ExtraBitsPerPixel, 4); debugNumber("bhi.Width", bhi.width, 4); - debugNumber("bhi.HeightRaw", bhi.heightRaw, 4); - debugNumber("bhi.HeightAbsolute", bhi.heightAbsolute, 4); + debugNumber("bhi.Height", bhi.height, 4); debugNumber("ImageLineLength", imageLineLength, 4); // this.debugNumber("imageDataSize", imageDataSize, 4); debugNumber("PixelCount", pixelCount, 4); @@ -433,9 +429,8 @@ private ImageContents readImageContents(final InputStream is, } else if (extraBytes > 0) { readBytes("BitmapDataOffset", is, extraBytes, "Not a Valid BMP File"); } - - // since image heightRaw can be negative use the absolute heightRaw here - final int imageDataSize = bhi.heightAbsolute * imageLineLength; + + final int imageDataSize = bhi.height * imageLineLength; if (verbose) { debugNumber("imageDataSize", imageDataSize, 4); @@ -518,8 +513,8 @@ public Dimension getImageSize(final ByteSource byteSource, Map p if (bhi == null) { throw new ImageReadException("BMP: couldn't read header"); } - // since image heightRaw can be negative use the absolute heightRaw here - return new Dimension(bhi.width, bhi.heightAbsolute); + + return new Dimension(bhi.width, bhi.height); } @@ -591,8 +586,8 @@ public ImageInfo getImageInfo(final ByteSource byteSource, Map p if (bhi == null) { throw new ImageReadException("BMP: couldn't read header"); } - // since image heightRaw can be negative use the absolute heightRaw here - final int heightAbsolute = bhi.heightAbsolute; + + final int height = bhi.height; final int width = bhi.width; final List comments = new ArrayList(); @@ -613,7 +608,7 @@ public ImageInfo getImageInfo(final ByteSource byteSource, Map p final float physicalWidthInch = (float) ((double) width / (double) physicalWidthDpi); // int physicalHeightDpi = 72; final int physicalHeightDpi = (int) (bhi.vResolution * .0254); - final float physicalHeightInch = (float) ((double) heightAbsolute / (double) physicalHeightDpi); + final float physicalHeightInch = (float) ((double) height / (double) physicalHeightDpi); final String formatDetails = "Bmp (" + (char) bhi.identifier1 + (char) bhi.identifier2 + ": " @@ -626,7 +621,7 @@ public ImageInfo getImageInfo(final ByteSource byteSource, Map p final ImageInfo.CompressionAlgorithm compressionAlgorithm = ImageInfo.CompressionAlgorithm.RLE; return new ImageInfo(formatDetails, bitsPerPixel, comments, - format, name, heightAbsolute, mimeType, numberOfImages, + format, name, height, mimeType, numberOfImages, physicalHeightDpi, physicalHeightInch, physicalWidthDpi, physicalWidthInch, width, progressive, transparent, usesPalette, colorType, compressionAlgorithm); @@ -712,34 +707,17 @@ public BufferedImage getBufferedImage(final InputStream inputStream, Map= 0; y--) { + for (int y = bhi.height - 1; y >= 0; y--) { for (int x = 0; x < bhi.width; x++) { final int rgb = getNextRGB(); From e7c8d7dafe38245f187d7c55c943e732338efb44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Mon, 16 Feb 2015 07:56:44 +0100 Subject: [PATCH 12/24] implemented better solution --- .../commons/imaging/formats/bmp/BmpHeaderInfo.java | 11 ++++++++++- .../commons/imaging/formats/bmp/BmpImageParser.java | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java index 62785d8cc9..996bf86dbf 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java @@ -13,6 +13,8 @@ * 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. + * + * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; @@ -33,6 +35,12 @@ class BmpHeaderInfo { public final int bitmapHeaderSize; public final int width; public final int height; + /** + * According to specification the height can be negative. + *
Positive height: Bitmap is stored bottom-up (0, 0 is in the bottom left corner) + *
Negative height: Bitmap is stored top-down (0, 0 is in the top left corner) + */ + public final boolean isBottomUpBitmap; public final int planes; public final int bitsPerPixel; public final int compression; @@ -85,7 +93,8 @@ public BmpHeaderInfo(final byte identifier1, final byte identifier2, final int f this.bitmapHeaderSize = bitmapHeaderSize; this.width = width; - this.height = height; + this.height = (height >= 0) ? height : height * -1; + this.isBottomUpBitmap = height >= 0; this.planes = planes; this.bitsPerPixel = bitsPerPixel; this.compression = compression; diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index 79ec0d93b8..b1a8b4b045 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -13,6 +13,8 @@ * 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. + * + * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; @@ -715,6 +717,10 @@ public BufferedImage getBufferedImage(final InputStream inputStream, Map Date: Tue, 17 Feb 2015 20:12:53 +0100 Subject: [PATCH 13/24] renamed test class --- .../{BmpReadSpecificTest.java => BmpReadHeightTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/java/org/apache/commons/imaging/formats/bmp/specific/{BmpReadSpecificTest.java => BmpReadHeightTest.java} (98%) diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java similarity index 98% rename from src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java rename to src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java index c330e7f80d..c2af5256e3 100644 --- a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadSpecificTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java @@ -40,7 +40,7 @@ /** * This test class contains some specific tests i.e. reading an image with negative height. */ -public class BmpReadSpecificTest extends BmpBaseTest { +public class BmpReadHeightTest extends BmpBaseTest { /** * Get image info for a bmp with negative height. * Expected result: Even if the height of bitmap a negative number all information about From a59e7d8430153dc3ee1cfb7696efe3e59f57a12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Tue, 17 Feb 2015 21:15:29 +0100 Subject: [PATCH 14/24] added correct colors and two methods to print the colors of the image --- .../bmp/specific/BmpReadHeightTest.java | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java index c2af5256e3..c061a6cfd4 100644 --- a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java @@ -27,7 +27,9 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.commons.imaging.ImageInfo; @@ -89,18 +91,53 @@ public void testBufferedImageNegativeHeightException() throws Exception { public void testBufferedImageNegativeHeight() throws Exception { final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-negative-height.bmp"); final BufferedImage bufImage = Imaging.getBufferedImage(imageFile); + //debugBufferedImageAsTable(bufImage); assertEquals(8, bufImage.getHeight()); assertEquals(4, bufImage.getWidth()); // the image is monochrome and has 4 black pixels, the remaning pixel are white - // the black pixels a placed such that we can make sure the picture is read - // as expected + // the black pixels a placed such that we can make sure the picture is read as expected + // -16777216 => -2^24 => black (4 pixels); -1 => white (other pixels) // top left - white - assertEquals(1, bufImage.getRGB(0, 0)); + assertEquals(-1, bufImage.getRGB(0, 0)); // top right - white - assertEquals(1, bufImage.getRGB(3, 0)); + assertEquals(-1, bufImage.getRGB(3, 0)); // bottom left - black - assertEquals(0, bufImage.getRGB(0, 7)); + assertEquals(-16777216, bufImage.getRGB(0, 7)); // bottom right - white - assertEquals(1, bufImage.getRGB(3, 7)); + assertEquals(-1, bufImage.getRGB(3, 7)); + //other black pixels - just for fun + assertEquals(-16777216, bufImage.getRGB(1, 6)); + assertEquals(-16777216, bufImage.getRGB(2, 5)); + assertEquals(-16777216, bufImage.getRGB(3, 4)); + } + + /** + * Returns a table which contains the RGB colors of the given image. + * @param bufImage + * @return + */ + private List> getBufferedImageAsTable(final BufferedImage bufImage) { + final int height = bufImage.getHeight(); // y + final int width = bufImage.getWidth(); // x + final List> table = new ArrayList>(); + + for (int y = 0; y < height; y++) { + final List row = new ArrayList(); + for(int x = 0; x < width; x++) { + row.add(bufImage.getRGB(x, y)); + } + table.add(row); + } + return table; + } + /** + * Prints the RGB colors of the given image as table with x, y = 0, 0 on top left. + * @param bufImage + */ + private void debugBufferedImageAsTable(final BufferedImage bufImage) { + List> table = getBufferedImageAsTable(bufImage); + for (List row : table) { + System.out.println(row); + } } } From fa263a292533e3c0fa534f8bb5fd4a55e49da498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Tue, 17 Feb 2015 21:36:29 +0100 Subject: [PATCH 15/24] added test for bmp image with positive height --- .../bmp/1/monochrome-positive-height.bmp | Bin 0 -> 1178 bytes .../bmp/1/monochrome-positive-height.xcf | Bin 0 -> 669 bytes ...rome-positive-heightBmp_theGimpOptions.png | Bin 0 -> 22101 bytes src/test/data/specificTests/info.txt | 6 ++- .../bmp/specific/BmpReadHeightTest.java | 50 ++++++++++++++++-- 5 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 src/test/data/specificTests/bmp/1/monochrome-positive-height.bmp create mode 100644 src/test/data/specificTests/bmp/1/monochrome-positive-height.xcf create mode 100644 src/test/data/specificTests/bmp/1/monochrome-positive-heightBmp_theGimpOptions.png diff --git a/src/test/data/specificTests/bmp/1/monochrome-positive-height.bmp b/src/test/data/specificTests/bmp/1/monochrome-positive-height.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d1bfd0162cb4000a4b040e7500a675c511e23786 GIT binary patch literal 1178 zcmb7)XEYEB7=|C4jEXcUw5VvBr4khy5(-5-TOwsO6qTk*TT@hutR@W_lv!pEFLU0|pF0 zNl6K1Wo1-UR2VpLAcF=CV({R>3>h+np+kqFs;Y{bni|7~4P*H5;fxqD0(EtDG&D3A zIdUYUMvY?h=+TTBGlsEa$1-l*I5agi(bCdFTU#3)9UXLabOqehMeSLi< zPMpZ3Nt2j7c`^nD227bU1w%tajEsz!I&~`3rcGn|^ywHI8)IT(f~lz~GiJKOO`BQ>C&YvTeghl%a^la#R^ugT#18&1CEZ4I5|1t?Cgw- ziwmxeYC9dgA5f#hNv1@b>m*?b@}hTel7$A0K>ueev`2 z!{6VZfPetjuV2rG4I9|FaU+{HZ6Yu*kj7*|Ueed-oC=8p^(X``EvKKL-vRAS^75g9i_C=+Ge!A3n^H zBS$!T^eD%U9pm`%bw$l&qg$2@uRgv`uLva+(s&dw$$Cx_hJT=Merc>44y&z?OaKR=&> zf&vN)3n?lpqPV!2l9CdhKYvbXX(=yWyx`@_mz0&2@#@tpUcY|Ln>TMLFE8iq+qYCy zR8U!2NmW%9)z#J1)YS0q-8*V)YpJWNheE9Hzj~_qs>C-1ZfBsB;eLW2g4Ky}3 z^5x4HzJC2mQ&SVo&CRs5wD9fQH@<)W&W|5IXl-q!t*wopKY#M;*Drqm{!M#(I~^Sz NbXmv0tgHHmzW{Y)o=yM& literal 0 HcmV?d00001 diff --git a/src/test/data/specificTests/bmp/1/monochrome-positive-height.xcf b/src/test/data/specificTests/bmp/1/monochrome-positive-height.xcf new file mode 100644 index 0000000000000000000000000000000000000000..2cfb811acaabecb6f7acd0a599b816c3ecfd8cf4 GIT binary patch literal 669 zcmZ{iO-{ow5QUuxL20Rg^0Q*$Wx5DzuTU0M7f4(oO&r%EiL1mF?Sdm9aT0FFI?PLL zCdkwNqniT^?z5^Zb86>$X`Zsj4KOy1mHU9W$*LZz^TDs?wEc z(695n5$5*?(f!xjJBO_}2OGhcBg*c6aP)&&lD^7XZ>sLtU?EOPC~HZ$N-%Ec+%hHh x;BnvMfyWmf4?Vsl#=0)f2(Smje;Ip+g~|eI?9&S0554dM<5By~+SYwR`vW?&Zx8?g literal 0 HcmV?d00001 diff --git a/src/test/data/specificTests/bmp/1/monochrome-positive-heightBmp_theGimpOptions.png b/src/test/data/specificTests/bmp/1/monochrome-positive-heightBmp_theGimpOptions.png new file mode 100644 index 0000000000000000000000000000000000000000..17488db159dd42e3638a568cb8b652348d89a343 GIT binary patch literal 22101 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 -2^24 => black (4 pixels); -1 => white (other pixels) + // top left - white + assertEquals(-1, bufImage.getRGB(0, 0)); + // top right - white + assertEquals(-1, bufImage.getRGB(3, 0)); + // bottom left - black + assertEquals(-16777216, bufImage.getRGB(0, 7)); + // bottom right - white + assertEquals(-1, bufImage.getRGB(3, 7)); + //other black pixels - just for fun + assertEquals(-16777216, bufImage.getRGB(1, 6)); + assertEquals(-16777216, bufImage.getRGB(2, 5)); + assertEquals(-16777216, bufImage.getRGB(3, 4)); + } + + /** + * Get a buffered image for a bmp with positive height. + * Expected: The test image has white pixels in each corner except bottom left (there is a black one). + * This test is to prove that changes to enable reading bmp images with negative height doesn't break + * the ability to read bmp images with positive height. + * @throws ImageReadException + * @throws IOException + */ + @Test + public void testBufferedImagePositiveHeight() throws Exception { + // set to true to print image data to STDOUT + final boolean debugMode = false; + final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-positive-height.bmp"); + final BufferedImage bufImage = Imaging.getBufferedImage(imageFile); + + if (debugMode) debugBufferedImageAsTable(bufImage, "positive height"); assertEquals(8, bufImage.getHeight()); assertEquals(4, bufImage.getWidth()); // the image is monochrome and has 4 black pixels, the remaning pixel are white @@ -134,10 +171,13 @@ private List> getBufferedImageAsTable(final BufferedImage bufImage * Prints the RGB colors of the given image as table with x, y = 0, 0 on top left. * @param bufImage */ - private void debugBufferedImageAsTable(final BufferedImage bufImage) { + private void debugBufferedImageAsTable(final BufferedImage bufImage, final String comment) { + System.out.println(); + System.out.println(comment); List> table = getBufferedImageAsTable(bufImage); for (List row : table) { System.out.println(row); } + System.out.println(); } } From 1e735e391ec19aa6c61c0926d10dcdffb92c95b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Wed, 18 Feb 2015 05:39:35 +0100 Subject: [PATCH 16/24] added test to image info for bmp image with positive height --- .../bmp/specific/BmpReadHeightTest.java | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java index b929f2eb4f..06b999c4d6 100644 --- a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java @@ -40,25 +40,47 @@ import org.junit.Test; /** - * This test class contains some specific tests i.e. reading an image with negative height. + * This test class contains tests specific for reading an image with + * negative and positive height. */ public class BmpReadHeightTest extends BmpBaseTest { /** * Get image info for a bmp with negative height. - * Expected result: Even if the height of bitmap a negative number all information about - * the size of the image shall be positive. The original negative height shall be used only - * to get the image data. + * Expected result: Even if the height of bitmap a negative number all + * information about the size of the image are positive numbers. * @throws ImageReadException * @throws IOException */ @Test public void testImageInfoNegativeHeight() throws ImageReadException, IOException { + // set to true to print image data to STDOUT + final boolean debugMode = false; final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-negative-height.bmp"); - final Map params = new HashMap(); - params.put(ImagingConstants.PARAM_KEY_VERBOSE, false); + if (debugMode) params.put(ImagingConstants.PARAM_KEY_VERBOSE, true); + final ImageInfo imageInfo = Imaging.getImageInfo(imageFile, params); + assertNotNull(imageInfo); + assertEquals(8, imageInfo.getHeight()); + assertEquals(72, imageInfo.getPhysicalHeightDpi()); + assertEquals(0.11111111f, imageInfo.getPhysicalHeightInch(), 0.1f); + } + + /** + * Get image info for a bmp with positive height. + * Expected result: All information about the size of the image are positive numbers. + * @throws ImageReadException + * @throws IOException + */ + @Test + public void testImageInfoPositiveHeight() throws ImageReadException, IOException { + // set to true to print image data to STDOUT + final boolean debugMode = false; + final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-positive-height.bmp"); + final Map params = new HashMap(); + if (debugMode) params.put(ImagingConstants.PARAM_KEY_VERBOSE, true); final ImageInfo imageInfo = Imaging.getImageInfo(imageFile, params); + assertNotNull(imageInfo); assertEquals(8, imageInfo.getHeight()); assertEquals(72, imageInfo.getPhysicalHeightDpi()); From aece262366e01c98f936fbc9c03c1e7811da62b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Wed, 18 Feb 2015 05:55:55 +0100 Subject: [PATCH 17/24] added info from bitmap header info to debug output --- .../org/apache/commons/imaging/formats/bmp/BmpImageParser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index b1a8b4b045..59be475fed 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -403,6 +403,7 @@ private ImageContents readImageContents(final InputStream is, // this.debugNumber("ExtraBitsPerPixel", ExtraBitsPerPixel, 4); debugNumber("bhi.Width", bhi.width, 4); debugNumber("bhi.Height", bhi.height, 4); + debugNumber("bhi.isBottomUpBitmap: " + bhi.isBottomUpBitmap, 0, 0); debugNumber("ImageLineLength", imageLineLength, 4); // this.debugNumber("imageDataSize", imageDataSize, 4); debugNumber("PixelCount", pixelCount, 4); From 7dbded44d9fdb3a91e12aba6fe9240b77f454e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Wed, 18 Feb 2015 21:22:46 +0100 Subject: [PATCH 18/24] doc --- .../org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java index 996bf86dbf..4b91caa092 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java @@ -37,8 +37,8 @@ class BmpHeaderInfo { public final int height; /** * According to specification the height can be negative. - *
Positive height: Bitmap is stored bottom-up (0, 0 is in the bottom left corner) - *
Negative height: Bitmap is stored top-down (0, 0 is in the top left corner) + *
Positive height: Bitmap is stored bottom-up (0, 0 is in the bottom left corner), then this field is true + *
Negative height: Bitmap is stored top-down (0, 0 is in the top left corner), then this field is false */ public final boolean isBottomUpBitmap; public final int planes; From 70f24db8088b5eb6683bd4ea577d89f61a40864b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Wed, 18 Feb 2015 22:39:28 +0100 Subject: [PATCH 19/24] fixed IMAGING-162 for non-RLE-encoded bitmaps --- .../commons/imaging/common/ImageBuilder.java | 33 ++++++++++++++++++- .../imaging/formats/bmp/BmpImageParser.java | 7 ++-- .../imaging/formats/bmp/PixelParserRle.java | 8 ++++- .../formats/bmp/PixelParserSimple.java | 29 ++++++++++++---- .../bmp/specific/BmpReadHeightTest.java | 15 --------- 5 files changed, 64 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/common/ImageBuilder.java b/src/main/java/org/apache/commons/imaging/common/ImageBuilder.java index fe060306ed..a3b8e5b3bf 100644 --- a/src/main/java/org/apache/commons/imaging/common/ImageBuilder.java +++ b/src/main/java/org/apache/commons/imaging/common/ImageBuilder.java @@ -58,6 +58,7 @@ public class ImageBuilder { private final int width; private final int height; private final boolean hasAlpha; + private final boolean readBottomUp; /** * Construct an ImageBuilder instance @@ -68,6 +69,26 @@ public class ImageBuilder { * requirements for the ImageBuilder or resulting BufferedImage. */ public ImageBuilder(final int width, final int height, final boolean hasAlpha) { + this(true, width, height, hasAlpha); + } + + /** + * Construct an ImageBuilder instance. + *

+ * Usually image data is stored bottom-up, that means that the last row in the + * image data is the first row of pixels in the image as displayed. + * Sometimes image data are stored top-down: The first row in the image data + * is also the first row of pixels in the image as displayed. + * With this constructor you can define the direction. + * @param readBottomUp {@code true}: the image data are stored bottom-up, + * {@code false} the image data are stored top-down + * @param width the width of the image to be built + * @param height the height of the image to be built + * @param hasAlpha indicates whether the image has an alpha channel + * (the selection of alpha channel does not change the memory + * requirements for the ImageBuilder or resulting BufferedImage. + */ + public ImageBuilder(final boolean readBottomUp, final int width, final int height, final boolean hasAlpha) { if (width <= 0) { throw new RasterFormatException("zero or negative width value"); } @@ -79,8 +100,18 @@ public ImageBuilder(final int width, final int height, final boolean hasAlpha) { this.width = width; this.height = height; this.hasAlpha = hasAlpha; + this.readBottomUp = readBottomUp; } - + + /** + * {@code true}: the image data are stored bottom-up, + * {@code false} the image data are stored top-down + * @return + */ + public boolean readBottomUp() { + return this.readBottomUp; + } + /** * Get the width of the ImageBuilder pixel field * @return a positive integer diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index 59be475fed..cf546cd105 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -717,14 +717,11 @@ public BufferedImage getBufferedImage(final InputStream inputStream, Map top + // when displayed. + // See PixelParserSimple.processImage() where we fixed this for non-RLE-encoded + // bitmaps. @Override public void processImage(final ImageBuilder imageBuilder) throws ImageReadException, IOException { diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserSimple.java b/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserSimple.java index b2171d4813..a6b8857be1 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserSimple.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserSimple.java @@ -13,6 +13,8 @@ * 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. + * + * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; @@ -32,14 +34,29 @@ public PixelParserSimple(final BmpHeaderInfo bhi, final byte[] colorTable, final @Override public void processImage(final ImageBuilder imageBuilder) throws ImageReadException, IOException { - for (int y = bhi.height - 1; y >= 0; y--) { - for (int x = 0; x < bhi.width; x++) { - final int rgb = getNextRGB(); + // image data are stored bottom-up + if (imageBuilder.readBottomUp() == true) { + for (int y = bhi.height - 1; y >= 0; y--) { + for (int x = 0; x < bhi.width; x++) { + final int rgb = getNextRGB(); + + imageBuilder.setRGB(x, y, rgb); + // db.setElem(y * bhi.width + x, rgb); + } + newline(); + } + } + // image data are stored top-down + else { + for (int y = 0; y < bhi.height; y++) { + for (int x = 0; x < bhi.width; x++) { + final int rgb = getNextRGB(); - imageBuilder.setRGB(x, y, rgb); - // db.setElem(y * bhi.width + x, rgb); + imageBuilder.setRGB(x, y, rgb); + // db.setElem(y * bhi.width + x, rgb); + } + newline(); } - newline(); } } } diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java index 06b999c4d6..862a4de2f2 100644 --- a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java @@ -87,27 +87,12 @@ public void testImageInfoPositiveHeight() throws ImageReadException, IOException assertEquals(0.11111111f, imageInfo.getPhysicalHeightInch(), 0.1f); } - /** - * Get a buffered image for a bmp with negative height. - * - * THIS TESTS THE HOTFIX EMPLOYED UNTIL READING BITMAPS WITH NEGATIVE HEIGTH IS IMPLEMENTED. - * - * @throws ImageReadException - * @throws IOException - */ - @Test(expected=ImageReadException.class) - public void testBufferedImageNegativeHeightException() throws Exception { - final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-negative-height.bmp"); - Imaging.getBufferedImage(imageFile); - } - /** * Get a buffered image for a bmp with negative height. * Expected: The test image has white pixels in each corner except bottom left (there is a black one). * @throws ImageReadException * @throws IOException */ - @Ignore(value = "Reading bitmaps with negative height has to be implemented before one can execute this test successfully.") @Test public void testBufferedImageNegativeHeight() throws Exception { // set to true to print image data to STDOUT From 56f98b7eecc5f6b0f5ed4d8ae42552571401d8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Sat, 21 Feb 2015 17:02:06 +0100 Subject: [PATCH 20/24] checked that my fix IMAGING-162 doesn't break anything for RLE-compressed bitmaps with positive height --- ...chrome-positive-height_TheGimpOptions.png} | Bin .../bmp/2/monochrome-positive-height-rle.bmp | Bin 0 -> 1190 bytes ...ome-positive-height-rle_TheGimpOptions.png | Bin 0 -> 22358 bytes .../bmp/2/monochrome-positive-height.xcf | Bin 0 -> 669 bytes src/test/data/specificTests/info.txt | 10 +- .../bmp/specific/BmpReadHeightRleTest.java | 136 ++++++++++++++++++ 6 files changed, 144 insertions(+), 2 deletions(-) rename src/test/data/specificTests/bmp/1/{monochrome-positive-heightBmp_theGimpOptions.png => monochrome-positive-height_TheGimpOptions.png} (100%) create mode 100644 src/test/data/specificTests/bmp/2/monochrome-positive-height-rle.bmp create mode 100644 src/test/data/specificTests/bmp/2/monochrome-positive-height-rle_TheGimpOptions.png create mode 100644 src/test/data/specificTests/bmp/2/monochrome-positive-height.xcf create mode 100644 src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java diff --git a/src/test/data/specificTests/bmp/1/monochrome-positive-heightBmp_theGimpOptions.png b/src/test/data/specificTests/bmp/1/monochrome-positive-height_TheGimpOptions.png similarity index 100% rename from src/test/data/specificTests/bmp/1/monochrome-positive-heightBmp_theGimpOptions.png rename to src/test/data/specificTests/bmp/1/monochrome-positive-height_TheGimpOptions.png diff --git a/src/test/data/specificTests/bmp/2/monochrome-positive-height-rle.bmp b/src/test/data/specificTests/bmp/2/monochrome-positive-height-rle.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ad2e65acab8d1d0adc7b533ae3e2adf15226cc37 GIT binary patch literal 1190 zcmb7^XIRJ!7{z}LNhu{|r)3vKMzo8Fj1tO-wnQ{(84Z;YLMWrm$j(g3N;D|5tO_j} zRw|Oe?w9-Fe!1`SocEmf_q?BvsgC}Lt_h>MHUp+g5GBqZqAu_Ka_l630S2`MQlq@|_l+_^I{GBU`@ z%F?Av7v$vRke8RIYuBzQC@9daTQ?LH6;V=BqI>u5^ytxpo;`cgt5+|2_wG%fK7Huh zw=c@d%Jl2k4;2*^R8>_`Q&U4-T^$V#4f^-*&wv2~7&vesg9Z&^@ZiA=88U>SLx-ZN zsfm`B7Q==OWBBmlXlrYuqoc!!5hEBmawNLCx{Mk%iqWG-GiJ;f#*Q6}o}M1##*JhA z`0?oL>tkSGfT5uwMn*;$8yjO{VuGouDQ0G7n46n3VZsC^PMnB^g$0u)O=9xo$yi!i zGG)pXrcRxTm6a9KrcGn|^y$o)F@u>iXJTz_jg5^Bvu4f0*4CEUvu87B&K%~>or|5F z9rpJ2%$qll`Sa(qV8H?wE?kI%g9D2eEn@NF#W*@T;^gFnv$HcUE-tvby5i>MhP%5v zOO`Cb!^4B6OPAv5>B+KX%UHgAIbL2~tXQ#vl`B``?d^?^j}N}SzWDk1;qUKHKtKSi zR;^<7>eU1W1`-q$L~w90At51zhK90c%^KFOUCX+4>sY^jJz-&CgolR{5fMRTWF#9l zY#=Hsis__=FM!`vW3{#ShjB6%C>FW*uH%`adC0%*s+71J9n~c z*Dm7YCz=GU%t$hD_6LB^(xn{T_Zg`o$J@HlaY}@W@aWgZrmU%D~p>qZ*uF_ zEpFew&7C`UxO?|5+1c6LyLXSAoE+}ozt4jQ56I2UB`+_J{QP_h3JQ4m@F9;LJ)*F% zkfNd@9zTA}lP6Dj`t&K!o;~CF^XI&H@q*&wVoFL%c=_@ruU@_4_3PKXdGm(1Z{Jc{ zT1r`28Rg~WynFYK_wV2H;ll?iDk`X~tfZ={it6fWYHDiu`0*p3K7FFLwwAiOI_m4| zX=rHR^XJce`SOLYU%&G0+c&;{|4w6LBR_uppsA^e=H_NvT3Yz|^C!Q4{i3zCmEXUA d)7I7|REb!dPzmB~!qx6VKwy76M}Ys9$R9Voj#K~u literal 0 HcmV?d00001 diff --git a/src/test/data/specificTests/bmp/2/monochrome-positive-height-rle_TheGimpOptions.png b/src/test/data/specificTests/bmp/2/monochrome-positive-height-rle_TheGimpOptions.png new file mode 100644 index 0000000000000000000000000000000000000000..84ede0118a14a9932eb28a0d08a5d0c3b0ecc96d GIT binary patch literal 22358 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 literal 0 HcmV?d00001 diff --git a/src/test/data/specificTests/info.txt b/src/test/data/specificTests/info.txt index 9a816d9487..04eb5c5f7c 100644 --- a/src/test/data/specificTests/info.txt +++ b/src/test/data/specificTests/info.txt @@ -26,7 +26,13 @@ bmp/1/monochrome-negative-height.bmp It was attached there by Myroslav Golub. bmp/1/monochrome-positive-height.bmp - Monochrome 4x8 bitmap with negative height value. + Monochrome 4x8 bitmap with positive height value. monochrome-positive-height.xfc is the original file created with "The Gimp 2.8.10". monochrome-positive-height.bmp itself was created by exporting the xfc image to bmp - using the options shown in monochrome-positive-heightBmp_theGimpOptions.png. + using the options shown in monochrome-positive-height_TheGimpOptions.png. + +bmp/2/monochrome-positive-height-rle.bmp + Monochrome 4x8 bitmap with positive height value. + monochrome-positive-height-rle.xfc is the original file created with "The Gimp 2.8.10". + monochrome-positive-height-rle.bmp itself was created by exporting the xfc image to bmp + using the options shown in monochrome-positive-height-rle_TheGimpOptions.png. diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java new file mode 100644 index 0000000000..339b711798 --- /dev/null +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + * Added 2015 by Michael Gross, mgmechanics@mgmechanics.de + * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de + */ + +package org.apache.commons.imaging.formats.bmp.specific; + +import org.apache.commons.imaging.formats.bmp.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertEquals; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.imaging.ImageInfo; +import org.apache.commons.imaging.ImageReadException; +import org.apache.commons.imaging.Imaging; +import org.apache.commons.imaging.ImagingConstants; +import org.junit.Ignore; +import org.junit.Test; + +/** + * This test class contains tests specific for reading an image with + * negative and positive height. + * These are tests for image files where the image data are RLE-compressed. + */ +public class BmpReadHeightRleTest extends BmpBaseTest { + /** + * Get image info for a bmp with positive height. + * Expected result: All information about the size of the image are positive numbers. + * @throws ImageReadException + * @throws IOException + */ + @Test + public void testImageInfoPositiveHeight() throws ImageReadException, IOException { + // set to true to print image data to STDOUT + final boolean debugMode = false; + final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/2/monochrome-positive-height-rle.bmp"); + final Map params = new HashMap(); + if (debugMode) params.put(ImagingConstants.PARAM_KEY_VERBOSE, true); + final ImageInfo imageInfo = Imaging.getImageInfo(imageFile, params); + + assertNotNull(imageInfo); + assertEquals(8, imageInfo.getHeight()); + assertEquals(72, imageInfo.getPhysicalHeightDpi()); + assertEquals(0.11111111f, imageInfo.getPhysicalHeightInch(), 0.1f); + } + + /** + * Get a buffered image for a bmp with positive height. + * Expected: The test image has white pixels in each corner except bottom left (there is a black one). + * This test is to prove that changes to enable reading bmp images with negative height doesn't break + * the ability to read bmp images with positive height. + * @throws ImageReadException + * @throws IOException + */ + @Test + public void testBufferedImagePositiveHeight() throws Exception { + // set to true to print image data to STDOUT + final boolean debugMode = false; + final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/2/monochrome-positive-height-rle.bmp"); + final BufferedImage bufImage = Imaging.getBufferedImage(imageFile); + + if (debugMode) debugBufferedImageAsTable(bufImage, "positive height rle"); + assertEquals(8, bufImage.getHeight()); + assertEquals(4, bufImage.getWidth()); + // the image is monochrome and has 4 black pixels, the remaning pixel are white + // the black pixels a placed such that we can make sure the picture is read as expected + // -16777216 => -2^24 => black (4 pixels); -1 => white (other pixels) + // top left - white + assertEquals(-1, bufImage.getRGB(0, 0)); + // top right - white + assertEquals(-1, bufImage.getRGB(3, 0)); + // bottom left - black + assertEquals(-16777216, bufImage.getRGB(0, 7)); + // bottom right - white + assertEquals(-1, bufImage.getRGB(3, 7)); + //other black pixels - just for fun + assertEquals(-16777216, bufImage.getRGB(1, 6)); + assertEquals(-16777216, bufImage.getRGB(2, 5)); + assertEquals(-16777216, bufImage.getRGB(3, 4)); + } + + /** + * Returns a table which contains the RGB colors of the given image. + * @param bufImage + * @return + */ + private List> getBufferedImageAsTable(final BufferedImage bufImage) { + final int height = bufImage.getHeight(); // y + final int width = bufImage.getWidth(); // x + final List> table = new ArrayList>(); + + for (int y = 0; y < height; y++) { + final List row = new ArrayList(); + for(int x = 0; x < width; x++) { + row.add(bufImage.getRGB(x, y)); + } + table.add(row); + } + return table; + } + /** + * Prints the RGB colors of the given image as table with x, y = 0, 0 on top left. + * @param bufImage + */ + private void debugBufferedImageAsTable(final BufferedImage bufImage, final String comment) { + System.out.println(); + System.out.println(comment); + List> table = getBufferedImageAsTable(bufImage); + for (List row : table) { + System.out.println(row); + } + System.out.println(); + } +} From 5610b5f8cdffb6a9552ead04da3ac5e81d6f78da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Sat, 21 Feb 2015 17:16:27 +0100 Subject: [PATCH 21/24] moved common methods to utility class --- .../bmp/specific/BmpReadHeightRleTest.java | 39 +----------- .../bmp/specific/BmpReadHeightTest.java | 41 +----------- .../imaging/test/util/BufferedImageTools.java | 62 +++++++++++++++++++ 3 files changed, 67 insertions(+), 75 deletions(-) create mode 100644 src/test/java/org/apache/commons/imaging/test/util/BufferedImageTools.java diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java index 339b711798..f9ecab93fc 100644 --- a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java @@ -27,16 +27,14 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.apache.commons.imaging.ImageInfo; import org.apache.commons.imaging.ImageReadException; import org.apache.commons.imaging.Imaging; import org.apache.commons.imaging.ImagingConstants; -import org.junit.Ignore; +import org.apache.commons.imaging.test.util.BufferedImageTools; import org.junit.Test; /** @@ -81,7 +79,7 @@ public void testBufferedImagePositiveHeight() throws Exception { final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/2/monochrome-positive-height-rle.bmp"); final BufferedImage bufImage = Imaging.getBufferedImage(imageFile); - if (debugMode) debugBufferedImageAsTable(bufImage, "positive height rle"); + if (debugMode) BufferedImageTools.debugBufferedImageAsTable(bufImage, "positive height rle"); assertEquals(8, bufImage.getHeight()); assertEquals(4, bufImage.getWidth()); // the image is monochrome and has 4 black pixels, the remaning pixel are white @@ -100,37 +98,4 @@ public void testBufferedImagePositiveHeight() throws Exception { assertEquals(-16777216, bufImage.getRGB(2, 5)); assertEquals(-16777216, bufImage.getRGB(3, 4)); } - - /** - * Returns a table which contains the RGB colors of the given image. - * @param bufImage - * @return - */ - private List> getBufferedImageAsTable(final BufferedImage bufImage) { - final int height = bufImage.getHeight(); // y - final int width = bufImage.getWidth(); // x - final List> table = new ArrayList>(); - - for (int y = 0; y < height; y++) { - final List row = new ArrayList(); - for(int x = 0; x < width; x++) { - row.add(bufImage.getRGB(x, y)); - } - table.add(row); - } - return table; - } - /** - * Prints the RGB colors of the given image as table with x, y = 0, 0 on top left. - * @param bufImage - */ - private void debugBufferedImageAsTable(final BufferedImage bufImage, final String comment) { - System.out.println(); - System.out.println(comment); - List> table = getBufferedImageAsTable(bufImage); - for (List row : table) { - System.out.println(row); - } - System.out.println(); - } } diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java index 862a4de2f2..f5959a3ee3 100644 --- a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java @@ -27,16 +27,14 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.apache.commons.imaging.ImageInfo; import org.apache.commons.imaging.ImageReadException; import org.apache.commons.imaging.Imaging; import org.apache.commons.imaging.ImagingConstants; -import org.junit.Ignore; +import org.apache.commons.imaging.test.util.BufferedImageTools; import org.junit.Test; /** @@ -100,7 +98,7 @@ public void testBufferedImageNegativeHeight() throws Exception { final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-negative-height.bmp"); final BufferedImage bufImage = Imaging.getBufferedImage(imageFile); - if (debugMode) debugBufferedImageAsTable(bufImage, "negative height"); + if (debugMode) BufferedImageTools.debugBufferedImageAsTable(bufImage, "negative height"); assertEquals(8, bufImage.getHeight()); assertEquals(4, bufImage.getWidth()); // the image is monochrome and has 4 black pixels, the remaning pixel are white @@ -135,7 +133,7 @@ public void testBufferedImagePositiveHeight() throws Exception { final File imageFile = new File(TEST_SPECIFIC_FOLDER, "bmp/1/monochrome-positive-height.bmp"); final BufferedImage bufImage = Imaging.getBufferedImage(imageFile); - if (debugMode) debugBufferedImageAsTable(bufImage, "positive height"); + if (debugMode) BufferedImageTools.debugBufferedImageAsTable(bufImage, "positive height"); assertEquals(8, bufImage.getHeight()); assertEquals(4, bufImage.getWidth()); // the image is monochrome and has 4 black pixels, the remaning pixel are white @@ -154,37 +152,4 @@ public void testBufferedImagePositiveHeight() throws Exception { assertEquals(-16777216, bufImage.getRGB(2, 5)); assertEquals(-16777216, bufImage.getRGB(3, 4)); } - - /** - * Returns a table which contains the RGB colors of the given image. - * @param bufImage - * @return - */ - private List> getBufferedImageAsTable(final BufferedImage bufImage) { - final int height = bufImage.getHeight(); // y - final int width = bufImage.getWidth(); // x - final List> table = new ArrayList>(); - - for (int y = 0; y < height; y++) { - final List row = new ArrayList(); - for(int x = 0; x < width; x++) { - row.add(bufImage.getRGB(x, y)); - } - table.add(row); - } - return table; - } - /** - * Prints the RGB colors of the given image as table with x, y = 0, 0 on top left. - * @param bufImage - */ - private void debugBufferedImageAsTable(final BufferedImage bufImage, final String comment) { - System.out.println(); - System.out.println(comment); - List> table = getBufferedImageAsTable(bufImage); - for (List row : table) { - System.out.println(row); - } - System.out.println(); - } } diff --git a/src/test/java/org/apache/commons/imaging/test/util/BufferedImageTools.java b/src/test/java/org/apache/commons/imaging/test/util/BufferedImageTools.java new file mode 100644 index 0000000000..3085faa108 --- /dev/null +++ b/src/test/java/org/apache/commons/imaging/test/util/BufferedImageTools.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + * Added 2015 by Michael Gross, mgmechanics@mgmechanics.de + */ + +package org.apache.commons.imaging.test.util; + +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; + +/** + * Tools for tests related to BufferedImages. + */ +public final class BufferedImageTools { + /** + * Returns a table which contains the RGB colors of the given image. + * @param bufImage + * @return + */ + public static List> getBufferedImageAsTable(final BufferedImage bufImage) { + final int height = bufImage.getHeight(); // y + final int width = bufImage.getWidth(); // x + final List> table = new ArrayList>(); + + for (int y = 0; y < height; y++) { + final List row = new ArrayList(); + for(int x = 0; x < width; x++) { + row.add(bufImage.getRGB(x, y)); + } + table.add(row); + } + return table; + } + /** + * Prints the RGB colors of the given image as table with x, y = 0, 0 on top left. + * @param bufImage + */ + public static void debugBufferedImageAsTable(final BufferedImage bufImage, final String comment) { + System.out.println(); + System.out.println(comment); + List> table = getBufferedImageAsTable(bufImage); + for (List row : table) { + System.out.println(row); + } + System.out.println(); + } +} From 29b585ca17b19103b6ea8303a29aa31a98d21b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Mon, 23 Feb 2015 21:23:53 +0100 Subject: [PATCH 22/24] doc --- .../commons/imaging/formats/bmp/BmpHeaderInfo.java | 2 -- .../commons/imaging/formats/bmp/BmpImageParser.java | 2 -- .../commons/imaging/formats/bmp/PixelParserSimple.java | 2 -- src/test/data/images/info.txt | 9 --------- src/test/data/specificTests/info.txt | 2 -- .../org/apache/commons/imaging/ImagingTestConstants.java | 2 -- .../formats/bmp/specific/BmpReadHeightRleTest.java | 3 --- .../imaging/formats/bmp/specific/BmpReadHeightTest.java | 3 --- .../commons/imaging/test/util/BufferedImageTools.java | 2 -- 9 files changed, 27 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java index 4b91caa092..a95e32c712 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpHeaderInfo.java @@ -13,8 +13,6 @@ * 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. - * - * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index cf546cd105..76fbb9d97c 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -13,8 +13,6 @@ * 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. - * - * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserSimple.java b/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserSimple.java index a6b8857be1..f2a85f9eb8 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserSimple.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserSimple.java @@ -13,8 +13,6 @@ * 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. - * - * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp; diff --git a/src/test/data/images/info.txt b/src/test/data/images/info.txt index 61223be82f..e878404b56 100644 --- a/src/test/data/images/info.txt +++ b/src/test/data/images/info.txt @@ -13,15 +13,6 @@ 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. -Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de - -Adding any image file to this folder means that this file will used immediately -in various tests. These tests use certain functions of this library for all -image files in this folder. -For example, consider an bmp image file which shall bring up an exception. -Adding this file here will cause some existing tests to fail while the same tests -pass for all other bmp images in this folder. - bmp/1/Oregon Scientific DS6639 - DSC_0307 - small.bmp Contributed by Charles Matthew Chen. diff --git a/src/test/data/specificTests/info.txt b/src/test/data/specificTests/info.txt index 04eb5c5f7c..a9920919f1 100644 --- a/src/test/data/specificTests/info.txt +++ b/src/test/data/specificTests/info.txt @@ -13,8 +13,6 @@ 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. -Added 2015 by Michael Gross, mgmechanics@mgmechanics.de - Adding a file to this folder has no effect to any existing test. If you want to use a just added file you need to add test which uses this file. diff --git a/src/test/java/org/apache/commons/imaging/ImagingTestConstants.java b/src/test/java/org/apache/commons/imaging/ImagingTestConstants.java index c46a119c8e..943b1fd59a 100644 --- a/src/test/java/org/apache/commons/imaging/ImagingTestConstants.java +++ b/src/test/java/org/apache/commons/imaging/ImagingTestConstants.java @@ -13,8 +13,6 @@ * 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. - * - * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging; diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java index f9ecab93fc..285960742b 100644 --- a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightRleTest.java @@ -13,9 +13,6 @@ * 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. - * - * Added 2015 by Michael Gross, mgmechanics@mgmechanics.de - * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp.specific; diff --git a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java index f5959a3ee3..6becbf692b 100644 --- a/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/bmp/specific/BmpReadHeightTest.java @@ -13,9 +13,6 @@ * 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. - * - * Added 2015 by Michael Gross, mgmechanics@mgmechanics.de - * Changed 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.formats.bmp.specific; diff --git a/src/test/java/org/apache/commons/imaging/test/util/BufferedImageTools.java b/src/test/java/org/apache/commons/imaging/test/util/BufferedImageTools.java index 3085faa108..7a11d03e2e 100644 --- a/src/test/java/org/apache/commons/imaging/test/util/BufferedImageTools.java +++ b/src/test/java/org/apache/commons/imaging/test/util/BufferedImageTools.java @@ -13,8 +13,6 @@ * 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. - * - * Added 2015 by Michael Gross, mgmechanics@mgmechanics.de */ package org.apache.commons.imaging.test.util; From dd08b0c1b2fcfac65fe307a0b19fec40ec8144c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Mon, 23 Feb 2015 21:52:05 +0100 Subject: [PATCH 23/24] found much simpler solution - restored ImageBuilder to trunk --- .../commons/imaging/common/ImageBuilder.java | 31 ------------------- .../imaging/formats/bmp/BmpImageParser.java | 2 +- .../formats/bmp/PixelParserSimple.java | 2 +- 3 files changed, 2 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/common/ImageBuilder.java b/src/main/java/org/apache/commons/imaging/common/ImageBuilder.java index a3b8e5b3bf..54f77e332e 100644 --- a/src/main/java/org/apache/commons/imaging/common/ImageBuilder.java +++ b/src/main/java/org/apache/commons/imaging/common/ImageBuilder.java @@ -58,7 +58,6 @@ public class ImageBuilder { private final int width; private final int height; private final boolean hasAlpha; - private final boolean readBottomUp; /** * Construct an ImageBuilder instance @@ -69,26 +68,6 @@ public class ImageBuilder { * requirements for the ImageBuilder or resulting BufferedImage. */ public ImageBuilder(final int width, final int height, final boolean hasAlpha) { - this(true, width, height, hasAlpha); - } - - /** - * Construct an ImageBuilder instance. - *

- * Usually image data is stored bottom-up, that means that the last row in the - * image data is the first row of pixels in the image as displayed. - * Sometimes image data are stored top-down: The first row in the image data - * is also the first row of pixels in the image as displayed. - * With this constructor you can define the direction. - * @param readBottomUp {@code true}: the image data are stored bottom-up, - * {@code false} the image data are stored top-down - * @param width the width of the image to be built - * @param height the height of the image to be built - * @param hasAlpha indicates whether the image has an alpha channel - * (the selection of alpha channel does not change the memory - * requirements for the ImageBuilder or resulting BufferedImage. - */ - public ImageBuilder(final boolean readBottomUp, final int width, final int height, final boolean hasAlpha) { if (width <= 0) { throw new RasterFormatException("zero or negative width value"); } @@ -100,16 +79,6 @@ public ImageBuilder(final boolean readBottomUp, final int width, final int heigh this.width = width; this.height = height; this.hasAlpha = hasAlpha; - this.readBottomUp = readBottomUp; - } - - /** - * {@code true}: the image data are stored bottom-up, - * {@code false} the image data are stored top-down - * @return - */ - public boolean readBottomUp() { - return this.readBottomUp; } /** diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java index 76fbb9d97c..e29eef06a0 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java @@ -719,7 +719,7 @@ public BufferedImage getBufferedImage(final InputStream inputStream, Map= 0; y--) { for (int x = 0; x < bhi.width; x++) { final int rgb = getNextRGB(); From 5472f1960f13768b7a773a2f075c48cffcc71bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9F?= Date: Tue, 24 Mar 2015 21:43:06 +0100 Subject: [PATCH 24/24] removed wrong comment --- .../apache/commons/imaging/formats/bmp/PixelParserRle.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserRle.java b/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserRle.java index 7c2e9e5c88..3687b8cc7c 100644 --- a/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserRle.java +++ b/src/main/java/org/apache/commons/imaging/formats/bmp/PixelParserRle.java @@ -85,12 +85,6 @@ private int processByteOfData(final int[] rgbs, final int repeat, int x, final i return pixelsWritten; } - // TODO: Reading RLE-encoded bitmaps where a negative height is given in the - // bitmap header won't work as expected. You'll get always a positive height - // from class BitmapHeaderInfo but the image data will appear bottom -> top - // when displayed. - // See PixelParserSimple.processImage() where we fixed this for non-RLE-encoded - // bitmaps. @Override public void processImage(final ImageBuilder imageBuilder) throws ImageReadException, IOException {