1/* 2 * Copyright (c) 2003, 2017, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 4641872 27 * @summary Tests writing compression modes of BMP plugin 28 * @modules java.desktop/com.sun.imageio.plugins.bmp 29 */ 30 31import java.awt.Color; 32import java.awt.Dimension; 33import java.awt.Graphics; 34import java.awt.Graphics2D; 35import java.awt.Transparency; 36import java.awt.color.ColorSpace; 37import java.awt.image.BufferedImage; 38import java.awt.image.ColorModel; 39import java.awt.image.ComponentColorModel; 40import java.awt.image.DataBuffer; 41import java.awt.image.DirectColorModel; 42import java.awt.image.IndexColorModel; 43import java.awt.image.PixelInterleavedSampleModel; 44import java.awt.image.Raster; 45import java.awt.image.SampleModel; 46import java.awt.image.SinglePixelPackedSampleModel; 47import java.awt.image.WritableRaster; 48import java.io.ByteArrayInputStream; 49import java.io.ByteArrayOutputStream; 50import java.io.File; 51import java.io.FileOutputStream; 52import java.io.IOException; 53import java.util.Arrays; 54import java.util.Iterator; 55import java.util.LinkedList; 56import java.util.List; 57 58import javax.imageio.IIOImage; 59import javax.imageio.ImageIO; 60import javax.imageio.ImageReader; 61import javax.imageio.ImageTypeSpecifier; 62import javax.imageio.ImageWriteParam; 63import javax.imageio.ImageWriter; 64import javax.imageio.metadata.IIOMetadata; 65import javax.imageio.plugins.bmp.BMPImageWriteParam; 66import javax.imageio.stream.ImageOutputStream; 67import javax.swing.JComponent; 68import javax.swing.JFrame; 69 70import com.sun.imageio.plugins.bmp.BMPMetadata; 71 72public class BMPCompressionTest { 73 74 static final String format = "BMP"; 75 76 public static void main(String[] args) { 77 78 ImageWriter iw = null; 79 Iterator writers = ImageIO.getImageWritersByFormatName(format); 80 if (!writers.hasNext()) { 81 throw new RuntimeException("No available Image writer for "+format); 82 } 83 iw = (ImageWriter)writers.next(); 84 85 86 Iterator tests = Test.createTestSet(iw); 87 88 while(tests.hasNext()) { 89 90 Test t = (Test)tests.next(); 91 System.out.println(t.getDescription()); 92 t.doTest(); 93 } 94 95 } 96 97 98 static class Test { 99 static ImageWriter iw; 100 private BufferedImage img; 101 private String description; 102 private BMPImageWriteParam param; 103 private IIOMetadata meta; 104 105 106 public static Iterator createTestSet(ImageWriter w) { 107 List l = new LinkedList(); 108 109 Test.iw = w; 110 111 // variate compression types 112 BMPImageWriteParam param = (BMPImageWriteParam)iw.getDefaultWriteParam(); 113 param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); 114 param.setCompressionType("BI_RGB"); 115 if (param.canWriteCompressed()) { 116 String[] cTypes = param.getCompressionTypes(); 117 String[] cDescr = param.getCompressionQualityDescriptions(); 118 float[] cValues = param.getCompressionQualityValues(); 119 120 if (cDescr == null) { 121 System.out.println("There are no compression quality description!"); 122 } else { 123 for(int i=0; i<cDescr.length; i++) { 124 System.out.println("Quality[" + i + "]=\""+cDescr[i]+"\""); 125 } 126 } 127 if (cValues == null) { 128 System.out.println("There are no compression quality values!"); 129 } else { 130 for(int i=0; i<cValues.length; i++) { 131 System.out.println("Value["+i+"]=\""+cValues[i]+"\""); 132 } 133 } 134 135 for(int i=0; i<cTypes.length; i++) { 136 String compressionType = cTypes[i]; 137 BufferedImage img = null; 138 139 int type = BufferedImage.TYPE_INT_BGR; 140 try { 141 img = createTestImage(type); 142 if (compressionType.equals("BI_RLE8")) { 143 img = createTestImage2(8, DataBuffer.TYPE_BYTE); 144 } else if (compressionType.equals("BI_RLE4")) { 145 img = createTestImage3(4, DataBuffer.TYPE_BYTE); 146 } else if (compressionType.equals("BI_BITFIELDS")) { 147 img = createTestImage4(32); 148 } 149 150 } catch (IOException ex) { 151 throw new RuntimeException("Unable to create test image"); 152 } 153 BMPImageWriteParam p = (BMPImageWriteParam)iw.getDefaultWriteParam(); 154 System.out.println("Current compression type is \""+cTypes[i]+"\""); 155 p.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); 156 p.setCompressionType(compressionType); 157 158 IIOMetadata md = iw.getDefaultImageMetadata(new ImageTypeSpecifier(img), p); 159 160 l.add( new Test(p, md, img)); 161 } 162 } 163 // } 164 return l.iterator(); 165 166 } 167 168 private Test(BMPImageWriteParam p, IIOMetadata md, BufferedImage i) { 169 param = p; 170 meta = md; 171 img = i; 172 173 174 description = "Compression type is " + p.getCompressionType(); 175 } 176 177 public String getDescription() { 178 return description; 179 } 180 181 public void doTest() { 182 try { 183 System.out.println(this.getDescription()); 184 if (param.getCompressionMode() != ImageWriteParam.MODE_EXPLICIT) { 185 System.out.println("Warning: compression mode is not MODE_EXPLICIT"); 186 } 187 // change metadata according to ImageWriteParam 188 IIOMetadata new_meta = iw.convertImageMetadata(meta, new ImageTypeSpecifier(img), param); 189 190 IIOImage iio_img = new IIOImage(img, null, new_meta); 191 192 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 193 ImageOutputStream ios = ImageIO.createImageOutputStream(baos); 194 iw.setOutput(ios); 195 System.out.print("write image..."); 196 System.out.println("Current compression Type is \""+param.getCompressionType()+"\""); 197 iw.write(new_meta, iio_img, param); 198 //iw.write(iio_img); 199 System.out.println("OK"); 200 System.out.print("read image ... "); 201 ios.flush(); 202 203 byte[] ba_image = baos.toByteArray(); 204 205 System.out.println("Array length=" + ba_image.length); 206 FileOutputStream fos = new FileOutputStream(new File(param.getCompressionType()+".bmp")); 207 fos.write(ba_image); 208 fos.flush(); 209 fos = null; 210 ByteArrayInputStream bais = new ByteArrayInputStream(ba_image); 211 212 ImageReader ir = ImageIO.getImageReader(iw); 213 ir.setInput(ImageIO.createImageInputStream(bais)); 214 215 BufferedImage res = ir.read(0); 216 System.out.println("OK"); 217 218 if (!param.getCompressionType().equals("BI_JPEG")) { 219 System.out.print("compare images ... "); 220 boolean r = compare(img,res); 221 System.out.println(r?"OK":"FAILED"); 222 if (!r) { 223 throw new RuntimeException("Compared images are not equals. Test failed."); 224 } 225 } 226 227 228 BMPMetadata mdata = (BMPMetadata)ir.getImageMetadata(0); 229 230 if (!param.getCompressionType().equals(param.getCompressionTypes()[mdata.compression])) { 231 throw new RuntimeException("Different compression value"); 232 } 233 234 } catch (Exception ex) { 235 ex.printStackTrace(); 236 throw new RuntimeException("Unexpected exception: " + ex); 237 } 238 239 } 240 241 private boolean compare(final BufferedImage in, final BufferedImage out) { 242 243 final int width = in.getWidth(); 244 int height = in.getHeight(); 245 if (out.getWidth() != width || out.getHeight() != height) { 246 throw new RuntimeException("Dimensions changed!"); 247 } 248 249 Raster oldras = in.getRaster(); 250 ColorModel oldcm = in.getColorModel(); 251 Raster newras = out.getRaster(); 252 ColorModel newcm = out.getColorModel(); 253 254 for (int j = 0; j < height; j++) { 255 for (int i = 0; i < width; i++) { 256 Object oldpixel = oldras.getDataElements(i, j, null); 257 int oldrgb = oldcm.getRGB(oldpixel); 258 int oldalpha = oldcm.getAlpha(oldpixel); 259 260 Object newpixel = newras.getDataElements(i, j, null); 261 int newrgb = newcm.getRGB(newpixel); 262 int newalpha = newcm.getAlpha(newpixel); 263 264 if (newrgb != oldrgb || 265 newalpha != oldalpha) { 266 // showDiff(in, out); 267 throw new RuntimeException("Pixels differ at " + i + 268 ", " + j + " new = " + Integer.toHexString(newrgb) + " old = " + Integer.toHexString(oldrgb)); 269 } 270 } 271 } 272 return true; 273 } 274 275 private static BufferedImage createTestImage2(int nbits, int transfertype) { 276 final int colorShift = 2; 277 int SIZE = 256; 278 BufferedImage image = null; 279 280 ColorSpace colorSpace = 281 ColorSpace.getInstance(ColorSpace.CS_GRAY); 282 ColorModel colorModel = 283 new ComponentColorModel(colorSpace, 284 new int[] {nbits}, 285 false, 286 false, 287 Transparency.OPAQUE, 288 transfertype); 289 290 SampleModel sampleModel = 291 new PixelInterleavedSampleModel(transfertype, 292 SIZE, 293 SIZE, 294 1, 295 SIZE, 296 new int[] {0}); 297 298 image = 299 new BufferedImage(colorModel, 300 Raster.createWritableRaster(sampleModel, null), 301 false, null); 302 WritableRaster raster = image.getWritableTile(0, 0); 303 int[] samples = raster.getSamples(0, 0, SIZE, SIZE, 0, (int[])null); 304 int off = 0; 305 int[] row = new int[SIZE]; 306 for(int i = 0; i < SIZE; i++) { 307 Arrays.fill(row, i << colorShift); 308 System.arraycopy(row, 0, samples, off, SIZE); 309 off += SIZE; 310 } 311 raster.setSamples(0, 0, SIZE, SIZE, 0, samples); 312 313 return image; 314 } 315 316 317 private static BufferedImage createTestImage3(int nbits, int transfertype) { 318 final int colorShift = 2; 319 int SIZE = 256; 320 BufferedImage image = null; 321 322 ColorSpace colorSpace = 323 ColorSpace.getInstance(ColorSpace.CS_sRGB); 324 ColorModel colorModel = 325 new IndexColorModel(nbits, 326 4, 327 new byte[] { (byte)255, 0, 0, (byte)255}, 328 new byte[] { 0, (byte)255, 0, (byte)255}, 329 new byte[] { 0, 0, (byte)255, (byte)255}); 330 331 SampleModel sampleModel = 332 new PixelInterleavedSampleModel(transfertype, 333 SIZE, 334 SIZE, 335 1, 336 SIZE, 337 new int[] {0}); 338 339 image = 340 new BufferedImage(colorModel, 341 Raster.createWritableRaster(sampleModel, null), 342 343 false, null); 344 345 Graphics2D g = image.createGraphics(); 346 g.setColor(Color.white); 347 g.fillRect(0,0, SIZE, SIZE); 348 g.setColor(Color.red); 349 g.fillOval(10, 10, SIZE -20, SIZE-20); 350 351 return image; 352 } 353 354 private static BufferedImage createTestImage4(int nbits) { 355 int SIZE = 10; 356 357 358 BufferedImage image = null; 359 360 ColorSpace colorSpace = 361 ColorSpace.getInstance(ColorSpace.CS_sRGB); 362 ColorModel colorModel = 363 new DirectColorModel(colorSpace, 364 nbits, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, false, DataBuffer.TYPE_INT); 365 366 SampleModel sampleModel = 367 new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, 368 SIZE, 369 SIZE, 370 new int[] { 0xff0000, 0x00ff00, 0x0000ff} ); 371 372 373 image = 374 new BufferedImage(colorModel, 375 Raster.createWritableRaster(sampleModel, null), 376 377 false, null); 378 379 Graphics2D g = image.createGraphics(); 380 g.setColor(Color.red); 381 g.fillRect(0,0, SIZE, SIZE); 382 g.setColor(Color.green); 383 //g.fillOval(10, 10, SIZE -20, SIZE-20); 384 g.drawLine(7, 0, 7, SIZE); 385 g.setColor(Color.blue); 386 g.drawLine(1, 0, 1, SIZE); 387 g.setColor(Color.white); 388 g.drawLine(3, 0, 3, SIZE); 389 g.setColor(Color.yellow); 390 g.drawLine(5, 0, 5, SIZE); 391 return image; 392 } 393 394 private static BufferedImage createTestImage(int type) 395 throws IOException { 396 397 int w = 200; 398 int h = 200; 399 BufferedImage b = new BufferedImage(w, h, type); 400 Graphics2D g = b.createGraphics(); 401 g.setColor(Color.white); 402 g.fillRect(0,0, w, h); 403 g.setColor(Color.black); 404 g.fillOval(10, 10, w -20, h-20); 405 406 return b; 407 } 408 409 410 } 411 412 private static void showDiff(final BufferedImage in, 413 final BufferedImage out) { 414 final int width = in.getWidth(); 415 final int height = in.getHeight(); 416 417 JFrame f = new JFrame(""); 418 f.getContentPane().add( new JComponent() { 419 public Dimension getPreferredSize() { 420 return new Dimension(2*width+2, height); 421 } 422 public void paintComponent(Graphics g) { 423 g.setColor(Color.black); 424 g.drawImage(in, 0,0, null); 425 426 g.drawImage(out, width+2, 0, null); 427 } 428 }); 429 f.pack(); 430 f.setVisible(true); 431 } 432 433} 434