├── 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 | --------------------------------------------------------------------------------