1 /*
   2  * Copyright (c) 2012, 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 test.com.sun.javafx.iio;
  27 
  28 import com.sun.javafx.iio.ImageFrame;
  29 import com.sun.javafx.iio.ImageLoader;
  30 import com.sun.javafx.iio.ImageStorage;
  31 import com.sun.javafx.iio.gif.GIFImageLoader2;
  32 import java.awt.image.*;
  33 import java.io.*;
  34 import static org.junit.Assert.*;
  35 import org.junit.Test;
  36 
  37 
  38 class TestStream extends InputStream {
  39     byte data[];
  40     int  p = 0;
  41 
  42     public TestStream(byte data[]) {
  43         this.data = data;
  44     }
  45 
  46     @Override
  47     public int read() throws IOException {
  48         return p < data.length ? (int)data[p++] & 0xff : -1;
  49     }
  50 }
  51 
  52 public class GIFLoaderTest {
  53 
  54     @Test
  55     public void testCtorNPE() {
  56         try {
  57             new GIFImageLoader2(null);
  58         } catch (NullPointerException ex) {
  59            return; // PASSED
  60         } catch (IOException ioEx) {
  61             fail("unexpected IOException:" + ioEx.toString());
  62         }
  63         fail("expected NPE after constructor invocation with null");
  64     }
  65 
  66 
  67 
  68     @Test
  69     public void testCtorReadBadHeader1()  {
  70         final byte tooShortHeaderData[] = {
  71             0,1,2,3,4
  72         };
  73 
  74         try {
  75             new GIFImageLoader2(new TestStream(tooShortHeaderData));
  76         } catch (EOFException ex) {
  77             return; // PASSED
  78         } catch (IOException ioEx) {
  79             fail("unexpected IOException:" + ioEx.toString());
  80         }
  81         fail("expected EOF exception for streams lesser then 13 bytes");
  82     }
  83 
  84     @Test
  85     public void testCtorReadBadHeader2()  {
  86         final byte tooShortHeaderData[] = {
  87             'G', 'I', 'F', '8', '9', 'a',
  88             0, 0, 0, 0, 0, 0
  89         };
  90 
  91         try {
  92             new GIFImageLoader2(new TestStream(tooShortHeaderData));
  93         } catch (EOFException ex) {
  94             return; // PASSED
  95         } catch (IOException ioEx) {
  96             fail("unexpected IOException:" + ioEx.toString());
  97         }
  98         fail("expected EOF exception for streams lesser then 13 bytes");
  99     }
 100 
 101     @Test
 102     public void testCtorReadGoodHeader()  {
 103         final byte _87HeaderData[] = {
 104             'G', 'I', 'F', '8', '7', 'a',
 105             1, 0, 1, 0, 0, 0, 0
 106         };
 107         final byte _89HeaderData[] = {
 108             'G', 'I', 'F', '8', '9', 'a',
 109             1, 0, 1, 0, 0, 0, 0
 110         };
 111         try {
 112             new GIFImageLoader2(new TestStream(_87HeaderData));
 113             new GIFImageLoader2(new TestStream(_89HeaderData));
 114         } catch (IOException ioEx) {
 115             ioEx.printStackTrace(System.out);
 116             fail("unexpected IOException:" + ioEx.toString());
 117 
 118         }
 119     }
 120 
 121     @Test (timeout=2000)
 122     public void testCtorReadBadExtension()  {
 123         final byte badGifData[] = {
 124             'G', 'I', 'F', '8', '9', 'a',
 125             1, 0, 1, 0, -112, 0, 0, -18, 51, 34,
 126             0, 0, 0, 44, 0, 0, 0, 0, 1, 0, 1, 0,
 127             0, 2, 2, 4, 1, 43, 48
 128         };
 129 
 130         // Create a loader using the data containing a bad GIF extension
 131         GIFImageLoader2 loader = null;
 132         try {
 133             loader = new GIFImageLoader2(new TestStream(badGifData));
 134         } catch (IOException ioEx) {
 135             fail("unexpected IOException:" + ioEx.toString());
 136         }
 137         assertNotNull(loader);
 138 
 139         // Now try to load the image; it should get an EOFException
 140         try {
 141             loader.load(0, 1, 1, true, true);
 142         } catch (EOFException ex) {
 143             return; // PASSED
 144         } catch (IOException ioEx) {
 145             fail("unexpected IOException:" + ioEx.toString());
 146         }
 147         fail("expected EOF exception for streams with bad extension");
 148     }
 149 
 150     private void compareBGRaAndIndexed(byte dataRGBA[], byte dataIndexed[], int paletteBGRA[]) {
 151         assertEquals(dataIndexed.length*4, dataRGBA.length);
 152         for (int i = 0, j = 0, e = dataIndexed.length; i < e; j += 4, ++i) {
 153             int r = dataRGBA[j+0] & 0xFF, g = dataRGBA[j+1] & 0xFF,
 154                 b = dataRGBA[j+2] & 0xFF, a = dataRGBA[j+3] & 0xFF;
 155             int x = b + (g<<8) + (r<<16) + (a<<24);
 156             int y = paletteBGRA[dataIndexed[i] & 0xFF];
 157 
 158             if ((x != y) && (((x & 0xFF000000) != 0) || ((y & 0xFF000000) != 0))) {
 159                 fail("colors are different : JDK: " + Integer.toHexString(y)
 160                         + ", JavaFX: " + Integer.toHexString(x));
 161             }
 162         }
 163     }
 164 
 165     private void compareBGRaAndIndexed(byte dataRGBA[], int dataIndexed[], int paletteBGRA[]) {
 166         assertEquals(dataIndexed.length*4, dataRGBA.length);
 167         for (int i = 0, j = 0, e = dataIndexed.length; i < e; j += 4, ++i) {
 168             int r = dataRGBA[j+0] & 0xFF, g = dataRGBA[j+1] & 0xFF,
 169                 b = dataRGBA[j+2] & 0xFF, a = dataRGBA[j+3] & 0xFF;
 170             int x = b + (g<<8) + (r<<16) + (a<<24);
 171             int y = paletteBGRA[dataIndexed[i] & 0xFF];
 172             if ((x != y) && (((x & 0xFF000000) != 0) || ((y & 0xFF000000) != 0))) {
 173                 fail("colors are different : JDK: " + Integer.toHexString(y)
 174                         + ", JavaFX: " + Integer.toHexString(x));
 175             }
 176         }
 177     }
 178 
 179 
 180     private void compareImageFrameAndBImage(ImageFrame f, BufferedImage bimg) {
 181         byte dataRGBA[] = (byte[])f.getImageData().array();
 182         assertEquals(dataRGBA.length, f.getHeight() * f.getWidth() * 4);
 183         assertEquals(f.getImageType(), ImageStorage.ImageType.RGBA);
 184 
 185         assertEquals(f.getHeight(), bimg.getHeight());
 186         assertEquals(f.getWidth(), bimg.getWidth());
 187 
 188         if (bimg.getColorModel() instanceof IndexColorModel) {
 189             IndexColorModel idx = (IndexColorModel)bimg.getColorModel();
 190             int rgb[] = new int [256];
 191             idx.getRGBs(rgb);
 192             Raster r = bimg.getData();
 193             DataBuffer db = r.getDataBuffer();
 194             assertTrue( db instanceof DataBufferByte);
 195             DataBufferByte bdb = (DataBufferByte)db;
 196             assertEquals(bdb.getNumBanks(), 1);
 197             byte dataIndexed[] = bdb.getData(0);
 198             int bitsPerPixel = idx.getPixelSize();
 199             if (bitsPerPixel == 8) {
 200                 assertEquals(dataIndexed.length, f.getHeight()*f.getWidth());
 201                 compareBGRaAndIndexed(dataRGBA, dataIndexed, rgb);
 202             } else {
 203                 int rgbData[] = new int[bimg.getWidth() * bimg.getHeight()];
 204                 r.getPixels(0, 0, bimg.getWidth(), bimg.getHeight(), rgbData);
 205                 compareBGRaAndIndexed(dataRGBA, rgbData, rgb);
 206             }
 207         } else {
 208             Raster r = bimg.getData();
 209 //            System.out.println("" + r.getWidth() + "," + r.getHeight() + "," + r.getNumBands()
 210 //                    + "," + r.getDataBuffer() + "," + r.getSampleModel());
 211             fail("Unexpected image form AWT");
 212         }
 213     }
 214 
 215     private void testReadGIFFile(String fname) throws IOException  {
 216         InputStream i = this.getClass().getResourceAsStream(fname);
 217         InputStream testStream = ImageTestHelper.createStutteringInputStream(i);
 218         ImageLoader l = new GIFImageLoader2(testStream);
 219         ImageFrame f = l.load(0, 0, 0, true, false);
 220         InputStream i2 = this.getClass().getResourceAsStream(fname);
 221         BufferedImage bimg = javax.imageio.ImageIO.read(i2);
 222 
 223         compareImageFrameAndBImage(f, bimg);
 224     }
 225 
 226     @Test
 227     public void testReadGIFFile() throws Exception  {
 228         for (String s : fileList) {
 229             try {
 230                 testReadGIFFile(s);
 231             } catch (Exception ex) {
 232                 System.err.println("Failure in test file " + s);
 233                 throw ex;
 234             }
 235         }
 236     }
 237 
 238 //    public static void main(String[] args) throws IOException {
 239 //        new GIFLoaderTest().testReadGIFFile();
 240 //    }
 241 
 242     final static String fileList[] = {
 243         "gif/adam_7_interlacing/basi0g01.gif",
 244         "gif/adam_7_interlacing/basi0g02.gif",
 245         "gif/adam_7_interlacing/basi0g04.gif",
 246         "gif/adam_7_interlacing/basi0g08.gif",
 247         "gif/adam_7_interlacing/basi0g16.gif",
 248         "gif/adam_7_interlacing/basi2c08.gif",
 249         "gif/adam_7_interlacing/basi2c16.gif",
 250         "gif/adam_7_interlacing/basi3p01.gif",
 251         "gif/adam_7_interlacing/basi3p02.gif",
 252         "gif/adam_7_interlacing/basi3p04.gif",
 253         "gif/adam_7_interlacing/basi3p08.gif",
 254         "gif/adam_7_interlacing/basi4a08.gif",
 255         "gif/adam_7_interlacing/basi4a16.gif",
 256         "gif/adam_7_interlacing/basi6a08.gif",
 257         "gif/adam_7_interlacing/basi6a16.gif",
 258         "gif/base/basn0g01.gif",
 259         "gif/base/basn0g02.gif",
 260         "gif/base/basn0g04.gif",
 261         "gif/base/basn0g08.gif",
 262         "gif/base/basn0g16.gif",
 263         "gif/base/basn2c08.gif",
 264         "gif/base/basn2c16.gif",
 265         "gif/base/basn3p01.gif",
 266         "gif/base/basn3p02.gif",
 267         "gif/base/basn3p04.gif",
 268         "gif/base/basn3p08.gif",
 269         "gif/base/basn4a08.gif",
 270         "gif/base/basn4a16.gif",
 271         "gif/base/basn6a08.gif",
 272         "gif/base/basn6a16.gif",
 273         "gif/background/bgai4a08.gif",
 274         "gif/background/bgai4a16.gif",
 275         "gif/background/bgan6a08.gif",
 276         "gif/background/bgan6a16.gif",
 277         "gif/background/bgbn4a08.gif",
 278         "gif/background/bggn4a16.gif",
 279         "gif/background/bgwn6a08.gif",
 280         "gif/background/bgyn6a16.gif",
 281         "gif/ancillary_chunks/ccwn2c08.gif",
 282         "gif/ancillary_chunks/ccwn3p08.gif",
 283         "gif/ancillary_chunks/cdfn2c08.gif",
 284         "gif/ancillary_chunks/cdhn2c08.gif",
 285         "gif/ancillary_chunks/cdsn2c08.gif",
 286         "gif/ancillary_chunks/cdun2c08.gif",
 287         "gif/ancillary_chunks/ch1n3p04.gif",
 288         "gif/ancillary_chunks/ch2n3p08.gif",
 289         "gif/ancillary_chunks/cm0n0g04.gif",
 290         "gif/ancillary_chunks/cm7n0g04.gif",
 291         "gif/ancillary_chunks/cm9n0g04.gif",
 292         "gif/ancillary_chunks/cs3n2c16.gif",
 293         "gif/ancillary_chunks/cs3n3p08.gif",
 294         "gif/ancillary_chunks/cs5n2c08.gif",
 295         "gif/ancillary_chunks/cs5n3p08.gif",
 296         "gif/ancillary_chunks/cs8n2c08.gif",
 297         "gif/ancillary_chunks/cs8n3p08.gif",
 298         "gif/ancillary_chunks/ct0n0g04.gif",
 299         "gif/ancillary_chunks/ct1n0g04.gif",
 300         "gif/ancillary_chunks/cten0g04.gif",
 301         "gif/ancillary_chunks/ctfn0g04.gif",
 302         "gif/ancillary_chunks/ctgn0g04.gif",
 303         "gif/ancillary_chunks/cthn0g04.gif",
 304         "gif/ancillary_chunks/ctjn0g04.gif",
 305         "gif/filtering/f00n0g08.gif",
 306         "gif/filtering/f00n2c08.gif",
 307         "gif/filtering/f01n0g08.gif",
 308         "gif/filtering/f01n2c08.gif",
 309         "gif/filtering/f02n0g08.gif",
 310         "gif/filtering/f02n2c08.gif",
 311         "gif/filtering/f03n0g08.gif",
 312         "gif/filtering/f03n2c08.gif",
 313         "gif/filtering/f04n0g08.gif",
 314         "gif/filtering/f04n2c08.gif",
 315         "gif/filtering/f99n0g04.gif",
 316         "gif/gamma/g03n0g16.gif",
 317         "gif/gamma/g03n2c08.gif",
 318         "gif/gamma/g03n3p04.gif",
 319         "gif/gamma/g04n0g16.gif",
 320         "gif/gamma/g04n2c08.gif",
 321         "gif/gamma/g04n3p04.gif",
 322         "gif/gamma/g05n0g16.gif",
 323         "gif/gamma/g05n2c08.gif",
 324         "gif/gamma/g05n3p04.gif",
 325         "gif/gamma/g07n0g16.gif",
 326         "gif/gamma/g07n2c08.gif",
 327         "gif/gamma/g07n3p04.gif",
 328         "gif/gamma/g10n0g16.gif",
 329         "gif/gamma/g10n2c08.gif",
 330         "gif/gamma/g10n3p04.gif",
 331         "gif/gamma/g25n0g16.gif",
 332         "gif/gamma/g25n2c08.gif",
 333         "gif/gamma/g25n3p04.gif",
 334         "gif/chunk_ordering/oi1n0g16.gif",
 335         "gif/chunk_ordering/oi1n2c16.gif",
 336         "gif/chunk_ordering/oi2n0g16.gif",
 337         "gif/chunk_ordering/oi2n2c16.gif",
 338         "gif/chunk_ordering/oi4n0g16.gif",
 339         "gif/chunk_ordering/oi4n2c16.gif",
 340         "gif/chunk_ordering/oi9n0g16.gif",
 341         "gif/chunk_ordering/oi9n2c16.gif",
 342         "gif/add_palets/pp0n2c16.gif",
 343         "gif/add_palets/pp0n6a08.gif",
 344         "gif/add_palets/ps1n0g08.gif",
 345         "gif/add_palets/ps1n2c16.gif",
 346         "gif/add_palets/ps2n0g08.gif",
 347         "gif/add_palets/ps2n2c16.gif",
 348         "gif/odd_sizes/s01i3p01.gif",
 349         "gif/odd_sizes/s01n3p01.gif",
 350         "gif/odd_sizes/s02i3p01.gif",
 351         "gif/odd_sizes/s02n3p01.gif",
 352         "gif/odd_sizes/s03i3p01.gif",
 353         "gif/odd_sizes/s03n3p01.gif",
 354         "gif/odd_sizes/s04i3p01.gif",
 355         "gif/odd_sizes/s04n3p01.gif",
 356         "gif/odd_sizes/s05i3p02.gif",
 357         "gif/odd_sizes/s05n3p02.gif",
 358         "gif/odd_sizes/s06i3p02.gif",
 359         "gif/odd_sizes/s06n3p02.gif",
 360         "gif/odd_sizes/s07i3p02.gif",
 361         "gif/odd_sizes/s07n3p02.gif",
 362         "gif/odd_sizes/s08i3p02.gif",
 363         "gif/odd_sizes/s08n3p02.gif",
 364         "gif/odd_sizes/s09i3p02.gif",
 365         "gif/odd_sizes/s09n3p02.gif",
 366         "gif/odd_sizes/s32i3p04.gif",
 367         "gif/odd_sizes/s32n3p04.gif",
 368         "gif/odd_sizes/s33i3p04.gif",
 369         "gif/odd_sizes/s33n3p04.gif",
 370         "gif/odd_sizes/s34i3p04.gif",
 371         "gif/odd_sizes/s34n3p04.gif",
 372         "gif/odd_sizes/s35i3p04.gif",
 373         "gif/odd_sizes/s35n3p04.gif",
 374         "gif/odd_sizes/s36i3p04.gif",
 375         "gif/odd_sizes/s36n3p04.gif",
 376         "gif/odd_sizes/s37i3p04.gif",
 377         "gif/odd_sizes/s37n3p04.gif",
 378         "gif/odd_sizes/s38i3p04.gif",
 379         "gif/odd_sizes/s38n3p04.gif",
 380         "gif/odd_sizes/s39i3p04.gif",
 381         "gif/odd_sizes/s39n3p04.gif",
 382         "gif/odd_sizes/s40i3p04.gif",
 383         "gif/odd_sizes/s40n3p04.gif",
 384         "gif/transparency/tbbn0g04.gif",
 385         "gif/transparency/tbbn2c16.gif",
 386         "gif/transparency/tbbn3p08.gif",
 387         "gif/transparency/tbgn2c16.gif",
 388         "gif/transparency/tbgn3p08.gif",
 389         "gif/transparency/tbrn2c08.gif",
 390         "gif/transparency/tbwn0g16.gif",
 391         "gif/transparency/tbwn3p08.gif",
 392         "gif/transparency/tbyn3p08.gif",
 393         "gif/transparency/tp0n0g08.gif",
 394         "gif/transparency/tp0n2c08.gif",
 395         "gif/transparency/tp0n3p08.gif",
 396         "gif/transparency/tp1n3p08.gif",
 397         "gif/corrupted/xc1n0g08.gif",
 398         "gif/corrupted/xc9n2c08.gif",
 399         "gif/corrupted/xcrn0g04.gif",
 400         "gif/corrupted/xcsn0g01.gif",
 401         "gif/corrupted/xd0n2c08.gif",
 402         "gif/corrupted/xd3n2c08.gif",
 403         "gif/corrupted/xd9n2c08.gif",
 404         "gif/corrupted/xdtn0g01.gif",
 405         "gif/corrupted/xhdn0g08.gif",
 406         "gif/corrupted/xlfn0g04.gif",
 407         "gif/corrupted/xs1n0g01.gif",
 408         "gif/corrupted/xs2n0g01.gif",
 409         "gif/corrupted/xs4n0g01.gif",
 410         "gif/corrupted/xs7n0g01.gif",
 411         "gif/zlib_compression_level/z00n2c08.gif",
 412         "gif/zlib_compression_level/z03n2c08.gif",
 413         "gif/zlib_compression_level/z06n2c08.gif",
 414         "gif/zlib_compression_level/z09n2c08.gif"
 415     };
 416 }