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