├── testsuite
└── pngsuite
│ ├── PngSuite.png
│ ├── basic
│ ├── basn0g01.png
│ ├── basn0g02.png
│ ├── basn0g04.png
│ ├── basn0g08.png
│ ├── basn0g16.png
│ ├── basn2c08.png
│ ├── basn2c16.png
│ ├── basn3p01.png
│ ├── basn3p02.png
│ ├── basn3p04.png
│ ├── basn3p08.png
│ ├── basn4a08.png
│ ├── basn4a16.png
│ ├── basn6a08.png
│ └── basn6a16.png
│ ├── gamma
│ ├── g03n0g16.png
│ ├── g03n2c08.png
│ ├── g03n3p04.png
│ ├── g04n0g16.png
│ ├── g04n2c08.png
│ ├── g04n3p04.png
│ ├── g05n0g16.png
│ ├── g05n2c08.png
│ ├── g05n3p04.png
│ ├── g07n0g16.png
│ ├── g07n2c08.png
│ ├── g07n3p04.png
│ ├── g10n0g16.png
│ ├── g10n2c08.png
│ ├── g10n3p04.png
│ ├── g25n0g16.png
│ ├── g25n2c08.png
│ └── g25n3p04.png
│ ├── zlib
│ ├── z00n2c08.png
│ ├── z03n2c08.png
│ ├── z06n2c08.png
│ └── z09n2c08.png
│ ├── odd_size
│ ├── s01i3p01.png
│ ├── s01n3p01.png
│ ├── s02i3p01.png
│ ├── s02n3p01.png
│ ├── s03i3p01.png
│ ├── s03n3p01.png
│ ├── s04i3p01.png
│ ├── s04n3p01.png
│ ├── s05i3p02.png
│ ├── s05n3p02.png
│ ├── s06i3p02.png
│ ├── s06n3p02.png
│ ├── s07i3p02.png
│ ├── s07n3p02.png
│ ├── s08i3p02.png
│ ├── s08n3p02.png
│ ├── s09i3p02.png
│ ├── s09n3p02.png
│ ├── s32i3p04.png
│ ├── s32n3p04.png
│ ├── s33i3p04.png
│ ├── s33n3p04.png
│ ├── s34i3p04.png
│ ├── s34n3p04.png
│ ├── s35i3p04.png
│ ├── s35n3p04.png
│ ├── s36i3p04.png
│ ├── s36n3p04.png
│ ├── s37i3p04.png
│ ├── s37n3p04.png
│ ├── s38i3p04.png
│ ├── s38n3p04.png
│ ├── s39i3p04.png
│ ├── s39n3p04.png
│ ├── s40i3p04.png
│ └── s40n3p04.png
│ ├── ordering
│ ├── oi1n0g16.png
│ ├── oi1n2c16.png
│ ├── oi2n0g16.png
│ ├── oi2n2c16.png
│ ├── oi4n0g16.png
│ ├── oi4n2c16.png
│ ├── oi9n0g16.png
│ └── oi9n2c16.png
│ ├── palette
│ ├── pp0n2c16.png
│ ├── pp0n6a08.png
│ ├── ps1n0g08.png
│ ├── ps1n2c16.png
│ ├── ps2n0g08.png
│ └── ps2n2c16.png
│ ├── ancillary
│ ├── ccwn2c08.png
│ ├── ccwn3p08.png
│ ├── cdfn2c08.png
│ ├── cdhn2c08.png
│ ├── cdsn2c08.png
│ ├── cdun2c08.png
│ ├── ch1n3p04.png
│ ├── ch2n3p08.png
│ ├── cm0n0g04.png
│ ├── cm7n0g04.png
│ ├── cm9n0g04.png
│ ├── cs3n2c16.png
│ ├── cs3n3p08.png
│ ├── cs5n2c08.png
│ ├── cs5n3p08.png
│ ├── cs8n2c08.png
│ ├── cs8n3p08.png
│ ├── ct0n0g04.png
│ ├── ct1n0g04.png
│ ├── cten0g04.png
│ ├── ctfn0g04.png
│ ├── ctgn0g04.png
│ ├── cthn0g04.png
│ ├── ctjn0g04.png
│ └── ctzn0g04.png
│ ├── background
│ ├── bgai4a08.png
│ ├── bgai4a16.png
│ ├── bgan6a08.png
│ ├── bgan6a16.png
│ ├── bgbn4a08.png
│ ├── bggn4a16.png
│ ├── bgwn6a08.png
│ └── bgyn6a16.png
│ ├── corrupted
│ ├── xc1n0g08.png
│ ├── xc9n2c08.png
│ ├── xcrn0g04.png
│ ├── xcsn0g01.png
│ ├── xd0n2c08.png
│ ├── xd3n2c08.png
│ ├── xd9n2c08.png
│ ├── xdtn0g01.png
│ ├── xhdn0g08.png
│ ├── xlfn0g04.png
│ ├── xs1n0g01.png
│ ├── xs2n0g01.png
│ ├── xs4n0g01.png
│ └── xs7n0g01.png
│ ├── filtering
│ ├── f00n0g08.png
│ ├── f00n2c08.png
│ ├── f01n0g08.png
│ ├── f01n2c08.png
│ ├── f02n0g08.png
│ ├── f02n2c08.png
│ ├── f03n0g08.png
│ ├── f03n2c08.png
│ ├── f04n0g08.png
│ ├── f04n2c08.png
│ └── f99n0g04.png
│ ├── interlacing
│ ├── basi0g01.png
│ ├── basi0g02.png
│ ├── basi0g04.png
│ ├── basi0g08.png
│ ├── basi0g16.png
│ ├── basi2c08.png
│ ├── basi2c16.png
│ ├── basi3p01.png
│ ├── basi3p02.png
│ ├── basi3p04.png
│ ├── basi3p08.png
│ ├── basi4a08.png
│ ├── basi4a16.png
│ ├── basi6a08.png
│ └── basi6a16.png
│ ├── transparency
│ ├── tbbn0g04.png
│ ├── tbbn2c16.png
│ ├── tbbn3p08.png
│ ├── tbgn2c16.png
│ ├── tbgn3p08.png
│ ├── tbrn2c08.png
│ ├── tbwn0g16.png
│ ├── tbwn3p08.png
│ ├── tbyn3p08.png
│ ├── tm3n3p02.png
│ ├── tp0n0g08.png
│ ├── tp0n2c08.png
│ ├── tp0n3p08.png
│ └── tp1n3p08.png
│ ├── PngSuite.LICENSE
│ └── PngSuite.README
├── fluid.vcxproj.filters
├── fluid.sln
├── fluid.h
├── LICENSE
├── README.md
├── .gitignore
├── fluid.vcxproj
├── viewer.cpp
└── fluid.c
/testsuite/pngsuite/PngSuite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/PngSuite.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn0g01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn0g01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn0g02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn0g02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn4a08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn4a08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn4a16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn4a16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn6a08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn6a08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/basic/basn6a16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/basic/basn6a16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g03n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g03n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g03n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g03n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g03n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g03n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g04n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g04n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g04n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g04n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g04n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g04n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g05n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g05n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g05n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g05n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g05n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g05n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g07n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g07n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g07n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g07n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g07n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g07n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g10n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g10n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g10n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g10n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g10n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g10n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g25n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g25n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g25n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g25n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/gamma/g25n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/gamma/g25n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/zlib/z00n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/zlib/z00n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/zlib/z03n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/zlib/z03n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/zlib/z06n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/zlib/z06n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/zlib/z09n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/zlib/z09n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s01i3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s01i3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s01n3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s01n3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s02i3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s02i3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s02n3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s02n3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s03i3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s03i3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s03n3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s03n3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s04i3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s04i3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s04n3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s04n3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s05i3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s05i3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s05n3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s05n3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s06i3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s06i3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s06n3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s06n3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s07i3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s07i3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s07n3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s07n3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s08i3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s08i3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s08n3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s08n3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s09i3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s09i3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s09n3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s09n3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s32i3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s32i3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s32n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s32n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s33i3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s33i3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s33n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s33n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s34i3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s34i3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s34n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s34n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s35i3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s35i3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s35n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s35n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s36i3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s36i3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s36n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s36n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s37i3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s37i3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s37n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s37n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s38i3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s38i3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s38n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s38n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s39i3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s39i3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s39n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s39n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s40i3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s40i3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/odd_size/s40n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/odd_size/s40n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ordering/oi1n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ordering/oi1n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ordering/oi1n2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ordering/oi1n2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ordering/oi2n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ordering/oi2n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ordering/oi2n2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ordering/oi2n2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ordering/oi4n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ordering/oi4n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ordering/oi4n2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ordering/oi4n2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ordering/oi9n0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ordering/oi9n0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ordering/oi9n2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ordering/oi9n2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/palette/pp0n2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/palette/pp0n2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/palette/pp0n6a08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/palette/pp0n6a08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/palette/ps1n0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/palette/ps1n0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/palette/ps1n2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/palette/ps1n2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/palette/ps2n0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/palette/ps2n0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/palette/ps2n2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/palette/ps2n2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ccwn2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ccwn2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ccwn3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ccwn3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cdfn2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cdfn2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cdhn2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cdhn2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cdsn2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cdsn2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cdun2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cdun2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ch1n3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ch1n3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ch2n3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ch2n3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cm0n0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cm0n0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cm7n0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cm7n0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cm9n0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cm9n0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cs3n2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cs3n2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cs3n3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cs3n3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cs5n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cs5n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cs5n3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cs5n3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cs8n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cs8n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cs8n3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cs8n3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ct0n0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ct0n0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ct1n0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ct1n0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cten0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cten0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ctfn0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ctfn0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ctgn0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ctgn0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/cthn0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/cthn0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ctjn0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ctjn0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/ancillary/ctzn0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/ancillary/ctzn0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/background/bgai4a08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/background/bgai4a08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/background/bgai4a16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/background/bgai4a16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/background/bgan6a08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/background/bgan6a08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/background/bgan6a16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/background/bgan6a16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/background/bgbn4a08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/background/bgbn4a08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/background/bggn4a16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/background/bggn4a16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/background/bgwn6a08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/background/bgwn6a08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/background/bgyn6a16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/background/bgyn6a16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xc1n0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xc1n0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xc9n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xc9n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xcrn0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xcrn0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xcsn0g01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xcsn0g01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xd0n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xd0n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xd3n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xd3n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xd9n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xd9n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xdtn0g01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xdtn0g01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xhdn0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xhdn0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xlfn0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xlfn0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xs1n0g01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xs1n0g01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xs2n0g01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xs2n0g01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xs4n0g01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xs4n0g01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/corrupted/xs7n0g01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/corrupted/xs7n0g01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f00n0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f00n0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f00n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f00n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f01n0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f01n0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f01n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f01n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f02n0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f02n0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f02n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f02n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f03n0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f03n0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f03n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f03n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f04n0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f04n0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f04n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f04n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/filtering/f99n0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/filtering/f99n0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi0g01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi0g01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi0g02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi0g02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi3p01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi3p01.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi3p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi3p04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi4a08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi4a08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi4a16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi4a16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi6a08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi6a08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/interlacing/basi6a16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/interlacing/basi6a16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tbbn0g04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tbbn0g04.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tbbn2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tbbn2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tbbn3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tbbn3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tbgn2c16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tbgn2c16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tbgn3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tbgn3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tbrn2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tbrn2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tbwn0g16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tbwn0g16.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tbwn3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tbwn3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tbyn3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tbyn3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tm3n3p02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tm3n3p02.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tp0n0g08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tp0n0g08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tp0n2c08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tp0n2c08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tp0n3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tp0n3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/transparency/tp1n3p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wishstudio/fluid/HEAD/testsuite/pngsuite/transparency/tp1n3p08.png
--------------------------------------------------------------------------------
/testsuite/pngsuite/PngSuite.LICENSE:
--------------------------------------------------------------------------------
1 | PngSuite
2 | --------
3 |
4 | Permission to use, copy, modify and distribute these images for any
5 | purpose and without fee is hereby granted.
6 |
7 |
8 | (c) Willem van Schaik, 1996, 2011
9 |
10 |
--------------------------------------------------------------------------------
/fluid.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 |
10 |
11 | Source Files
12 |
13 |
14 |
15 |
16 | Source Files
17 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------
/testsuite/pngsuite/PngSuite.README:
--------------------------------------------------------------------------------
1 | PNGSUITE
2 | ----------------
3 |
4 | testset for PNG-(de)coders
5 | created by Willem van Schaik
6 | ------------------------------------
7 |
8 | This is a collection of graphics images created to test the png applications
9 | like viewers, converters and editors. All (as far as that is possible)
10 | formats supported by the PNG standard are represented.
11 |
12 | The suite consists of the following files:
13 |
14 | - PngSuite.README - this file
15 | - PngSuite.LICENSE - the PngSuite is freeware
16 | - PngSuite.png - image with PngSuite logo
17 | - PngSuite.tgz - archive of all PNG testfiles
18 | - PngSuite.zip - same in .zip format for PCs
19 |
20 |
21 | --------
22 | (c) Willem van Schaik
23 | willem@schaik.com
24 | Calgary, April 2011
25 |
26 |
--------------------------------------------------------------------------------
/fluid.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.21005.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fluid", "fluid.vcxproj", "{2AFEDE32-E2CA-49C3-841E-B58A52385CBA}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Win32 = Debug|Win32
11 | Release|Win32 = Release|Win32
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {2AFEDE32-E2CA-49C3-841E-B58A52385CBA}.Debug|Win32.ActiveCfg = Debug|Win32
15 | {2AFEDE32-E2CA-49C3-841E-B58A52385CBA}.Debug|Win32.Build.0 = Debug|Win32
16 | {2AFEDE32-E2CA-49C3-841E-B58A52385CBA}.Release|Win32.ActiveCfg = Release|Win32
17 | {2AFEDE32-E2CA-49C3-841E-B58A52385CBA}.Release|Win32.Build.0 = Release|Win32
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/fluid.h:
--------------------------------------------------------------------------------
1 | /*
2 | * FLUID: Fast lightweight universal image decoder
3 | * Copyleft 2013 Xiangyan Sun (wishstudio@gmail.com)
4 | *
5 | * This file is placed in the public domain.
6 | * For details, refer to LICENSE file.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
11 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
12 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
13 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
14 | * OTHER DEALINGS IN THE SOFTWARE.
15 | */
16 |
17 | #pragma once
18 | #ifndef _FLUID_H
19 | #define _FLUID_H
20 |
21 | #ifdef __cplusplus
22 | extern "C" {
23 | #endif
24 |
25 | /*
26 | * fluid_decode: Decode an image
27 | * @data: [in] The image data
28 | * @size: [in] Size of the data in bytes
29 | * @width: [out] Width of the image in pixels
30 | * @height: [out] Height of the image in pixels
31 | * Return: Raw RGBA data, or NULL if failed
32 | */
33 | char *fluid_decode(const char *data, int size, int *width, int *height);
34 |
35 | #ifdef __cplusplus
36 | }
37 | #endif
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Overview
2 | =====
3 |
4 | FLUID (Fast Lightweight Universal Image Decoder) is a very lightweight and easy to integrate (single file) universal image decoder.
5 |
6 | Supported image formats:
7 |
8 | * PNG (All visible chunks except gamma, support interlaced)
9 | * JPEG (JFIF/Baseline, no progressive JPEG)
10 | * PSD (Raw RGB only)
11 |
12 | Currently fluid is perfect for game developments. Support for other popular formats are planned and will be done when I get time (and request).
13 |
14 | Usage
15 | =====
16 | /*
17 | * fluid_decode: Decode an image
18 | * @data: [in] The image data
19 | * @size: [in] Size of the data in bytes
20 | * @width: [out] Width of the image in pixels
21 | * @height: [out] Height of the image in pixels
22 | * Return: Raw RGBA data, or NULL if failed
23 | */
24 | char *fluid_decode(const char *data, int size, int *width, int *height);
25 |
26 | Install
27 | =====
28 | Integrating fluid to your project is very simple. You just grab fluid.c and fluid.h to anywhere in your project, add it to the build system, and you're done.
29 |
30 | Viewer
31 | =====
32 | The project contains a basic image viewer based on fluid. It is used to test the functionality during development and placed here for your interest. To build and run it, use the supplied Visual Studio project.
33 |
34 | License
35 | =====
36 | I decided to place fluid in the [public domain](http://unlicense.org/). So you can do whatever you want with it, without concerning about licensing.
37 |
38 | Contribution
39 | =====
40 | As I want to keep fluid a public domain project, every contributor must agree this. As the method used in [SQLite copyright notice](http://www.sqlite.org/copyright.html), any new contributions must be accompanied with the following statements:
41 |
42 | _The author or authors of this code dedicate any and all copyright interest in this code to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this code under copyright law._
43 |
44 | If you don't do this your contribution won't be merged. Plus if you make changes as an employee, due to the complexity mentioned in the above document I won't accept any contributions.
45 |
46 | However, bug reports and reasonsable feature requests are highly appreciated, as usual.
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 |
11 | [Dd]ebug/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | [Bb]in/
16 | [Oo]bj/
17 |
18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
19 | !packages/*/build/
20 |
21 | # MSTest test Results
22 | [Tt]est[Rr]esult*/
23 | [Bb]uild[Ll]og.*
24 |
25 | *_i.c
26 | *_p.c
27 | *.ilk
28 | *.meta
29 | *.obj
30 | *.pch
31 | *.pdb
32 | *.pgc
33 | *.pgd
34 | *.rsp
35 | *.sbr
36 | *.tlb
37 | *.tli
38 | *.tlh
39 | *.tmp
40 | *.tmp_proj
41 | *.log
42 | *.vspscc
43 | *.vssscc
44 | .builds
45 | *.pidb
46 | *.log
47 | *.scc
48 |
49 | # Visual C++ cache files
50 | ipch/
51 | *.aps
52 | *.ncb
53 | *.opensdf
54 | *.sdf
55 | *.cachefile
56 |
57 | # Visual Studio profiler
58 | *.psess
59 | *.vsp
60 | *.vspx
61 |
62 | # Guidance Automation Toolkit
63 | *.gpState
64 |
65 | # ReSharper is a .NET coding add-in
66 | _ReSharper*/
67 | *.[Rr]e[Ss]harper
68 |
69 | # TeamCity is a build add-in
70 | _TeamCity*
71 |
72 | # DotCover is a Code Coverage Tool
73 | *.dotCover
74 |
75 | # NCrunch
76 | *.ncrunch*
77 | .*crunch*.local.xml
78 |
79 | # Installshield output folder
80 | [Ee]xpress/
81 |
82 | # DocProject is a documentation generator add-in
83 | DocProject/buildhelp/
84 | DocProject/Help/*.HxT
85 | DocProject/Help/*.HxC
86 | DocProject/Help/*.hhc
87 | DocProject/Help/*.hhk
88 | DocProject/Help/*.hhp
89 | DocProject/Help/Html2
90 | DocProject/Help/html
91 |
92 | # Click-Once directory
93 | publish/
94 |
95 | # Publish Web Output
96 | *.Publish.xml
97 | *.pubxml
98 |
99 | # NuGet Packages Directory
100 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
101 | #packages/
102 |
103 | # Windows Azure Build Output
104 | csx
105 | *.build.csdef
106 |
107 | # Windows Store app package directory
108 | AppPackages/
109 |
110 | # Others
111 | sql/
112 | *.Cache
113 | ClientBin/
114 | [Ss]tyle[Cc]op.*
115 | ~$*
116 | *~
117 | *.dbmdl
118 | *.[Pp]ublish.xml
119 | *.pfx
120 | *.publishsettings
121 |
122 | # RIA/Silverlight projects
123 | Generated_Code/
124 |
125 | # Backup & report files from converting an old project file to a newer
126 | # Visual Studio version. Backup files are not needed, because we have git ;-)
127 | _UpgradeReport_Files/
128 | Backup*/
129 | UpgradeLog*.XML
130 | UpgradeLog*.htm
131 |
132 | # SQL Server files
133 | App_Data/*.mdf
134 | App_Data/*.ldf
135 |
136 | # =========================
137 | # Windows detritus
138 | # =========================
139 |
140 | # Windows image file caches
141 | Thumbs.db
142 | ehthumbs.db
143 |
144 | # Folder config file
145 | Desktop.ini
146 |
147 | # Recycle Bin used on file shares
148 | $RECYCLE.BIN/
149 |
150 | # Mac crap
151 | .DS_Store
152 |
--------------------------------------------------------------------------------
/fluid.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 |
14 | {2AFEDE32-E2CA-49C3-841E-B58A52385CBA}
15 | Win32Proj
16 | fluid
17 |
18 |
19 |
20 | Application
21 | true
22 | v120
23 | Unicode
24 |
25 |
26 | Application
27 | false
28 | v120
29 | true
30 | Unicode
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | true
44 |
45 |
46 | false
47 |
48 |
49 |
50 |
51 |
52 | Level3
53 | Disabled
54 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
55 | true
56 |
57 |
58 | Windows
59 | true
60 |
61 |
62 |
63 |
64 | Level3
65 |
66 |
67 | MaxSpeed
68 | true
69 | true
70 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
71 | true
72 | MultiThreaded
73 |
74 |
75 | Windows
76 | true
77 | true
78 | true
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/viewer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * FLUID: Fast lightweight universal image decoder
3 | * Copyleft 2013 Xiangyan Sun (wishstudio@gmail.com)
4 | *
5 | * This file is placed in the public domain.
6 | * For details, refer to LICENSE file.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
11 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
12 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
13 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
14 | * OTHER DEALINGS IN THE SOFTWARE.
15 | */
16 |
17 | #include
18 | #include
19 |
20 | #include "fluid.h"
21 |
22 | /* Windows manifest */
23 | #pragma comment(linker,"\"/manifestdependency:type='win32' \
24 | name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
25 | processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
26 |
27 | /* Control definitions */
28 | #define IDC_BROWSE_BUTTON 101
29 |
30 | HBITMAP bitmap;
31 | int bitmapWidth, bitmapHeight;
32 |
33 | static char *readFile(LPWSTR fileName, int *fileSize)
34 | {
35 | HANDLE hFile = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
36 | if (hFile == INVALID_HANDLE_VALUE)
37 | return nullptr;
38 |
39 | LARGE_INTEGER size;
40 | if (GetFileSizeEx(hFile, &size) == 0)
41 | {
42 | CloseHandle(hFile);
43 | return nullptr;
44 | }
45 |
46 | (*fileSize) = (int) size.QuadPart;
47 | char *content = (char *) malloc(*fileSize);
48 | if (content == nullptr)
49 | {
50 | CloseHandle(hFile);
51 | return nullptr;
52 | }
53 | DWORD bytesRead;
54 | if (!ReadFile(hFile, content, (*fileSize), &bytesRead, nullptr))
55 | {
56 | free(content);
57 | content = nullptr;
58 | }
59 | CloseHandle(hFile);
60 | return content;
61 | }
62 |
63 | static void loadImage(HWND hWnd, LPWSTR fileName)
64 | {
65 | char *data;
66 | int size;
67 | data = readFile(fileName, &size);
68 | if (data == nullptr)
69 | {
70 | MessageBoxW(hWnd, L"Cannot read file content!", L"Critical", MB_ICONERROR | MB_OK);
71 | return;
72 | }
73 |
74 | int width, height;
75 | char *decoded = fluid_decode(data, size, &width, &height);
76 | free(data);
77 | if (decoded == nullptr)
78 | {
79 | MessageBoxW(hWnd, L"Decode image file failed.", L"Critical", MB_ICONERROR | MB_OK);
80 | return;
81 | }
82 |
83 | /* ARGB -> BGRA, Premultiply alpha */
84 | unsigned char *r = (unsigned char *) decoded;
85 | for (int i = 0; i < height; i++)
86 | for (int j = 0; j < width; j++)
87 | {
88 | unsigned char t = r[0];
89 | r[0] = r[2];
90 | r[2] = t;
91 |
92 | /* Premultiply (for display) */
93 | r[0] = r[0] * r[3] / 255 + (255 - r[3]);
94 | r[1] = r[1] * r[3] / 255 + (255 - r[3]);
95 | r[2] = r[2] * r[3] / 255 + (255 - r[3]);
96 |
97 | r += 4;
98 | }
99 |
100 | if (bitmap)
101 | DeleteObject(bitmap);
102 | bitmapWidth = width;
103 | bitmapHeight = height;
104 |
105 | BITMAPINFO bmi;
106 | bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
107 | bmi.bmiHeader.biWidth = width;
108 | bmi.bmiHeader.biHeight = -height;
109 | bmi.bmiHeader.biPlanes = 1;
110 | bmi.bmiHeader.biBitCount = 32;
111 | bmi.bmiHeader.biCompression = BI_RGB;
112 | bmi.bmiHeader.biSizeImage = width * height * 4;
113 | HDC hdc = GetDC(hWnd);
114 | bitmap = CreateDIBitmap(hdc, &bmi.bmiHeader, CBM_INIT, decoded, &bmi, DIB_RGB_COLORS);
115 | ReleaseDC(hWnd, hdc);
116 | SendMessageW(hWnd, WM_PAINT, 0, 0);
117 | free(decoded);
118 | }
119 |
120 | static void openFile(HWND hWnd)
121 | {
122 | HRESULT hr;
123 | IFileDialog *pFileDialog = nullptr;
124 | IShellItem *pShellItem = nullptr;
125 | PWSTR pFilePath = nullptr;
126 | DWORD dwFlags;
127 |
128 | /* Create FileOpenDialog */
129 | hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileDialog));
130 | if (FAILED(hr))
131 | goto FINISH;
132 |
133 | /* Get options */
134 | hr = pFileDialog->GetOptions(&dwFlags);
135 | if (FAILED(hr))
136 | goto FINISH;
137 |
138 | /* Get shell items only for file system items */
139 | hr = pFileDialog->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
140 | if (FAILED(hr))
141 | goto FINISH;
142 |
143 | /* Set file types */
144 | COMDLG_FILTERSPEC fileTypes[] =
145 | {
146 | { L"All supported images", L"*.png;*.jpg;*.jpeg;*.psd" },
147 | };
148 | hr = pFileDialog->SetFileTypes(ARRAYSIZE(fileTypes), fileTypes);
149 | if (FAILED(hr))
150 | goto FINISH;
151 |
152 | /* Show dialog */
153 | hr = pFileDialog->Show(hWnd);
154 | if (FAILED(hr))
155 | goto FINISH;
156 |
157 | hr = pFileDialog->GetResult(&pShellItem);
158 | if (FAILED(hr))
159 | goto FINISH;
160 |
161 | hr = pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pFilePath);
162 | if (FAILED(hr))
163 | goto FINISH;
164 |
165 | loadImage(hWnd, pFilePath);
166 |
167 | FINISH:
168 | if (pFilePath)
169 | CoTaskMemFree(pFilePath);
170 | if (pShellItem)
171 | pShellItem->Release();
172 | if (pFileDialog)
173 | pFileDialog->Release();
174 | }
175 |
176 | static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
177 | {
178 | switch (message)
179 | {
180 | case WM_DESTROY:
181 | PostQuitMessage(0);
182 | return 1;
183 |
184 | case WM_COMMAND:
185 | switch (LOWORD(wParam))
186 | {
187 | case IDC_BROWSE_BUTTON:
188 | openFile(hWnd);
189 | break;
190 | }
191 | break;
192 |
193 | case WM_PAINT:
194 | HDC dc = GetDC(hWnd);
195 | HDC bitmapDC = CreateCompatibleDC(dc);
196 | SelectObject(bitmapDC, bitmap);
197 | StretchBlt(dc, 10, 100, bitmapWidth, bitmapHeight, bitmapDC, 0, 0, bitmapWidth, bitmapHeight, SRCCOPY);
198 | DeleteDC(bitmapDC);
199 | ReleaseDC(hWnd, dc);
200 | break;
201 | }
202 | return DefWindowProcW(hWnd, message, wParam, lParam);
203 | }
204 |
205 | int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
206 | {
207 | CoInitialize(nullptr);
208 |
209 | WNDCLASSEXW wcex;
210 | wcex.cbSize = sizeof(WNDCLASSEX);
211 | wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
212 | wcex.lpfnWndProc = WndProc;
213 | wcex.cbClsExtra = 0;
214 | wcex.cbWndExtra = 0;
215 | wcex.hInstance = hInstance;
216 | wcex.hIcon = 0;
217 | wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
218 | wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
219 | wcex.lpszMenuName = nullptr;
220 | wcex.lpszClassName = L"fluid_viewer";
221 | wcex.hIconSm = 0;
222 | RegisterClassExW(&wcex);
223 |
224 | /* Create the window */
225 | HWND windowHandle = CreateWindowExW(0, L"fluid_viewer", L"",
226 | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
227 | CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, hInstance, nullptr);
228 |
229 | if (windowHandle == nullptr)
230 | return 0;
231 |
232 | /* Show the window */
233 | ShowWindow(windowHandle, SW_SHOW);
234 | UpdateWindow(windowHandle);
235 |
236 | /* Set window size */
237 | SetWindowLongW(windowHandle, GWL_STYLE, GetWindowLong(windowHandle, GWL_STYLE) & ~(WS_POPUP | WS_EX_TOPMOST));
238 |
239 | RECT r;
240 | GetWindowRect(windowHandle, &r);
241 | /* Convert client size to window size */
242 | RECT rect;
243 | rect.top = 0;
244 | rect.left = 0;
245 | rect.right = 1024;
246 | rect.bottom = 768;
247 | AdjustWindowRect(&rect, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, FALSE);
248 |
249 | MoveWindow(windowHandle, r.left, r.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
250 |
251 | /* Add controls */
252 | CreateWindowExW(0, L"BUTTON", L"Browse file...",
253 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
254 | 20, 20, 100, 26,
255 | windowHandle, (HMENU) IDC_BROWSE_BUTTON, hInstance, nullptr);
256 |
257 | /* Message loop */
258 | MSG msg;
259 | ZeroMemory(&msg, sizeof msg);
260 | while (GetMessageW(&msg, nullptr, 0, 0))
261 | {
262 | TranslateMessage(&msg);
263 | DispatchMessageW(&msg);
264 | if (msg.message == WM_QUIT)
265 | break;
266 | }
267 | if (bitmap)
268 | DeleteObject(bitmap);
269 |
270 | CoUninitialize();
271 | return 0;
272 | }
273 |
--------------------------------------------------------------------------------
/fluid.c:
--------------------------------------------------------------------------------
1 | /*
2 | * FLUID: Fast lightweight universal image decoder
3 | * Copyleft 2013 Xiangyan Sun (wishstudio@gmail.com)
4 | *
5 | * This file is placed in the public domain.
6 | * For details, refer to LICENSE file.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
11 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
12 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
13 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
14 | * OTHER DEALINGS IN THE SOFTWARE.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 | #include "fluid.h"
23 |
24 | #define INLINE __inline
25 |
26 | /* General helpers */
27 | #define LOBYTE(x) ((unsigned char) (x) & 0x0F)
28 | #define HIBYTE(x) ((unsigned char) (x) >> 4)
29 | #define LOINT(x) ((unsigned int) (x) & 0xFFFF)
30 | #define HIINT(x) ((unsigned int) (x) >> 16)
31 | #define BITMASK(len) ((1 << (len)) - 1)
32 | #define EXTRACT_UINT8(data, x) \
33 | { x = (uint8_t)*(data)++; }
34 | #define GET_UINT16_BIG(data) (((data)[0] << 8) | (data)[1])
35 | #define EXTRACT_UINT16_BIG(data, x) \
36 | { x = GET_UINT16_BIG(data); (data) += 2; }
37 | #define EXTRACT_UINT16_LITTLE(data, x) \
38 | { x = *(uint16_t *)(data); (data) += 2; }
39 | #define EXTRACT_UINT24_BIG(data, x) \
40 | { x = ((data)[0] << 16) | ((data)[1] << 8) | (data)[2]; (data) += 3; }
41 | #define EXTRACT_UINT32_BIG(data, x) \
42 | { x = ((data)[0] << 24) | ((data)[1] << 16) | ((data)[2] << 8) | (data)[3]; (data) += 4; }
43 | #define EXTRACT_UINT32_LITTLE(data, x) \
44 | { x = *(uint32_t *)(data); (data) += 4; }
45 |
46 | static int extract_bits_big(const unsigned char **data, int *bit, int *size, int bits)
47 | {
48 | int x;
49 | if (*bit == 8)
50 | {
51 | *bit = 0;
52 | (*data)++, (*size)--;
53 | }
54 | if (*bit + bits <= 8)
55 | {
56 | x = ((*data)[0] >> (8 - (*bit + bits))) & BITMASK(bits);
57 | *bit += bits;
58 | }
59 | else if (*bit + bits <= 16)
60 | {
61 | x = ((((*data)[0] << 8) | (*data)[1]) >> (16 - (*bit + bits))) & BITMASK(bits);
62 | *bit += bits - 8;
63 | (*data)++, (*size)--;
64 | }
65 | else if (*bit + bits <= 24)
66 | {
67 | x = ((((*data)[0] << 16) | (*data)[1] << 8 | (*data)[2]) >> (24 - (*bit + bits))) & BITMASK(bits);
68 | *bit += bits - 16;
69 | (*data) += 2, (*size) -= 2;
70 | }
71 | return x;
72 | }
73 |
74 | static int extract_bits_little(const unsigned char **data, int *bit, int *size, int bits)
75 | {
76 | int x;
77 | if (*bit == 8)
78 | {
79 | *bit = 0;
80 | (*data)++, (*size)--;
81 | }
82 | if (*bit + bits <= 8)
83 | {
84 | x = ((*data)[0] >> *bit) & BITMASK(bits);
85 | *bit += bits;
86 | }
87 | else if (*bit + bits <= 16)
88 | {
89 | x = ((((*data)[1] << 8) | (*data)[0]) >> *bit) & BITMASK(bits);
90 | *bit += bits - 8;
91 | (*data)++, (*size)--;
92 | }
93 | else if (*bit + bits <= 24)
94 | {
95 | x = ((((*data)[2] << 16) | (*data)[1] << 8 | (*data)[0]) >> *bit) & BITMASK(bits);
96 | *bit += bits - 16;
97 | (*data) += 2, (*size) -= 2;
98 | }
99 | return x;
100 | }
101 |
102 | /* Rescale sample from depth-bit to 8-bit */
103 | static INLINE unsigned int sample_rescale(unsigned int depth, unsigned int sample)
104 | {
105 | if (depth >= 8) /* Down sample */
106 | return sample >> (depth - 8);
107 | else /* Up sample */
108 | {
109 | if (sample & 1)
110 | return (sample << (8 - depth)) | BITMASK(8 - depth);
111 | else
112 | return sample << (8 - depth);
113 | }
114 | }
115 |
116 | static INLINE int color_clamp(int c)
117 | {
118 | if ((unsigned int) c > 255)
119 | {
120 | if (c < 0)
121 | return 0;
122 | return 255;
123 | }
124 | return c;
125 | }
126 |
127 | /* Zlib deflate decoder */
128 | #define DEFLATE_ALPHABET_SIZE 288
129 | #define DEFLATE_HUFFMAN_MAX_CODELEN 15
130 | #define DEFLATE_HUFFMAN_TREE_SIZE (1 << DEFLATE_HUFFMAN_MAX_CODELEN)
131 | typedef struct
132 | {
133 | int codelen[DEFLATE_ALPHABET_SIZE], codelen_count[DEFLATE_HUFFMAN_MAX_CODELEN + 1], next_code[DEFLATE_HUFFMAN_MAX_CODELEN + 1];
134 | int hm_lit[DEFLATE_HUFFMAN_TREE_SIZE], hm_dist[DEFLATE_HUFFMAN_TREE_SIZE];
135 | /* Packed huffman data:
136 | * High 16 bits: Huffman code length
137 | * Low 16 bits: Original alphabet
138 | */
139 | } DEFLATE_status;
140 |
141 | #define HC_VAL(len, alphabet) (((len) << 16) | (alphabet))
142 | #define HC_ISVALID(x) ((x) != -1)
143 | #define HC_LEN(x) HIINT(x)
144 | #define HC_ALPHABET(x) LOINT(x)
145 |
146 | static const int HCLEN_ORDER[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
147 | static const int LEN_BASE[29] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 };
148 | static const int LEN_BITS[29] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
149 | static const int DIST_BASE[30] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
150 | static const int DIST_BITS[30] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 };
151 |
152 | static int zlib_huffman_code(DEFLATE_status *status, int n, int *dest)
153 | {
154 | int i, code;
155 | memset(status->codelen_count, 0, sizeof(status->codelen_count));
156 | for (i = 0; i < (1 << DEFLATE_HUFFMAN_MAX_CODELEN); i++)
157 | dest[i] = -1;
158 |
159 | for (i = 0; i < n; i++)
160 | if (status->codelen[i] > 0)
161 | status->codelen_count[status->codelen[i]]++;
162 | status->next_code[0] = 0;
163 | for (i = 1; i <= DEFLATE_HUFFMAN_MAX_CODELEN; i++)
164 | status->next_code[i] = (status->next_code[i - 1] + status->codelen_count[i - 1]) << 1;
165 | for (i = 0; i < n; i++)
166 | if (status->codelen[i] > 0)
167 | {
168 | code = status->next_code[status->codelen[i]]++;
169 | if (code >= (1 << status->codelen[i])) /* Too much codepoints for a given length */
170 | return 0;
171 | dest[code] = HC_VAL(status->codelen[i], i);
172 | }
173 | return 1;
174 | }
175 |
176 | /* Byte order:
177 | * Data elements are packed into bytes in order of
178 | * increasing bit number within the byte, i.e., starting
179 | * with the least-significant bit of the byte.
180 | * Data elements other than Huffman codes are packed
181 | * starting with the least-significant bit of the data
182 | * element.
183 | * Huffman codes are packed starting with the most-
184 | * significant bit of the code.
185 | */
186 | static int zlib_extract_huffman_code(const unsigned char **data, int *bit, int *size, int *huffman, int *code)
187 | {
188 | int i, b, c;
189 | for (c = 0, i = 0;;)
190 | {
191 | b = extract_bits_little(data, bit, size, 1);
192 | c = (c << 1) | b;
193 | if (++i > DEFLATE_HUFFMAN_MAX_CODELEN)
194 | return 0;
195 | if (HC_ISVALID(huffman[c]) && HC_LEN(huffman[c]) == i)
196 | {
197 | *code = HC_ALPHABET(huffman[c]);
198 | return 1;
199 | }
200 | }
201 | }
202 |
203 | static int zlib_read_huffman_codelen(const unsigned char **data, int *bit, int *size, int count, int *hm, int *codelen)
204 | {
205 | int i, j, lit;
206 | for (i = 0; i < count;)
207 | {
208 | if (*size <= 4)
209 | return 0;
210 | if (!zlib_extract_huffman_code(data, bit, size, hm, &lit) || lit > 18)
211 | return 0;
212 | if (lit < 16) /* Literal */
213 | codelen[i++] = lit;
214 | else if (lit == 16) /* Repeat last */
215 | {
216 | if (i == 0)
217 | return 0;
218 | j = j = 3 + extract_bits_little(data, bit, size, 2);
219 | if (i + j > count)
220 | return 0;
221 | for (; j > 0; i++, j--)
222 | codelen[i] = codelen[i - 1];
223 | }
224 | else if (lit == 17) /* Repeat zero */
225 | {
226 | j = 3 + extract_bits_little(data, bit, size, 3);
227 | if (i + j > count)
228 | return 0;
229 | for (; j > 0; j--)
230 | codelen[i++] = 0;
231 | }
232 | else /* Repeat zero */
233 | {
234 | j = 11 + extract_bits_little(data, bit, size, 7);
235 | if (i + j > count)
236 | return 0;
237 | for (; j > 0; j--)
238 | codelen[i++] = 0;
239 | }
240 | }
241 | return 1;
242 | }
243 |
244 | static int zlib_deflate_decode(const unsigned char *data, int size, unsigned char *raw, int rawsize)
245 | {
246 | int cmf, flg;
247 | unsigned char *current; /* Output pointer */
248 | unsigned char *cp; /* Copy pointer */
249 | unsigned int bit; /* Current bit of *data (0 - 8) */
250 |
251 | int bfinal, btype;
252 | int hlit, hdist, hclen;
253 | int i;
254 | int lit, dist, len, nlen;
255 |
256 | DEFLATE_status status;
257 |
258 | if (size < 6)
259 | return 0;
260 | /* Zlib header */
261 | size -= 2;
262 | EXTRACT_UINT8(data, cmf);
263 | EXTRACT_UINT8(data, flg);
264 | if (LOBYTE(cmf) != 8) /* Deflate */
265 | return 0;
266 | /* TODO: Check FLG */
267 | current = raw;
268 | bit = 0;
269 | bfinal = 0;
270 | while (current < raw + rawsize)
271 | {
272 | if (bfinal == 1) /* From last block */
273 | return 0;
274 | if (size <= 4)
275 | return 0;
276 | bfinal = extract_bits_little(&data, &bit, &size, 1);
277 | btype = extract_bits_little(&data, &bit, &size, 2);
278 | if (btype == 3)
279 | return 0;
280 |
281 | if (btype == 0) /* Non-compressed */
282 | {
283 | if (bit > 0)
284 | data++, bit = 0;
285 | if (size <= 4)
286 | return 0;
287 | EXTRACT_UINT16_LITTLE(data, len);
288 | EXTRACT_UINT16_LITTLE(data, nlen);
289 | size -= 4;
290 | if (size < 4 + len)
291 | return 0;
292 | size -= len;
293 | if ((len | nlen) != 0xFFFF)
294 | return 0;
295 | for (i = 0; i < len; i++)
296 | *current++ = *data++;
297 | }
298 | else /* Compressed */
299 | {
300 | /* Construct huffman code */
301 | if (btype == 1) /* Fixed huffman code */
302 | {
303 | for (i = 0; i < 144; i++)
304 | status.codelen[i] = 8;
305 | for (i = 144; i < 256; i++)
306 | status.codelen[i] = 9;
307 | for (i = 256; i < 280; i++)
308 | status.codelen[i] = 7;
309 | for (i = 280; i < 288; i++)
310 | status.codelen[i] = 8;
311 | zlib_huffman_code(&status, 288, status.hm_lit);
312 | for (i = 0; i < 32; i++)
313 | status.codelen[i] = 5;
314 | zlib_huffman_code(&status, 32, status.hm_dist);
315 | }
316 | else /* Dynamic huffman code */
317 | {
318 | hlit = 257 + extract_bits_little(&data, &bit, &size, 5);
319 | hdist = 1 + extract_bits_little(&data, &bit, &size, 5);
320 | hclen = 4 + extract_bits_little(&data, &bit, &size, 4);
321 | /* Generate length descriptor huffman code */
322 | for (i = 0; i < 19; i++)
323 | status.codelen[i] = 0;
324 | for (i = 0; i < hclen; i++)
325 | {
326 | if (size <= 4)
327 | return 0;
328 | status.codelen[HCLEN_ORDER[i]] = extract_bits_little(&data, &bit, &size, 3);
329 | }
330 | if (!zlib_huffman_code(&status, 19, status.hm_dist))
331 | return 0;
332 | /* Generate literal/length huffman code */
333 | if (!zlib_read_huffman_codelen(&data, &bit, &size, hlit, status.hm_dist, status.codelen))
334 | return 0;
335 | if (!zlib_huffman_code(&status, hlit, status.hm_lit))
336 | return 0;
337 | /* Generate distance huffman code */
338 | if (!zlib_read_huffman_codelen(&data, &bit, &size, hdist, status.hm_dist, status.codelen))
339 | return 0;
340 | if (!zlib_huffman_code(&status, hdist, status.hm_dist))
341 | return 0;
342 | }
343 | /* Actual decompressing */
344 | for (;;)
345 | {
346 | /* Extract literal/length */
347 | if (size <= 4)
348 | return 0;
349 | if (!zlib_extract_huffman_code(&data, &bit, &size, status.hm_lit, &lit) || lit > 285)
350 | return 0;
351 | if (lit == 256) /* End of block */
352 | break;
353 | if (lit < 256) /* Literal data */
354 | {
355 | if (current + 1 > raw + rawsize)
356 | return 0;
357 | *current++ = lit;
358 | }
359 | else /* Distance/length pair */
360 | {
361 | len = LEN_BASE[lit - 257] + extract_bits_little(&data, &bit, &size, LEN_BITS[lit - 257]);
362 | /* Extract distance */
363 | if (size <= 4)
364 | return 0;
365 | if (!zlib_extract_huffman_code(&data, &bit, &size, status.hm_dist, &lit))
366 | return 0;
367 | if (lit > 29) /* Invalid code point */
368 | return 0;
369 | dist = DIST_BASE[lit] + extract_bits_little(&data, &bit, &size, DIST_BITS[lit]);
370 | /* Copy data */
371 | cp = current - dist;
372 | if (cp < raw || current + len > raw + rawsize)
373 | return 0;
374 | for (i = 0; i < len; i++)
375 | *current++ = *cp++;
376 | }
377 | }
378 | }
379 | }
380 | return 1;
381 | }
382 |
383 | /* PNG decoder */
384 | typedef struct
385 | {
386 | int width, height;
387 | int depth, color_type;
388 | int compression_method, filter_method, interlace_method;
389 | int sample_per_pixel;
390 | int zlen, rawlen, imagelen;
391 | unsigned char *zraw, *raw, *defiltered, *interlaced, *image;
392 | /* Palette */
393 | int palette_count;
394 | const unsigned char *palette;
395 | /* Interlacing */
396 | int adam7_pass_width[8], adam7_pass_height[8];
397 | /* Transparency */
398 | int transparency_count;
399 | const unsigned char *transparency;
400 | } PNG_status;
401 |
402 | static int png_extract_chunk(const unsigned char **data, int *size, const unsigned char **chunk_type, const unsigned char **chunk_data, int *chunk_len)
403 | {
404 | if (*size < 12)
405 | return 0;
406 | EXTRACT_UINT32_BIG(*data, *chunk_len);
407 | if (*size < 12 + *chunk_len)
408 | return 0;
409 | *size -= 12 + *chunk_len;
410 | *chunk_type = *data;
411 | *data += 4;
412 | *chunk_data = *data;
413 | *data += *chunk_len;
414 | *data += 4; /* CRC */
415 | return 1;
416 | }
417 |
418 | static int png_extract_data_size(PNG_status *status, const unsigned char *data, int size, const unsigned char *ctype, const unsigned char *cdata, int clen)
419 | {
420 | status->zlen = 0;
421 | do
422 | {
423 | status->zlen += clen;
424 | if (!png_extract_chunk(&data, &size, &ctype, &cdata, &clen))
425 | return 0;
426 | } while (ctype[0] == 'I' && ctype[1] == 'D' && ctype[2] == 'A' && ctype[3] == 'T');
427 | return 1;
428 | }
429 |
430 | static INLINE int png_get_scanline_len(int width, int depth, int sample_per_pixel)
431 | {
432 | int sample_per_byte;
433 | if (width == 0)
434 | return 0;
435 | if (depth < 8)
436 | {
437 | sample_per_byte = 8 / depth;
438 | return 1 + (width * sample_per_pixel + sample_per_byte - 1) / sample_per_byte;
439 | }
440 | else
441 | return 1 + width * sample_per_pixel * depth / 8;
442 | }
443 |
444 | static INLINE int png_paeth_predictor(int a, int b, int c)
445 | {
446 | int p, pa, pb, pc;
447 | p = a + b - c;
448 | pa = abs(p - a);
449 | pb = abs(p - b);
450 | pc = abs(p - c);
451 | if (pa <= pb && pa <= pc)
452 | return a;
453 | else if (pb <= pc)
454 | return b;
455 | else
456 | return c;
457 | }
458 |
459 | static void png_defilter(const unsigned char *data, unsigned char *image, int width, int height, int depth, int sample_per_pixel)
460 | {
461 | unsigned char type;
462 | int i, j;
463 | int ap, bp; /* Byte offset of a, b */
464 | unsigned int a, b, c, k;
465 | int scanline_len;
466 |
467 | scanline_len = png_get_scanline_len(width, depth, sample_per_pixel);
468 |
469 | if (depth < 8)
470 | ap = -1;
471 | else
472 | ap = -(depth / 8 * sample_per_pixel);
473 | bp = -scanline_len;
474 |
475 | for (i = 0; i < height; i++)
476 | {
477 | EXTRACT_UINT8(data, type);
478 | *image++ = type;
479 | if (type == 0) /* None */
480 | {
481 | for (j = 1; j < scanline_len; j++)
482 | {
483 | EXTRACT_UINT8(data, k);
484 | *image++ = k;
485 | }
486 | }
487 | else if (type == 1) /* Sub */
488 | {
489 | for (j = 1; j < scanline_len; j++)
490 | {
491 | a = (j + ap > 0) ? image[ap] : 0;
492 | EXTRACT_UINT8(data, k);
493 | *image++ = k + a;
494 | }
495 | }
496 | else if (type == 2) /* Up */
497 | {
498 | for (j = 1; j < scanline_len; j++)
499 | {
500 | b = (i > 0) ? image[bp] : 0;
501 | EXTRACT_UINT8(data, k);
502 | *image++ = k + b;
503 | }
504 | }
505 | else if (type == 3) /* Average */
506 | {
507 | for (j = 1; j < scanline_len; j++)
508 | {
509 | a = (j + ap > 0) ? image[ap] : 0;
510 | b = (i > 0) ? image[bp] : 0;
511 | EXTRACT_UINT8(data, k);
512 | *image++ = k + (a + b) / 2;
513 | }
514 | }
515 | else if (type == 4) /* Paeth */
516 | {
517 | for (j = 1; j < scanline_len; j++)
518 | {
519 | a = (j + ap > 0) ? image[ap] : 0;
520 | b = (i > 0) ? image[bp] : 0;
521 | c = (i > 0 && j + ap > 0) ? image[ap + bp] : 0;
522 | EXTRACT_UINT8(data, k);
523 | *image++ = k + png_paeth_predictor(a, b, c);
524 | }
525 | }
526 | }
527 | }
528 |
529 | /*
530 | * Adam7 passes:
531 | *
532 | * 1 6 4 6 2 6 4 6
533 | * 7 7 7 7 7 7 7 7
534 | * 5 6 5 6 5 6 5 6
535 | * 7 7 7 7 7 7 7 7
536 | * 3 6 4 6 3 6 4 6
537 | * 7 7 7 7 7 7 7 7
538 | * 5 6 5 6 5 6 5 6
539 | * 7 7 7 7 7 7 7 7
540 | */
541 | static const int adam7_horizontal_start[8] = { 0, 1, 5, 1, 3, 1, 2, 1 };
542 | static const int adam7_vertical_start[8] = { 0, 1, 1, 5, 1, 3, 1, 2 };
543 | static const int adam7_horizontal_delta[8] = { 0, 8, 8, 4, 4, 2, 2, 1 };
544 | static const int adam7_vertical_delta[8] = { 0, 8, 8, 8, 4, 4, 2, 2 };
545 | static void png_extract_adam7_extent(PNG_status *status)
546 | {
547 | int i;
548 | for (i = 1; i <= 7; i++)
549 | {
550 | status->adam7_pass_width[i] = (status->width + adam7_horizontal_delta[i] - adam7_horizontal_start[i]) / adam7_horizontal_delta[i];
551 | status->adam7_pass_height[i] = (status->height + adam7_vertical_delta[i] - adam7_vertical_start[i]) / adam7_vertical_delta[i];
552 | }
553 | }
554 |
555 | static void png_deinterlace_adam7(PNG_status *status, const unsigned char *data, unsigned char *image)
556 | {
557 | int pass, i, j;
558 | for (pass = 1; pass <= 7; pass++)
559 | for (i = adam7_vertical_start[pass] - 1; i < status->height; i += adam7_vertical_delta[pass])
560 | for (j = adam7_horizontal_start[pass] - 1; j < status->width; j += adam7_horizontal_delta[pass])
561 | {
562 | *(uint32_t *) (image + (status->width * i + j) * 4) = *(uint32_t *) data;
563 | data += 4;
564 | }
565 | }
566 |
567 | static int png_extract_pixels(PNG_status *status, const unsigned char *data, unsigned char *dest, int width, int height, int size)
568 | {
569 | unsigned char *image;
570 | unsigned int bit;
571 | int i, j, index;
572 | unsigned int sampler, sampleg, sampleb;
573 | int tr, tg, tb;
574 |
575 | image = dest;
576 | bit = 0;
577 | if (status->color_type == 0) /* Grayscale */
578 | {
579 | if (status->transparency)
580 | tg = GET_UINT16_BIG(status->transparency);
581 | for (i = 0; i < height; i++)
582 | {
583 | data++; /* Filter type byte */
584 | for (j = 0; j < width; j++)
585 | {
586 | sampleg = extract_bits_big(&data, &bit, &size, status->depth);
587 | image[0] = image[1] = image[2] = sample_rescale(status->depth, sampleg);
588 | image[3] = (status->transparency && sampleg == tg) ? 0 : 0xFF;
589 | image += 4;
590 | }
591 | if (bit > 0) /* Skip remaining bits */
592 | data++, bit = 0;
593 | }
594 | }
595 | else if (status->color_type == 2) /* Truecolor */
596 | {
597 | if (status->transparency)
598 | {
599 | tr = GET_UINT16_BIG(status->transparency);
600 | tg = GET_UINT16_BIG(status->transparency + 2);
601 | tb = GET_UINT16_BIG(status->transparency + 4);
602 | }
603 | for (i = 0; i < height; i++)
604 | {
605 | data++; /* Filter type byte */
606 | for (j = 0; j < width; j++)
607 | {
608 | sampler = extract_bits_big(&data, &bit, &size, status->depth);
609 | sampleg = extract_bits_big(&data, &bit, &size, status->depth);
610 | sampleb = extract_bits_big(&data, &bit, &size, status->depth);
611 | image[0] = sample_rescale(status->depth, sampler);
612 | image[1] = sample_rescale(status->depth, sampleg);
613 | image[2] = sample_rescale(status->depth, sampleb);
614 | image[3] = (status->transparency && sampler == tr && sampleg == tg && sampleb == tb) ? 0 : 0xFF;
615 | image += 4;
616 | }
617 | if (bit > 0) /* Skip remaining bits */
618 | data++, bit = 0;
619 | }
620 | }
621 | else if (status->color_type == 3) /* Indexed */
622 | {
623 | for (i = 0; i < height; i++)
624 | {
625 | data++; /* Filter type byte */
626 | for (j = 0; j < width; j++)
627 | {
628 | index = extract_bits_big(&data, &bit, &size, status->depth);
629 | if (index >= status->palette_count)
630 | return 0;
631 | image[0] = status->palette[index * 3 + 0];
632 | image[1] = status->palette[index * 3 + 1];
633 | image[2] = status->palette[index * 3 + 2];
634 | image[3] = (status->transparency && index < status->transparency_count) ? status->transparency[index] : 0xFF;
635 | image += 4;
636 | }
637 | if (bit > 0) /* Skip remaining bits */
638 | data++, bit = 0;
639 | }
640 | }
641 | else if (status->color_type == 4) /* Gray with alpha */
642 | {
643 | for (i = 0; i < height; i++)
644 | {
645 | data++; /* Filter type byte */
646 | for (j = 0; j < width; j++)
647 | {
648 | image[0] = image[1] = image[2] = sample_rescale(status->depth, extract_bits_big(&data, &bit, &size, status->depth));
649 | image[3] = sample_rescale(status->depth, extract_bits_big(&data, &bit, &size, status->depth));
650 | image += 4;
651 | }
652 | if (bit > 0) /* Skip remaining bits */
653 | data++, bit = 0;
654 | }
655 | }
656 | else if (status->color_type == 6) /* Truecolor with alpha */
657 | {
658 | for (i = 0; i < height; i++)
659 | {
660 | data++; /* Filter type byte */
661 | for (j = 0; j < width; j++)
662 | {
663 | image[0] = sample_rescale(status->depth, extract_bits_big(&data, &bit, &size, status->depth));
664 | image[1] = sample_rescale(status->depth, extract_bits_big(&data, &bit, &size, status->depth));
665 | image[2] = sample_rescale(status->depth, extract_bits_big(&data, &bit, &size, status->depth));
666 | image[3] = sample_rescale(status->depth, extract_bits_big(&data, &bit, &size, status->depth));
667 | image += 4;
668 | }
669 | if (bit > 0) /* Skip remaining bits */
670 | data++, bit = 0;
671 | }
672 | }
673 | return 1;
674 | }
675 |
676 | static char *png_decode(const unsigned char *data, int size, int *width, int *height)
677 | {
678 | PNG_status status;
679 | const unsigned char *ctype, *cdata;
680 | unsigned char *zraw;
681 | int clen, isize, i, j, k;
682 |
683 | status.zraw = NULL;
684 | status.raw = NULL;
685 | status.defiltered = NULL;
686 | status.interlaced = NULL;
687 | status.image = NULL;
688 | status.palette = NULL;
689 | status.transparency = NULL;
690 |
691 | /* Dealing with IHDR chunk */
692 | if (png_extract_chunk(&data, &size, &ctype, &cdata, &clen) &&
693 | clen == 13 &&
694 | ctype[0] == 'I' && ctype[1] == 'H' && ctype[2] == 'D' && ctype[3] == 'R')
695 | {
696 | EXTRACT_UINT32_BIG(cdata, status.width);
697 | EXTRACT_UINT32_BIG(cdata, status.height);
698 | EXTRACT_UINT8(cdata, status.depth);
699 | EXTRACT_UINT8(cdata, status.color_type);
700 | EXTRACT_UINT8(cdata, status.compression_method);
701 | EXTRACT_UINT8(cdata, status.filter_method);
702 | EXTRACT_UINT8(cdata, status.interlace_method);
703 |
704 | if (status.width < 0 || status.height < 0)
705 | return 0;
706 | *width = status.width;
707 | *height = status.height;
708 |
709 | /* Initialization and basic checking */
710 | if (status.color_type == 0) /* Grayscale */
711 | {
712 | status.sample_per_pixel = 1;
713 | if (status.depth != 1 && status.depth != 2 && status.depth != 4 && status.depth != 8 && status.depth != 16)
714 | goto FINISH;
715 | }
716 | else if (status.color_type == 2) /* Truecolor */
717 | {
718 | status.sample_per_pixel = 3;
719 | if (status.depth != 8 && status.depth != 16)
720 | goto FINISH;
721 | }
722 | else if (status.color_type == 3) /* Indexed */
723 | {
724 | status.sample_per_pixel = 1;
725 | if (status.depth != 1 && status.depth != 2 && status.depth != 4 && status.depth != 8)
726 | goto FINISH;
727 | }
728 | else if (status.color_type == 4) /* Gray with alpha */
729 | {
730 | status.sample_per_pixel = 2;
731 | if (status.depth != 8 && status.depth != 16)
732 | goto FINISH;
733 | }
734 | else if (status.color_type == 6) /* Truecolor with alpha */
735 | {
736 | status.sample_per_pixel = 4;
737 | if (status.depth != 8 && status.depth != 16)
738 | goto FINISH;
739 | }
740 | else
741 | goto FINISH;
742 | if (status.compression_method != 0)
743 | goto FINISH;
744 | if (status.filter_method != 0)
745 | goto FINISH;
746 | if (status.interlace_method == 0)
747 | status.rawlen = png_get_scanline_len(status.width, status.depth, status.sample_per_pixel) * status.height;
748 | else if (status.interlace_method == 1)
749 | {
750 | png_extract_adam7_extent(&status);
751 | status.rawlen = 0;
752 | for (i = 1; i <= 7; i++)
753 | status.rawlen += png_get_scanline_len(status.adam7_pass_width[i], status.depth, status.sample_per_pixel) * status.adam7_pass_height[i];
754 | }
755 | else
756 | goto FINISH;
757 |
758 | /* Dealing with remaining chunks */
759 | while (png_extract_chunk(&data, &size, &ctype, &cdata, &clen))
760 | {
761 | if (ctype[0] == 'I' && ctype[1] == 'D' && ctype[2] == 'A' && ctype[3] == 'T')
762 | {
763 | /* Non-contiguous IDAT chunks */
764 | if (status.zraw)
765 | goto FINISH;
766 |
767 | /* Extract total data size */
768 | if (!png_extract_data_size(&status, data, size, ctype, cdata, clen))
769 | goto FINISH;
770 |
771 | /* Create a whole buffer for zlib data */
772 | status.zraw = malloc(status.zlen);
773 | if (!status.zraw)
774 | goto FINISH;
775 |
776 | /* Copy zlib data */
777 | zraw = status.zraw;
778 | do
779 | {
780 | memcpy(zraw, cdata, clen);
781 | zraw += clen;
782 | /* Since data size is correctly extracted, no need to check again */
783 | png_extract_chunk(&data, &size, &ctype, &cdata, &clen);
784 | } while (zraw < status.zraw + status.zlen);
785 | }
786 | if (ctype[0] == 'I' && ctype[1] == 'E' && ctype[2] == 'N' && ctype[3] == 'D')
787 | break;
788 | else if (ctype[0] == 'P' && ctype[1] == 'L' && ctype[2] == 'T' && ctype[3] == 'E')
789 | {
790 | /* Palette */
791 | if (clen % 3 || clen / 3 > (1 << status.depth))
792 | goto FINISH;
793 | status.palette_count = clen / 3;
794 | status.palette = cdata;
795 | }
796 | else if (ctype[0] == 't' && ctype[1] == 'R' && ctype[2] == 'N' && ctype[3] == 'S')
797 | {
798 | /* Transparency */
799 | if (status.color_type == 0 && clen != 2)
800 | goto FINISH;
801 | else if (status.color_type == 2 && clen != 6)
802 | goto FINISH;
803 | else if (status.color_type == 3 && (!status.palette || clen > status.palette_count))
804 | goto FINISH;
805 | status.transparency_count = clen;
806 | status.transparency = cdata;
807 | }
808 | }
809 |
810 | if (status.color_type == 3 && !status.palette) /* No palette for indexed color type */
811 | goto FINISH;
812 |
813 | if (status.zraw == NULL)
814 | goto FINISH;
815 |
816 | /* Zlib decompress */
817 | status.raw = malloc(status.rawlen);
818 | if (!status.raw)
819 | goto FINISH;
820 | if (!zlib_deflate_decode(status.zraw, status.zlen, status.raw, status.rawlen))
821 | goto FINISH;
822 |
823 | status.defiltered = malloc(status.rawlen);
824 | if (!status.defiltered)
825 | goto FINISH;
826 |
827 | if (status.interlace_method == 0)
828 | png_defilter(status.raw, status.defiltered, status.width, status.height, status.depth, status.sample_per_pixel);
829 | else
830 | {
831 | j = 0;
832 | for (i = 1; i <= 7; i++)
833 | {
834 | png_defilter(status.raw + j, status.defiltered + j, status.adam7_pass_width[i], status.adam7_pass_height[i], status.depth, status.sample_per_pixel);
835 | j += png_get_scanline_len(status.adam7_pass_width[i], status.depth, status.sample_per_pixel) * status.adam7_pass_height[i];
836 | }
837 | }
838 |
839 | status.imagelen = status.width * status.height * 4;
840 | status.interlaced = malloc(status.imagelen);
841 | if (!status.interlaced)
842 | goto FINISH;
843 | if (status.interlace_method == 0)
844 | {
845 | if (!png_extract_pixels(&status, status.defiltered, status.interlaced, status.width, status.height, status.rawlen))
846 | goto FINISH;
847 | status.image = status.interlaced;
848 | status.interlaced = NULL;
849 | }
850 | else
851 | {
852 | j = 0;
853 | k = 0;
854 | for (i = 1; i <= 7; i++)
855 | {
856 | isize = png_get_scanline_len(status.adam7_pass_width[i], status.depth, status.sample_per_pixel) * status.adam7_pass_height[i];
857 | if (!png_extract_pixels(&status, status.defiltered + j, status.interlaced + k, status.adam7_pass_width[i], status.adam7_pass_height[i], isize))
858 | goto FINISH;
859 | j += isize;
860 | k += status.adam7_pass_width[i] * status.adam7_pass_height[i] * 4;
861 | }
862 | status.image = malloc(status.imagelen);
863 | if (!status.image)
864 | goto FINISH;
865 | png_deinterlace_adam7(&status, status.interlaced, status.image);
866 | }
867 | }
868 | FINISH:
869 | if (status.defiltered)
870 | free(status.defiltered);
871 | if (status.zraw)
872 | free(status.zraw);
873 | if (status.raw)
874 | free(status.raw);
875 | if (status.interlaced)
876 | free(status.interlaced);
877 | return status.image;
878 | }
879 |
880 | /* JPEG Decoder */
881 | #define JPEG_SOF0 0xC0
882 | #define JPEG_SOF1 0xC1
883 | #define JPEG_SOF2 0xC2
884 | #define JPEG_SOF3 0xC3
885 | #define JPEG_DHT 0xC4
886 | #define JPEG_SOF5 0xC5
887 | #define JPEG_SOF6 0xC6
888 | #define JPEG_SOF7 0xC7
889 | #define JPEG_JPG 0xC8
890 | #define JPEG_SOF9 0xC9
891 | #define JPEG_SOF10 0xCA
892 | #define JPEG_SOF11 0xCB
893 | #define JPEG_DAC 0xCC
894 | #define JPEG_SOF13 0xCD
895 | #define JPEG_SOF14 0xCE
896 | #define JPEG_SOF15 0xCF
897 | #define JPEG_RST0 0xD0
898 | #define JPEG_RST1 0xD1
899 | #define JPEG_RST2 0xD2
900 | #define JPEG_RST3 0xD3
901 | #define JPEG_RST4 0xD4
902 | #define JPEG_RST5 0xD5
903 | #define JPEG_RST6 0xD6
904 | #define JPEG_RST7 0xD7
905 | #define JPEG_SOI 0xD8
906 | #define JPEG_EOI 0xD9
907 | #define JPEG_SOS 0xDA
908 | #define JPEG_DQT 0xDB
909 | #define JPEG_DNL 0xDC
910 | #define JPEG_DRI 0xDD
911 | #define JPEG_DHP 0xDE
912 | #define JPEG_EXP 0xDF
913 | #define JPEG_COMPONENTS_COUNT 256
914 | #define JPEG_SCAN_COMPONENTS_COUNT 5
915 | #define JPEG_HUFFMAN_LENGTH_MAX 255
916 | #define JPEG_HUFFMAN_LENGTH_COUNT 17
917 | typedef struct
918 | {
919 | int H, V, Tq;
920 | int hs, vs;
921 | int linebytes, lines;
922 | int valid;
923 | unsigned char *raw;
924 | } JPEG_component;
925 |
926 | typedef struct
927 | {
928 | int Pq; /* Precision */
929 | int Qk[64];
930 | int valid;
931 | } JPEG_quantization_table;
932 |
933 | typedef struct
934 | {
935 | int Tc; /* Table class: 0 = DC, 1 = AC */
936 | int L[JPEG_HUFFMAN_LENGTH_COUNT];
937 | int hmin[JPEG_HUFFMAN_LENGTH_COUNT], hmax[JPEG_HUFFMAN_LENGTH_COUNT];
938 | int V[JPEG_HUFFMAN_LENGTH_COUNT][JPEG_HUFFMAN_LENGTH_MAX];
939 | int valid;
940 | } JPEG_huffman_table;
941 |
942 | typedef struct
943 | {
944 | /* Frame header */
945 | int P;
946 | int Y, X;
947 | int Nf;
948 | int hmax, vmax;
949 | int hcnt, vcnt;
950 | /* Scan header */
951 | int Ns;
952 | int Cs[JPEG_SCAN_COMPONENTS_COUNT], Td[JPEG_SCAN_COMPONENTS_COUNT], Ta[JPEG_SCAN_COMPONENTS_COUNT];
953 | int Ss, Se, Ah, Al;
954 | int pred[JPEG_SCAN_COMPONENTS_COUNT];
955 | /* Restart interval */
956 | int Ri;
957 | /* Tables */
958 | JPEG_component comp[JPEG_COMPONENTS_COUNT];
959 | JPEG_quantization_table qtable[4];
960 | JPEG_huffman_table hdc[4], hac[4];
961 | /* Final image */
962 | unsigned char *image;
963 | } JPEG_status;
964 |
965 | static int jpeg_extract_bits(const unsigned char **data, int *bit, int *size, int bits, int *raw)
966 | {
967 | *raw = 0;
968 | for (;;)
969 | {
970 | *raw = (*raw << (8 - *bit)) | ((*data)[0] & BITMASK(8 - *bit));
971 | if (bits <= 8 - *bit)
972 | {
973 | *raw >>= 8 - *bit - bits;
974 | *bit += bits;
975 | return 1;
976 | }
977 | else
978 | {
979 | bits -= 8 - *bit;
980 | *bit = 0;
981 | if ((*data)[0] == 0xFF)
982 | {
983 | if (*size < 2)
984 | return 0;
985 | (*size) -= 2;
986 | if ((*data)[1] != 0x00)
987 | return 0;
988 | (*data) += 2;
989 | }
990 | else
991 | {
992 | if (*size < 1)
993 | return 0;
994 | (*size)--;
995 | (*data)++;
996 | }
997 | }
998 | }
999 | }
1000 |
1001 | static int jpeg_extract_segment(const unsigned char **data, int *size, unsigned char *seg_type, const unsigned char **seg_data, int *seg_len)
1002 | {
1003 | if (*size < 2)
1004 | return 0;
1005 | EXTRACT_UINT8(*data, *seg_type);
1006 | (*size)--;
1007 | if (*seg_type != 0xFF)
1008 | return 0;
1009 | while (*size >= 1)
1010 | {
1011 | EXTRACT_UINT8(*data, *seg_type);
1012 | (*size)--;
1013 | if (*seg_type != 0xFF)
1014 | break;
1015 | }
1016 | if ((*seg_type >= JPEG_RST0 && *seg_type <= JPEG_RST7) || *seg_type == JPEG_SOI || *seg_type == JPEG_EOI) /* Standard-alone marker */
1017 | return 1;
1018 | if (*size < 2)
1019 | return 0;
1020 | EXTRACT_UINT16_BIG(*data, *seg_len);
1021 | *size -= 2;
1022 | *seg_len -= 2;
1023 | if (*size < *seg_len)
1024 | return 0;
1025 | *size -= *seg_len;
1026 | *seg_data = *data;
1027 | *data += *seg_len;
1028 | return 1;
1029 | }
1030 |
1031 | static int jpeg_process_restart_interval(JPEG_status *status, unsigned char stype, const unsigned char *sdata, int slen)
1032 | {
1033 | if (slen != 2)
1034 | return 0;
1035 | EXTRACT_UINT16_BIG(sdata, status->Ri);
1036 | return 1;
1037 | }
1038 |
1039 | static int jpeg_process_quantization_table(JPEG_status *status, unsigned char stype, const unsigned char *sdata, int slen)
1040 | {
1041 | int i, j, Pq, Tq;
1042 | if (slen == 0)
1043 | return 0;
1044 | while (slen > 0)
1045 | {
1046 | if (slen < 1)
1047 | return 0;
1048 | slen--;
1049 | EXTRACT_UINT8(sdata, j);
1050 | Pq = HIBYTE(j);
1051 | if (Pq == 0)
1052 | Pq = 8;
1053 | else if (Pq == 1)
1054 | Pq = 16;
1055 | else
1056 | return 0;
1057 | Tq = LOBYTE(j);
1058 | status->qtable[Tq].valid = 1;
1059 | status->qtable[Tq].Pq = Pq;
1060 | if (slen < Pq / 8 * 64)
1061 | return 0;
1062 | slen -= Pq / 8 * 64;
1063 | if (Pq == 8)
1064 | {
1065 | for (i = 0; i < 64; i++)
1066 | EXTRACT_UINT8(sdata, status->qtable[Tq].Qk[i]);
1067 | }
1068 | else
1069 | {
1070 | for (i = 0; i < 64; i++)
1071 | EXTRACT_UINT16_BIG(sdata, status->qtable[Tq].Qk[i]);
1072 | }
1073 | }
1074 | return 1;
1075 | }
1076 |
1077 | static int jpeg_process_huffman_table(JPEG_status *status, unsigned char stype, const unsigned char *sdata, int slen)
1078 | {
1079 | int i, j, mt, Tc, Th;
1080 | JPEG_huffman_table *huffman;
1081 | if (slen == 0)
1082 | return 0;
1083 | while (slen > 0)
1084 | {
1085 | if (slen < 17)
1086 | return 0;
1087 | slen -= 17;
1088 | EXTRACT_UINT8(sdata, j);
1089 | Tc = HIBYTE(j);
1090 | Th = LOBYTE(j);
1091 | if (Tc > 1 || Th > 3)
1092 | return 0;
1093 | if (Tc == 0)
1094 | huffman = &status->hdc[Th];
1095 | else
1096 | huffman = &status->hac[Th];
1097 | huffman->valid = 1;
1098 | mt = 0;
1099 | for (i = 1; i <= 16; i++)
1100 | {
1101 | EXTRACT_UINT8(sdata, huffman->L[i]);
1102 | mt += huffman->L[i];
1103 | }
1104 | if (slen < mt)
1105 | return 0;
1106 | slen -= mt;
1107 | for (i = 1; i <= 16; i++)
1108 | for (j = 0; j < huffman->L[i]; j++)
1109 | EXTRACT_UINT8(sdata, huffman->V[i][j]);
1110 | /* Initialize hmin and hmax */
1111 | j = 0;
1112 | for (i = 1; i <= 16; i++)
1113 | {
1114 | if (huffman->L[i] == 0)
1115 | huffman->hmin[i] = huffman->hmax[i] = -1;
1116 | else
1117 | {
1118 | huffman->hmin[i] = j;
1119 | huffman->hmax[i] = j + huffman->L[i] - 1;
1120 | if (huffman->hmax[i] >= (1 << i))
1121 | return 0;
1122 | j += huffman->L[i];
1123 | }
1124 | j <<= 1;
1125 | }
1126 | }
1127 | return 1;
1128 | }
1129 |
1130 | static int jpeg_extract_huffman_code(JPEG_huffman_table *huffman, const unsigned char **data, int *bit, int *size, unsigned char *code)
1131 | {
1132 | int i, j, k;
1133 |
1134 | j = 0;
1135 | for (i = 1; i <= 16; i++)
1136 | {
1137 | if (!jpeg_extract_bits(data, bit, size, 1, &k))
1138 | return 0;
1139 | j = (j << 1) | k;
1140 | if (j >= huffman->hmin[i] && j <= huffman->hmax[i])
1141 | {
1142 | *code = huffman->V[i][j - huffman->hmin[i]];
1143 | return 1;
1144 | }
1145 | }
1146 | return 0;
1147 | }
1148 |
1149 | static int jpeg_process_segment(JPEG_status *status, unsigned char stype, const unsigned char *sdata, int slen)
1150 | {
1151 | if (stype == JPEG_DRI)
1152 | return jpeg_process_restart_interval(status, stype, sdata, slen);
1153 | else if (stype == JPEG_DQT)
1154 | return jpeg_process_quantization_table(status, stype, sdata, slen);
1155 | else if (stype == JPEG_DHT)
1156 | return jpeg_process_huffman_table(status, stype, sdata, slen);
1157 | else /* Unrecognized segment marker, just return without processing */
1158 | return 1;
1159 | }
1160 |
1161 | static int jpeg_process_sof(JPEG_status *status, unsigned char stype, const unsigned char *sdata, int slen)
1162 | {
1163 | int i, j, k;
1164 | if (slen < 6)
1165 | return 0;
1166 | slen -= 6;
1167 | EXTRACT_UINT8(sdata, status->P);
1168 | EXTRACT_UINT16_BIG(sdata, status->Y);
1169 | EXTRACT_UINT16_BIG(sdata, status->X);
1170 | EXTRACT_UINT8(sdata, status->Nf);
1171 | if (status->P != 8)
1172 | return 0;
1173 | if (status->Y == 0 || status->X == 0)
1174 | return 0;
1175 | if (status->Nf != 1 && status->Nf != 3) /* We only accept grayscale or YCbCr */
1176 | return 0;
1177 | if (slen != status->Nf * 3)
1178 | return 0;
1179 | for (i = 1; i <= status->Nf; i++)
1180 | {
1181 | EXTRACT_UINT8(sdata, k);
1182 | if (k != i) /* No non-standard mapping please */
1183 | return 0;
1184 | status->comp[i].valid = 1;
1185 | EXTRACT_UINT8(sdata, j);
1186 | status->comp[i].H = HIBYTE(j);
1187 | status->comp[i].V = LOBYTE(j);
1188 | if (status->comp[i].H == 0 || status->comp[i].H > 4 || status->comp[i].V == 0 || status->comp[i].V > 4)
1189 | return 0;
1190 | EXTRACT_UINT8(sdata, status->comp[i].Tq);
1191 | status->hmax = max(status->hmax, status->comp[i].H);
1192 | status->vmax = max(status->vmax, status->comp[i].V);
1193 | }
1194 | for (i = 1; i <= status->Nf; i++)
1195 | {
1196 | if (status->hmax % status->comp[i].H != 0 || status->vmax % status->comp[i].V != 0) /* 4:3 and 3:2 is Unsupported */
1197 | return 0;
1198 | status->comp[i].hs = status->hmax / status->comp[i].H;
1199 | status->comp[i].vs = status->vmax / status->comp[i].V;
1200 | }
1201 | status->vcnt = (status->Y + status->vmax * 8 - 1) / (status->vmax * 8);
1202 | status->hcnt = (status->X + status->hmax * 8 - 1) / (status->hmax * 8);
1203 | /* Allocate memory for components */
1204 | for (i = 1; i <= status->Nf; i++)
1205 | {
1206 | status->comp[i].linebytes = status->comp[i].H * status->hcnt * 8;
1207 | status->comp[i].lines = status->comp[i].V * status->vcnt * 8;
1208 | status->comp[i].raw = malloc(status->comp[i].linebytes * status->comp[i].lines);
1209 | if (!status->comp[i].raw)
1210 | return 0;
1211 | }
1212 | return 1;
1213 | }
1214 |
1215 | /* The EXTEND procedure in JPEG specification */
1216 | static INLINE int jpeg_extend(int raw, int t)
1217 | {
1218 | int Vt;
1219 |
1220 | Vt = 1 << (t - 1);
1221 | if (raw < Vt)
1222 | return raw + ((-1) << t) + 1;
1223 | else
1224 | return raw;
1225 | }
1226 |
1227 | /* TODO: Optimization */
1228 | static const double pi = 3.1415926535897932384626433832795028841971693993751;
1229 | static void jpeg_idct(int *src)
1230 | {
1231 | int S[64];
1232 | int x, y, u, v;
1233 | double ans, cu, cv;
1234 |
1235 | memcpy(S, src, 64 * sizeof(int));
1236 | for (y = 0; y < 8; y++)
1237 | for (x = 0; x < 8; x++)
1238 | {
1239 | ans = 0;
1240 | for (v = 0; v < 8; v++)
1241 | for (u = 0; u < 8; u++)
1242 | {
1243 | cv = (v == 0) ? 1.0 / sqrt(2) : 1;
1244 | cu = (u == 0) ? 1.0 / sqrt(2) : 1;
1245 | ans += cv * cu * S[v * 8 + u] * cos((2 * x + 1) * u * pi / 16) * cos((2 * y + 1) * v * pi / 16);
1246 | }
1247 | src[y * 8 + x] = (int)(ans / 4);
1248 | }
1249 | }
1250 |
1251 | static const int jpeg_zigzag[8][8] = {
1252 | { 0, 1, 5, 6, 14, 15, 27, 28 },
1253 | { 2, 4, 7, 13, 16, 26, 29, 42 },
1254 | { 3, 8, 12, 17, 25, 30, 41, 43 },
1255 | { 9, 11, 18, 24, 31, 40, 44, 53 },
1256 | { 10, 19, 23, 32, 39, 45, 52, 54 },
1257 | { 20, 22, 33, 38, 46, 51, 55, 60 },
1258 | { 21, 34, 37, 47, 50, 56, 59, 61 },
1259 | { 35, 36, 48, 49, 57, 58, 62, 63 },
1260 | };
1261 | static int jpeg_process_scan_header(JPEG_status *status, unsigned char stype, const unsigned char *sdata, int slen)
1262 | {
1263 | int i, j;
1264 |
1265 | if (slen < 4)
1266 | return 0;
1267 | slen -= 4;
1268 | EXTRACT_UINT8(sdata, status->Ns);
1269 | if (slen != status->Ns * 2)
1270 | return 0;
1271 | for (i = 1; i <= status->Ns; i++)
1272 | {
1273 | EXTRACT_UINT8(sdata, status->Cs[i]);
1274 | if (!status->comp[status->Cs[i]].valid)
1275 | return 0;
1276 | EXTRACT_UINT8(sdata, j);
1277 | status->Td[i] = HIBYTE(j);
1278 | status->Ta[i] = LOBYTE(j);
1279 | if (!status->hdc[status->Td[i]].valid || !status->hac[status->Ta[i]].valid)
1280 | return 0;
1281 | }
1282 | EXTRACT_UINT8(sdata, status->Ss);
1283 | EXTRACT_UINT8(sdata, status->Se);
1284 | EXTRACT_UINT8(sdata, j);
1285 | status->Ah = HIBYTE(j);
1286 | status->Al = LOBYTE(j);
1287 | /* These shall all be zero for sequential DCT process */
1288 | if (status->Ss != 0 || status->Se != 63 || status->Ah != 0 || status->Al != 0)
1289 | return 0;
1290 | return 1;
1291 | }
1292 |
1293 | static int jpeg_extract_scan(JPEG_status *status, const unsigned char **data, int *size)
1294 | {
1295 | int i, j, k, c, g, mx, my, x, y, X, Y;
1296 | int mcucnt, mcutotal;
1297 | int bit;
1298 | unsigned char t, rs, r, s;
1299 | int raw[64], co[64], tmp;
1300 | /* Extents of MCU */
1301 | mcutotal = status->hcnt * status->vcnt;
1302 | mcucnt = 0;
1303 | bit = 0;
1304 |
1305 | for (k = 1; k <= status->Ns; k++)
1306 | status->pred[k] = 0;
1307 | for (i = 0; i < status->vcnt; i++)
1308 | for (j = 0; j < status->hcnt; j++)
1309 | {
1310 | /* Decode MCU */
1311 | for (k = 1; k <= status->Ns; k++)
1312 | {
1313 | c = status->Cs[k];
1314 | for (my = 0; my < status->comp[c].V; my++)
1315 | for (mx = 0; mx < status->comp[c].H; mx++)
1316 | {
1317 | /* Decode 8x8 block */
1318 | /* Read data in */
1319 | if (!jpeg_extract_huffman_code(&status->hdc[status->Td[k]], data, &bit, size, &t))
1320 | return 0;
1321 | if (t > 16)
1322 | return 0;
1323 | if (!jpeg_extract_bits(data, &bit, size, t, &tmp))
1324 | return 0;
1325 | status->pred[k] += t ? jpeg_extend(tmp, t) : 0;
1326 | raw[0] = status->pred[k];
1327 | for (g = 1; g <= 63; g++)
1328 | raw[g] = 0;
1329 | for (g = 1;;)
1330 | {
1331 | if (!jpeg_extract_huffman_code(&status->hac[status->Ta[k]], data, &bit, size, &rs))
1332 | return 0;
1333 | r = HIBYTE(rs);
1334 | s = LOBYTE(rs);
1335 | if (s == 0)
1336 | {
1337 | if (r != 15)
1338 | break;
1339 | g += 16;
1340 | if (g > 63)
1341 | return 0;
1342 | }
1343 | else
1344 | {
1345 | g += r;
1346 | if (g > 63)
1347 | return 0;
1348 | if (!jpeg_extract_bits(data, &bit, size, s, &tmp))
1349 | return 0;
1350 | raw[g] = s ? jpeg_extend(tmp, s) : 0;
1351 | if (g == 63)
1352 | break;
1353 | g++;
1354 | }
1355 | }
1356 | /* Dequantization and de-zigzag */
1357 | for (y = 0; y < 8; y++)
1358 | for (x = 0; x < 8; x++)
1359 | {
1360 | g = jpeg_zigzag[y][x];
1361 | co[y * 8 + x] = raw[g] * status->qtable[status->comp[c].Tq].Qk[g];
1362 | }
1363 | /* IDCT */
1364 | jpeg_idct(co);
1365 | /* Write data */
1366 | for (y = 0; y < 8; y++)
1367 | for (x = 0; x < 8; x++)
1368 | {
1369 | Y = (i * status->comp[c].V + my) * 8 + y;
1370 | X = (j * status->comp[c].H + mx) * 8 + x;
1371 | status->comp[c].raw[status->comp[c].linebytes * Y + X] = color_clamp(co[y * 8 + x] + 128);
1372 | }
1373 | }
1374 | }
1375 | mcucnt++;
1376 | if (status->Ri != 0 && (mcucnt % status->Ri == 0) && mcucnt < mcutotal) /* Should occur a RST marker */
1377 | {
1378 | for (k = 1; k <= status->Ns; k++)
1379 | status->pred[k] = 0;
1380 | /* Skip remaining bits in current byte */
1381 | if (bit > 0)
1382 | (*data)++, bit = 0, (*size)--;
1383 | if (*size < 2)
1384 | return 0;
1385 | if (**data != 0xFF)
1386 | return 0;
1387 | (*data)++, (*size)--;
1388 | if (**data < JPEG_RST0 || **data > JPEG_RST7)
1389 | return 0;
1390 | (*data)++, (*size)--;
1391 | }
1392 | }
1393 |
1394 | return 1;
1395 | }
1396 |
1397 | static char *jpeg_decode(const unsigned char *data, int size, int *width, int *height)
1398 | {
1399 | unsigned char stype;
1400 | const unsigned char *sdata;
1401 | int slen;
1402 | JPEG_status status;
1403 | int i, j, k;
1404 | int Y, Cb, Cr;
1405 |
1406 | memset(&status, 0, sizeof(JPEG_status));
1407 |
1408 | if (!jpeg_extract_segment(&data, &size, &stype, &sdata, &slen) || stype != JPEG_SOI)
1409 | goto FINISH;
1410 | for (;;)
1411 | {
1412 | if (!jpeg_extract_segment(&data, &size, &stype, &sdata, &slen))
1413 | goto FINISH;
1414 | if (stype == JPEG_SOF0)
1415 | break;
1416 | if (!jpeg_process_segment(&status, stype, sdata, slen))
1417 | goto FINISH;
1418 | }
1419 | if (!jpeg_process_sof(&status, stype, sdata, slen))
1420 | goto FINISH;
1421 |
1422 | for (;;)
1423 | {
1424 | if (!jpeg_extract_segment(&data, &size, &stype, &sdata, &slen))
1425 | goto FINISH;
1426 | if (stype == JPEG_SOS)
1427 | break;
1428 | if (!jpeg_process_segment(&status, stype, sdata, slen))
1429 | goto FINISH;
1430 | }
1431 | if (!jpeg_process_scan_header(&status, stype, sdata, slen))
1432 | goto FINISH;
1433 | if (!jpeg_extract_scan(&status, &data, &size))
1434 | goto FINISH;
1435 |
1436 | status.image = malloc(status.Y * status.X * 4);
1437 | if (!status.image)
1438 | goto FINISH;
1439 | *width = status.X;
1440 | *height = status.Y;
1441 |
1442 | if (status.Nf == 1)
1443 | {
1444 | for (i = 0; i < status.Y; i++)
1445 | for (j = 0; j < status.X; j++)
1446 | {
1447 | k = (i * status.X + j) * 4;
1448 | status.image[k] = status.image[k + 1] = status.image[k + 2] = status.comp[1].raw[status.comp[1].linebytes * i + j];
1449 | status.image[k + 3] = 0xFF;
1450 | }
1451 | }
1452 | else /* Nf == 3 */
1453 | {
1454 | /* Resample and YCbCr -> RGB */
1455 | for (i = 0; i < status.Y; i++)
1456 | for (j = 0; j < status.X; j++)
1457 | {
1458 | k = (i * status.X + j) * 4;
1459 | Y = status.comp[1].raw[(i / status.comp[1].vs) * status.comp[1].linebytes + j / status.comp[1].hs];
1460 | Cb = status.comp[2].raw[(i / status.comp[2].vs) * status.comp[2].linebytes + j / status.comp[2].hs];
1461 | Cr = status.comp[3].raw[(i / status.comp[3].vs) * status.comp[3].linebytes + j / status.comp[3].hs];
1462 |
1463 | status.image[k + 0] = color_clamp((int)(Y + 1.402 * (Cr - 128)));
1464 | status.image[k + 1] = color_clamp((int)(Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128)));
1465 | status.image[k + 2] = color_clamp((int)(Y + 1.772 * (Cb - 128)));
1466 | status.image[k + 3] = 255;
1467 | }
1468 | }
1469 |
1470 | FINISH:
1471 | for (i = 0; i < JPEG_COMPONENTS_COUNT; i++)
1472 | if (status.comp[i].raw)
1473 | free(status.comp[i].raw);
1474 | return status.image;
1475 | }
1476 |
1477 | /* PSD Decoder */
1478 | #define PSD_BITMAP 0
1479 | #define PSD_GRAYSCALE 1
1480 | #define PSD_INDEXED 2
1481 | #define PSD_RGB 3
1482 | #define PSD_CMYK 4
1483 | #define PSD_MULTI 7
1484 | #define PSD_DUOTONE 8
1485 | #define PSD_LAB 9
1486 | typedef struct
1487 | {
1488 | int channels;
1489 | int width, height;
1490 | int depth;
1491 | int color_mode;
1492 | int compression_method;
1493 | unsigned char *image;
1494 | } PSD_status;
1495 |
1496 | static char *psd_decode(const unsigned char *data, int size, int *width, int *height)
1497 | {
1498 | int i, j, k, c, bit, expected_size;
1499 | PSD_status status;
1500 |
1501 | memset(&status, 0, sizeof(PSD_status));
1502 |
1503 | if (size < 16)
1504 | return 0;
1505 |
1506 | /* File header */
1507 | EXTRACT_UINT16_BIG(data, k); /* Version */
1508 | if (k != 1)
1509 | return 0;
1510 | data += 6; /* Reserved */
1511 | EXTRACT_UINT16_BIG(data, status.channels);
1512 | EXTRACT_UINT32_BIG(data, status.height);
1513 | EXTRACT_UINT32_BIG(data, status.width);
1514 | EXTRACT_UINT16_BIG(data, status.depth);
1515 | EXTRACT_UINT16_BIG(data, status.color_mode);
1516 | size -= 16;
1517 |
1518 | *width = status.width;
1519 | *height = status.height;
1520 |
1521 | if (status.channels != 3)
1522 | return 0;
1523 | if (status.width == 0 || status.height == 0)
1524 | return 0;
1525 | if (status.depth != 1 && status.depth != 8 && status.depth != 16 && status.depth != 32)
1526 | return 0;
1527 | if (status.color_mode != PSD_RGB)
1528 | return 0;
1529 |
1530 | /* Color mode data */
1531 | if (size < 4)
1532 | return 0;
1533 | EXTRACT_UINT32_BIG(data, k);
1534 | if (size < 4 + k)
1535 | return 0;
1536 | data += k; /* Just skip */
1537 | size -= k;
1538 |
1539 | /* Image resources */
1540 | if (size < 4)
1541 | return 0;
1542 | EXTRACT_UINT32_BIG(data, k);
1543 | if (size < 4 + k)
1544 | return 0;
1545 | data += k; /* just skip */
1546 | size -= k;
1547 |
1548 | /* Layer and mask information */
1549 | if (size < 4)
1550 | return 0;
1551 | EXTRACT_UINT32_BIG(data, k);
1552 | if (size < 4 + k)
1553 | return 0;
1554 | data += k; /* just skip */
1555 | size -= k;
1556 |
1557 | /* Image data */
1558 | if (size < 2)
1559 | return 0;
1560 | EXTRACT_UINT16_BIG(data, status.compression_method);
1561 | size -= 2;
1562 |
1563 | status.image = malloc(status.width * status.height * 4);
1564 | if (!status.image)
1565 | goto FINISH;
1566 | if (status.compression_method == 0)
1567 | {
1568 | expected_size = status.channels * status.width * status.height;
1569 | if (status.depth == 1)
1570 | expected_size = (expected_size + 7) / 8;
1571 | else
1572 | expected_size = expected_size * (status.depth / 8);
1573 | if (size < expected_size)
1574 | {
1575 | free(status.image);
1576 | goto FINISH;
1577 | }
1578 | bit = 0;
1579 | for (c = 0; c < status.channels; c++)
1580 | for (i = 0; i < status.height; i++)
1581 | for (j = 0; j < status.width; j++)
1582 | {
1583 | k = (i * status.width + j) * 4;
1584 | status.image[k + c] = sample_rescale(status.depth, extract_bits_big(&data, &bit, &size, status.depth));
1585 | }
1586 | for (i = 0; i < status.height; i++)
1587 | for (j = 0; j < status.width; j++)
1588 | {
1589 | k = (i * status.width + j) * 4;
1590 | status.image[k + 3] = 255;
1591 | }
1592 | }
1593 | else if (status.compression_method == 1)
1594 | {
1595 | }
1596 | else /* Unsupported compression method */
1597 | return 0;
1598 |
1599 | FINISH:
1600 | return status.image;
1601 | }
1602 |
1603 | char *fluid_decode(const char *_data, int size, int *width, int *height)
1604 | {
1605 | const unsigned char *data = _data;
1606 | /* Identify image format and call corresponding image decoder */
1607 | /* Check PNG */
1608 | if (size >= 8)
1609 | {
1610 | if (data[0] == 137 && data[1] == 80 && data[2] == 78 && data[3] == 71 &&
1611 | data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10)
1612 | return png_decode(data + 8, size - 8, width, height);
1613 | }
1614 | /* Check JPEG */
1615 | if (size >= 1)
1616 | {
1617 | if (data[0] == 0xFF)
1618 | return jpeg_decode(data, size, width, height);
1619 | }
1620 | /* Check PSD */
1621 | if (size >= 4)
1622 | {
1623 | if (data[0] == '8' && data[1] == 'B' && data[2] == 'P' && data[3] == 'S')
1624 | return psd_decode(data + 4, size - 4, width, height);
1625 | }
1626 | return NULL;
1627 | }
1628 |
--------------------------------------------------------------------------------