1/*
2 * Copyright (c) 2005, 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 6332480
27 * @summary Test verifies that images encoded as BMP with RLE4 or RLE8
28 *          compression type are read correctly
29 */
30
31import java.awt.Color;
32import java.awt.Graphics2D;
33import java.awt.image.BufferedImage;
34import java.awt.image.IndexColorModel;
35import java.io.ByteArrayInputStream;
36import java.io.ByteArrayOutputStream;
37import java.io.IOException;
38
39import javax.imageio.IIOImage;
40import javax.imageio.ImageIO;
41import javax.imageio.ImageWriteParam;
42import javax.imageio.ImageWriter;
43import javax.imageio.stream.ImageOutputStream;
44
45public class RLECompressionTest {
46    public static final int TEST_RLE8 = 0x01;
47    public static final int TEST_RLE4 = 0x02;
48
49    private static Color[] usedColors = new Color[] {
50        Color.black, Color.white, Color.red,
51        Color.green, Color.blue, Color.yellow };
52
53    int w = 100;
54    // NB: problem occurs when image height > width
55    // The problem manifestation is that only first w
56    // lines of image are filled by decoded data,
57    // rest of image (all lines below (w-1)-th line)
58    // is leaved uninitialized (black).
59    // In order to verify that this problem is solved,
60    // we use image with height > width.
61    int h = 2 * w;
62
63    private IndexColorModel getTestColorModel(int type) {
64        IndexColorModel icm = null;
65        int bpp = 8;
66        int size = 256;
67
68        switch(type) {
69            case TEST_RLE8:
70                bpp = 8;
71                size = 256;
72                break;
73            case TEST_RLE4:
74                bpp = 4;
75                size = 16;
76                break;
77            default:
78                throw new IllegalArgumentException("Wrong test type: " + type);
79        }
80
81        byte[] palette = new byte[size * 3];
82        for (int i = 0; i < usedColors.length; i++) {
83            palette[3 * i] = (byte)(0xff & usedColors[i].getRed());
84            palette[3 * i + 1] = (byte)(0xff & usedColors[i].getGreen());
85            palette[3 * i + 2] = (byte)(0xff & usedColors[i].getBlue());
86        }
87        // rest of palette is black
88
89        icm = new IndexColorModel(bpp, size, palette, 0, false);
90        return icm;
91    }
92
93    private BufferedImage getTestImage(int type) {
94        BufferedImage src = null;
95        IndexColorModel icm = getTestColorModel(type);
96        src = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED, icm);
97        Graphics2D g = src.createGraphics();
98        g.setColor(Color.white);
99        g.fillRect(0, 0, w, h);
100        g.dispose();
101
102        return src;
103    }
104
105    public void doTest(int type) throws IOException {
106        BufferedImage src = getTestImage(type);
107
108        ByteArrayOutputStream baos = new ByteArrayOutputStream();
109        ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
110
111        ImageWriter writer = ImageIO.getImageWritersByFormatName("BMP").next();
112        writer.setOutput(ios);
113
114        ImageWriteParam wparam = writer.getDefaultWriteParam();
115        wparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
116        switch(type) {
117            case TEST_RLE8:
118                wparam.setCompressionType("BI_RLE8");
119                break;
120            case TEST_RLE4:
121                wparam.setCompressionType("BI_RLE4");
122                break;
123            default:
124                throw new IllegalArgumentException("Wrong test type: " + type);
125        }
126
127        writer.write(null, new IIOImage(src, null, null), wparam);
128
129        ios.close();
130        baos.close();
131
132        // read result
133        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
134
135        BufferedImage dst = ImageIO.read(bais);
136
137        checkResult(src, dst);
138    }
139
140    private void checkResult(BufferedImage src, BufferedImage dst) {
141        int x = w / 2;
142        for (int y = 0; y < h; y++) {
143            int srcRgb = src.getRGB(x, y);
144            int dstRgb = dst.getRGB(x, y);
145
146            if (srcRgb != dstRgb) {
147                throw new RuntimeException("Test failed due to color difference: " +
148                        Integer.toHexString(dstRgb) + " instead of " + Integer.toHexString(srcRgb) +
149                        " at [" + x + ", " + y + "]");
150            }
151        }
152    }
153
154    public static void main(String[] args) throws IOException {
155        RLECompressionTest test = new RLECompressionTest();
156        test.doTest(TEST_RLE8);
157        test.doTest(TEST_RLE4);
158    }
159}
160