1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.iio; 27 28 import com.sun.javafx.iio.bmp.BMPImageLoaderFactory; 29 import com.sun.prism.Image; 30 import java.awt.image.BufferedImage; 31 import java.awt.image.DataBuffer; 32 import java.awt.image.IndexColorModel; 33 import java.io.ByteArrayInputStream; 34 import java.io.ByteArrayOutputStream; 35 import java.io.File; 36 import java.io.FileInputStream; 37 import java.io.IOException; 38 import java.io.InputStream; 39 import javax.imageio.ImageIO; 40 import javax.imageio.stream.MemoryCacheImageInputStream; 41 import static org.junit.Assert.*; 42 import org.junit.Test; 43 44 public class BMPImageLoaderTest { 45 // if true, the test will write BMP files generated by JDK to the current directory 46 static final boolean writeFiles = false; 47 static final int testWidth = 509, testHeight = 157; 48 49 ByteArrayInputStream constructStream(int[] bytes) { 50 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 51 for (int b : bytes) { 52 baos.write(b); 53 } 54 return new ByteArrayInputStream(baos.toByteArray()); 55 } 56 57 int getByte(int dword, int shift) { 58 return (dword >> shift) & 0xff; 59 } 60 61 boolean compareByte(int p1, int p2, int shift, int tolerance) { 62 return Math.abs(getByte(p1, shift) - getByte(p2, shift)) <= tolerance; 63 } 64 65 boolean compareRGB(int p1, int p2, int tolerance) { 66 return compareByte(p1, p2, 24, tolerance) && 67 compareByte(p1, p2, 16, tolerance) && 68 compareByte(p1, p2, 8, tolerance); 69 } 70 71 void compare(Image img, BufferedImage bImg) { 72 assertNotNull(img); 73 assertNotNull(bImg); 74 int w = bImg.getWidth(), h = bImg.getHeight(); 75 assertEquals("Unmatched width", w, img.getWidth()); 76 assertEquals("Unmatched height", h, img.getHeight()); 77 78 for (int y = 0; y < h; y++) { 79 for (int x = 0; x < w; x++) { 80 int p1 = bImg.getRGB(x, y); 81 int p2 = img.getArgb(x, y); 82 if (!compareRGB(p1, p2, 1)) { 83 throw new org.junit.ComparisonFailure( 84 "pixel " + x + ", " + y + " does not match", 85 String.format("0x%08X", p1), String.format("0x%08X", p2) 86 ); 87 } 88 } 89 } 90 } 91 92 Image loadImage(InputStream stream) { 93 ImageLoaderFactory loaderFactory = BMPImageLoaderFactory.getInstance(); 94 ImageLoader loader = null; 95 try { 96 loader = loaderFactory.createImageLoader(stream); 97 } catch (IOException ioEx) { 98 fail("unexpected IOException: " + ioEx); 99 } 100 assertNotNull(loader); 101 102 try { 103 ImageFrame frame = loader.load(0, 0, 0, true, true); 104 return Image.convertImageFrame(frame); 105 } catch (IOException e) { 106 fail("unexpected IOException: " + e); 107 } 108 return null; 109 } 110 111 BufferedImage create4BitImage() { 112 int[] cmap = new int[16]; 113 int i = 0; 114 for (int r = 0; r < 2; r++) { 115 for (int g = 0; g < 2; g++) { 116 for (int b = 0; b < 2; b++) { 117 cmap[i++] = 0xff << 24 | r * 255 << 16 | g * 255 << 8 | b * 255; 118 if ((r | g | b) == 0) { 119 cmap[i++] = 0xffc0c0c0; 120 } else { 121 cmap[i++] = 0xff << 24 | r * 128 << 16 | g * 128 << 8 | b * 128; 122 } 123 } 124 } 125 } 126 IndexColorModel cm = new IndexColorModel(4, 16, cmap, 0, false, -1, DataBuffer.TYPE_BYTE); 127 return new BufferedImage(testWidth, testHeight, BufferedImage.TYPE_BYTE_BINARY, cm); 128 } 129 130 BufferedImage createImage(int type) { 131 return new BufferedImage(testWidth, testHeight, type); 132 } 133 134 void writeBMPImage(BufferedImage bImg, String fileName, String compression) { 135 ImageTestHelper.writeImage(bImg, fileName, "bmp", compression); 136 } 137 138 Image getImage(BufferedImage bImg, String compression) { 139 ByteArrayInputStream stream = 140 ImageTestHelper.writeImageToStream(bImg, "bmp", compression, null); 141 return loadImage(stream); 142 } 143 144 void testImageType(int type, String fileName, String compression) { 145 BufferedImage bImg = createImage(type); 146 testImage(bImg, fileName, compression); 147 } 148 149 void testImageType(int type, String fileName) { 150 BufferedImage bImg = createImage(type); 151 testImage(bImg, fileName, null); 152 } 153 154 void testImage(BufferedImage bImg, String fileName, String compression) { 155 //ImageTestHelper.drawImageHue(bImg); 156 //ImageTestHelper.drawImageAll(bImg); 157 ImageTestHelper.drawImageRandom(bImg); 158 if (writeFiles) { 159 writeBMPImage(bImg, fileName, compression); 160 } 161 Image image = getImage(bImg, compression); 162 compare(image, bImg); 163 } 164 165 @Test 166 public void testRT32213() { 167 final int[] bytes = { 168 0x42, 0x4d, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 169 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x28, 0x00, 170 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 171 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 172 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 175 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 176 0x00, 0x00 177 }; 178 179 ByteArrayInputStream stream = constructStream(bytes); 180 Image image = loadImage(stream); 181 stream.reset(); 182 try { 183 BufferedImage bImg = ImageIO.read(new MemoryCacheImageInputStream(stream)); 184 compare(image, bImg); 185 } catch (IOException e) { 186 fail("unexpected IOException: " + e); 187 } 188 } 189 190 private static class RT15619InputStream extends InputStream { 191 192 private final InputStream delegate; 193 194 public RT15619InputStream(InputStream delegate) { 195 this.delegate = delegate; 196 } 197 198 @Override 199 public int read() throws IOException { 200 return delegate.read(); 201 } 202 203 // read by 128 bytes chunks 204 @Override 205 public int read(byte[] b, int off, int len) throws IOException { 206 return delegate.read(b, off, Math.min(len, 128)); 207 } 208 } 209 210 @Test 211 public void testRT15619() { 212 BufferedImage bImg = createImage(BufferedImage.TYPE_INT_RGB); 213 ImageTestHelper.drawImageRandom(bImg); 214 ByteArrayInputStream stream = 215 ImageTestHelper.writeImageToStream(bImg, "bmp", null, null); 216 RT15619InputStream testStream = new RT15619InputStream(stream); 217 Image image = loadImage(testStream); 218 compare(image, bImg); 219 } 220 221 @Test 222 public void test1Bit() { 223 testImageType(BufferedImage.TYPE_BYTE_BINARY, "out1bit.bmp"); 224 } 225 226 @Test 227 public void test4Bit() { 228 testImage(create4BitImage(), "out4bit.bmp", null); 229 } 230 231 //@Test 232 public void test4BitRLE() { 233 testImage(create4BitImage(), "out4bitRLE.bmp", "BI_RLE4"); 234 } 235 236 @Test 237 public void test8Bit() { 238 testImageType(BufferedImage.TYPE_BYTE_INDEXED, "out8bit.bmp"); 239 } 240 241 @Test 242 public void test8BitRLE() { 243 testImageType(BufferedImage.TYPE_BYTE_INDEXED, "out8bitRLE.bmp", "BI_RLE8"); 244 } 245 246 @Test 247 public void test16Bit() { 248 testImageType(BufferedImage.TYPE_USHORT_555_RGB, "out16bit.bmp"); 249 } 250 251 @Test 252 public void test24Bit() { 253 testImageType(BufferedImage.TYPE_INT_RGB, "out24bit.bmp"); 254 } 255 256 void testFile(String fileName, String outFileName, String compression) { 257 try { 258 Image image = loadImage(new FileInputStream(fileName)); 259 BufferedImage bImg = ImageIO.read(new File(fileName)); 260 if (writeFiles) { 261 writeBMPImage(bImg, outFileName, compression); 262 } 263 compare(image, bImg); 264 } catch (IOException e) { 265 fail("unexpected IOException: " + e); 266 } 267 } 268 269 //@Test 270 public void testFiles() { 271 testFile("pal4rle.bmp", "pal4rleOut.bmp", "BI_RLE4"); 272 testFile("out4bitRLE.bmp", "out4bitRLEOut.bmp", "BI_RLE4"); 273 testFile("pal8rletrns.bmp", "pal8rletrnsOut.bmp", null); 274 } 275 }