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.Color; 31 import java.awt.GradientPaint; 32 import java.awt.Graphics2D; 33 import java.awt.image.BufferedImage; 34 import java.awt.image.DataBuffer; 35 import java.awt.image.IndexColorModel; 36 import java.io.ByteArrayInputStream; 37 import java.io.ByteArrayOutputStream; 38 import java.io.File; 39 import java.io.FileInputStream; 40 import java.io.IOException; 41 import java.io.InputStream; 42 import java.util.Iterator; 43 import java.util.Random; 44 import javax.imageio.IIOImage; 45 import javax.imageio.ImageIO; 46 import javax.imageio.ImageWriteParam; 47 import javax.imageio.ImageWriter; 48 import javax.imageio.stream.ImageOutputStream; 49 import javax.imageio.stream.MemoryCacheImageInputStream; 50 import static org.junit.Assert.*; 51 import org.junit.Test; 52 53 public class BMPImageLoaderTest { 54 static final boolean writeFiles = false; 55 static final int testWidth = 509, testHeight = 157; 56 57 ByteArrayInputStream constructStream(int[] bytes) { 58 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 59 for (int b : bytes) { 60 baos.write(b); 61 } 62 return new ByteArrayInputStream(baos.toByteArray()); 63 } 64 65 void compare(Image img, BufferedImage bImg) { 66 assertNotNull(img); 67 assertNotNull(bImg); 68 int w = bImg.getWidth(), h = bImg.getHeight(); 69 assertEquals("Unmatched width", w, img.getWidth()); 70 assertEquals("Unmatched height", h, img.getHeight()); 71 72 for (int y = 0; y < h; y++) { 73 for (int x = 0; x < w; x++) { 74 int p1 = bImg.getRGB(x, y); 75 int p2 = img.getArgb(x, y); 76 if (p1 != p2) { 77 throw new org.junit.ComparisonFailure( 78 "pixel " + x + ", " + y + " does not match", 79 String.format("0x%08X", p1), String.format("0x%08X", p2) 80 ); 81 } 82 } 83 } 84 } 85 86 Image loadImage(InputStream stream) { 87 ImageLoaderFactory loaderFactory = BMPImageLoaderFactory.getInstance(); 88 ImageLoader loader = null; 89 try { 90 loader = loaderFactory.createImageLoader(stream); 91 } catch (IOException ioEx) { 92 fail("unexpected IOException: " + ioEx); 93 } 94 assertNotNull(loader); 95 96 try { 97 ImageFrame frame = loader.load(0, 0, 0, true, true); 98 return Image.convertImageFrame(frame); 99 } catch (IOException e) { 100 fail("unexpected IOException: " + e); 101 } 102 return null; 103 } 104 105 BufferedImage create4BitImage() { 106 int[] cmap = new int[16]; 107 int i = 0; 108 for (int r = 0; r < 2; r++) { 109 for (int g = 0; g < 2; g++) { 110 for (int b = 0; b < 2; b++) { 111 cmap[i++] = 0xff << 24 | r * 255 << 16 | g * 255 << 8 | b * 255; 112 if ((r | g | b) == 0) { 113 cmap[i++] = 0xffc0c0c0; 114 } else { 115 cmap[i++] = 0xff << 24 | r * 128 << 16 | g * 128 << 8 | b * 128; 116 } 117 } 118 } 119 } 120 IndexColorModel cm = new IndexColorModel(4, 16, cmap, 0, false, -1, DataBuffer.TYPE_BYTE); 121 return new BufferedImage(testWidth, testHeight, BufferedImage.TYPE_BYTE_BINARY, cm); 122 } 123 124 BufferedImage createImage(int type) { 125 return new BufferedImage(testWidth, testHeight, type); 126 } 127 128 void writeImage(BufferedImage bImg, Object out, String compression) { 129 try { 130 ImageOutputStream ios = ImageIO.createImageOutputStream(out); 131 Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("bmp"); 132 ImageWriter writer = iter.next(); 133 ImageWriteParam iwp = writer.getDefaultWriteParam(); 134 if (compression != null) { 135 iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); 136 iwp.setCompressionType(compression); 137 } 138 writer.setOutput(ios); 139 writer.write(null, new IIOImage(bImg, null, null), iwp); 140 } catch (IOException e) { 141 fail("unexpected IOException: " + e); 142 } 143 } 144 145 Image getImage(BufferedImage bImg, String compression) { 146 ByteArrayOutputStream out = new ByteArrayOutputStream(); 147 writeImage(bImg, out, compression); 148 return loadImage(new ByteArrayInputStream(out.toByteArray())); 149 } 150 151 void testImageType(int type, String fileName, String compression) { 152 BufferedImage bImg = createImage(type); 153 testImage(bImg, fileName, compression); 154 } 155 156 void testImageType(int type, String fileName) { 157 BufferedImage bImg = createImage(type); 158 testImage(bImg, fileName, null); 159 } 160 161 void drawImageGradient(BufferedImage bImg) { 162 Graphics2D graphics = bImg.createGraphics(); 163 GradientPaint g = new GradientPaint(0, 0, Color.RED, testWidth, testHeight, Color.GREEN); 164 graphics.setPaint(g); 165 graphics.fillRect(0, 0, testWidth, testHeight); 166 } 167 168 void drawImageRandom(BufferedImage bImg) { 169 int h = bImg.getHeight(), w = bImg.getWidth(); 170 Random r = new Random(1); 171 for (int y = 0; y < h; y++) { 172 for (int x = 0; x < w; x++) { 173 bImg.setRGB(x, y, r.nextInt(1 << 24)); 174 } 175 } 176 } 177 178 void drawImageHue(BufferedImage bImg) { 179 int h = bImg.getHeight(), w = bImg.getWidth(); 180 for (int y = 0; y < h; y++) { 181 float s = 2.0f * y / h; 182 if (s > 1) { 183 s = 1; 184 } 185 float b = 2.0f * (h - y) / h; 186 if (b > 1) { 187 b = 1; 188 } 189 for (int x = 0; x < w; x++) { 190 float hue = (float) x / w; 191 bImg.setRGB(x, y, Color.HSBtoRGB(hue, s, b)); 192 } 193 } 194 } 195 196 void drawImageAll(BufferedImage bImg) { 197 int h = bImg.getHeight(), w = bImg.getWidth(); 198 //if (h*w < (1<<24)) return; 199 for (int y = 0; y < h; y++) { 200 for (int x = 0; x < w; x++) { 201 bImg.setRGB(x, y, y * h + x); 202 } 203 } 204 } 205 206 void testImage(BufferedImage bImg, String fileName, String compression) { 207 //drawImageHue(bImg); 208 //drawImageAll(bImg); 209 drawImageRandom(bImg); 210 if (writeFiles && fileName != null) { 211 File file = new File(fileName); 212 file.delete(); 213 writeImage(bImg, file, compression); 214 } 215 Image image = getImage(bImg, compression); 216 compare(image, bImg); 217 } 218 219 @Test 220 public void testRT32213() { 221 final int[] bytes = { 222 0x42, 0x4d, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 223 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x28, 0x00, 224 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 225 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 226 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 229 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 230 0x00, 0x00 231 }; 232 233 ByteArrayInputStream stream = constructStream(bytes); 234 Image image = loadImage(stream); 235 stream.reset(); 236 try { 237 BufferedImage bImg = ImageIO.read(new MemoryCacheImageInputStream(stream)); 238 compare(image, bImg); 239 } catch (IOException e) { 240 fail("unexpected IOException: " + e); 241 } 242 } 243 244 @Test 245 public void test1Bit() { 246 testImageType(BufferedImage.TYPE_BYTE_BINARY, "out1bit.bmp"); 247 } 248 249 @Test 250 public void test4Bit() { 251 testImage(create4BitImage(), "out4bit.bmp", null); 252 } 253 254 //@Test 255 public void test4BitRLE() { 256 testImage(create4BitImage(), "out4bitRLE.bmp", "BI_RLE4"); 257 } 258 259 @Test 260 public void test8Bit() { 261 testImageType(BufferedImage.TYPE_BYTE_INDEXED, "out8bit.bmp"); 262 } 263 264 @Test 265 public void test8BitRLE() { 266 testImageType(BufferedImage.TYPE_BYTE_INDEXED, "out8bitRLE.bmp", "BI_RLE8"); 267 } 268 269 @Test 270 public void test16Bit() { 271 testImageType(BufferedImage.TYPE_USHORT_555_RGB, "out16bit.bmp"); 272 } 273 274 @Test 275 public void test24Bit() { 276 testImageType(BufferedImage.TYPE_INT_RGB, "out24bit.bmp"); 277 } 278 279 void testFile(String fileName, String outFileName, String compression) { 280 try { 281 Image image = loadImage(new FileInputStream(fileName)); 282 BufferedImage bImg = ImageIO.read(new File(fileName)); 283 if (writeFiles && outFileName != null) { 284 File outFile = new File(outFileName); 285 outFile.delete(); 286 writeImage(bImg, outFile, compression); 287 } 288 compare(image, bImg); 289 } catch (IOException e) { 290 fail("unexpected IOException: " + e); 291 } 292 } 293 294 //@Test 295 public void testFiles() { 296 testFile("pal4rle.bmp", "pal4rleOut.bmp", "BI_RLE4"); 297 testFile("out4bitRLE.bmp", "out4bitRLEOut.bmp", "BI_RLE4"); 298 testFile("pal8rletrns.bmp", "pal8rletrnsOut.bmp", null); 299 } 300 }