From 5ea02f4798fedfd0d5e85616d6959ff7b0532308 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Tue, 13 Sep 2011 09:35:12 -0500 Subject: [PATCH] PNG library should reverse filter on entire bytes Add word to test that some pngs fail to load --- extra/images/png/png-tests.factor | 346 +++++++++++++++------------- extra/images/png/png.factor | 48 ++-- extra/images/testing/testing.factor | 5 +- 3 files changed, 217 insertions(+), 182 deletions(-) diff --git a/extra/images/png/png-tests.factor b/extra/images/png/png-tests.factor index 6e02c3311d..acccc84e37 100644 --- a/extra/images/png/png-tests.factor +++ b/extra/images/png/png-tests.factor @@ -75,164 +75,188 @@ IN: images.png.tests "z09n2c08.png" decode-test ] with-directory -! The current PNG decoder implementation is very limited, -! so the entire test suite is not currently enabled. -! "vocab:images/testing/png/suite" [ -! "basi0g01.png" decode-test -! "basi0g02.png" decode-test -! "basi0g04.png" decode-test -! "basi0g08.png" decode-test -! "basi0g16.png" decode-test -! "basi2c08.png" decode-test -! "basi2c16.png" decode-test -! "basi3p01.png" decode-test -! "basi3p02.png" decode-test -! "basi3p04.png" decode-test -! "basi3p08.png" decode-test -! "basi4a08.png" decode-test -! "basi4a16.png" decode-test -! "basi6a08.png" decode-test -! "basi6a16.png" decode-test -! "basn0g01.png" decode-test -! "basn0g02.png" decode-test -! "basn0g04.png" decode-test -! "basn0g08.png" decode-test -! "basn0g16.png" decode-test -! "basn2c08.png" decode-test -! "basn2c16.png" decode-test -! "basn3p01.png" decode-test -! "basn3p02.png" decode-test -! "basn3p04.png" decode-test -! "basn3p08.png" decode-test -! "basn4a08.png" decode-test -! "basn4a16.png" decode-test -! "basn6a08.png" decode-test -! "basn6a16.png" decode-test -! "bgai4a08.png" decode-test -! "bgai4a16.png" decode-test -! "bgan6a08.png" decode-test -! "bgan6a16.png" decode-test -! "bgbn4a08.png" decode-test -! "bggn4a16.png" decode-test -! "bgwn6a08.png" decode-test -! "bgyn6a16.png" decode-test -! "ccwn2c08.png" decode-test -! "ccwn3p08.png" decode-test -! "cdfn2c08.png" decode-test -! "cdhn2c08.png" decode-test -! "cdsn2c08.png" decode-test -! "cdun2c08.png" decode-test -! "ch1n3p04.png" decode-test -! "ch2n3p08.png" decode-test -! "cm0n0g04.png" decode-test -! "cm7n0g04.png" decode-test -! "cm9n0g04.png" decode-test -! "cs3n2c16.png" decode-test -! "cs3n3p08.png" decode-test -! "cs5n2c08.png" decode-test -! "cs5n3p08.png" decode-test -! "cs8n2c08.png" decode-test -! "cs8n3p08.png" decode-test -! "ct0n0g04.png" decode-test -! "ct1n0g04.png" decode-test -! "ctzn0g04.png" decode-test -! "f00n0g08.png" decode-test -! "f00n2c08.png" decode-test -! "f01n0g08.png" decode-test -! "f01n2c08.png" decode-test -! "f02n0g08.png" decode-test -! "f02n2c08.png" decode-test -! "f03n0g08.png" decode-test -! "f03n2c08.png" decode-test -! "f04n0g08.png" decode-test -! "f04n2c08.png" decode-test -! "g03n0g16.png" decode-test -! "g03n2c08.png" decode-test -! "g03n3p04.png" decode-test -! "g04n0g16.png" decode-test -! "g04n2c08.png" decode-test -! "g04n3p04.png" decode-test -! "g05n0g16.png" decode-test -! "g05n2c08.png" decode-test -! "g05n3p04.png" decode-test -! "g07n0g16.png" decode-test -! "g07n2c08.png" decode-test -! "g07n3p04.png" decode-test -! "g10n0g16.png" decode-test -! "g10n2c08.png" decode-test -! "g10n3p04.png" decode-test -! "g25n0g16.png" decode-test -! "g25n2c08.png" decode-test -! "g25n3p04.png" decode-test -! "oi1n0g16.png" decode-test -! "oi1n2c16.png" decode-test -! "oi2n0g16.png" decode-test -! "oi2n2c16.png" decode-test -! "oi4n0g16.png" decode-test -! "oi4n2c16.png" decode-test -! "oi9n0g16.png" decode-test -! "oi9n2c16.png" decode-test -! "pngsuite_logo.png" decode-test -! "pp0n2c16.png" decode-test -! "pp0n6a08.png" decode-test -! "ps1n0g08.png" decode-test -! "ps1n2c16.png" decode-test -! "ps2n0g08.png" decode-test -! "ps2n2c16.png" decode-test -! "s01i3p01.png" decode-test -! "s01n3p01.png" decode-test -! "s02i3p01.png" decode-test -! "s02n3p01.png" decode-test -! "s03i3p01.png" decode-test -! "s03n3p01.png" decode-test -! "s04i3p01.png" decode-test -! "s04n3p01.png" decode-test -! "s05i3p02.png" decode-test -! "s05n3p02.png" decode-test -! "s06i3p02.png" decode-test -! "s06n3p02.png" decode-test -! "s07i3p02.png" decode-test -! "s07n3p02.png" decode-test -! "s08i3p02.png" decode-test -! "s08n3p02.png" decode-test -! "s09i3p02.png" decode-test -! "s09n3p02.png" decode-test -! "s32i3p04.png" decode-test -! "s32n3p04.png" decode-test -! "s33i3p04.png" decode-test -! "s33n3p04.png" decode-test -! "s34i3p04.png" decode-test -! "s34n3p04.png" decode-test -! "s35i3p04.png" decode-test -! "s35n3p04.png" decode-test -! "s36i3p04.png" decode-test -! "s36n3p04.png" decode-test -! "s37i3p04.png" decode-test -! "s37n3p04.png" decode-test -! "s38i3p04.png" decode-test -! "s38n3p04.png" decode-test -! "s39i3p04.png" decode-test -! "s39n3p04.png" decode-test -! "s40i3p04.png" decode-test -! "s40n3p04.png" decode-test -! "tbbn1g04.png" decode-test -! "tbbn2c16.png" decode-test -! "tbbn3p08.png" decode-test -! "tbgn2c16.png" decode-test -! "tbgn3p08.png" decode-test -! "tbrn2c08.png" decode-test -! "tbwn1g16.png" decode-test -! "tbwn3p08.png" decode-test -! "tbyn3p08.png" decode-test -! "tp0n1g08.png" decode-test -! "tp0n2c08.png" decode-test -! "tp0n3p08.png" decode-test -! "tp1n3p08.png" decode-test -! "x00n0g01.png" decode-test -! "xcrn0g04.png" decode-test -! "xlfn0g04.png" decode-test -! "z00n2c08.png" decode-test -! "z03n2c08.png" decode-test -! "z06n2c08.png" decode-test -! "z09n2c08.png" decode-test -! ] with-directory +! Test pngsuite +"vocab:images/testing/png/suite" [ + "PngSuite.png" decode-test + "basi0g01.png" decode-test + "basi0g02.png" decode-test + "basi0g04.png" decode-test + "basi0g08.png" decode-test + "basi0g16.png" decode-test + "basi2c08.png" decode-test + "basi2c16.png" decode-test + "basi3p01.png" decode-test + "basi3p02.png" decode-test + "basi3p04.png" decode-test + "basi3p08.png" decode-test + "basi4a08.png" decode-test + "basi4a16.png" decode-test + "basi6a08.png" decode-test + "basi6a16.png" decode-test + "basn0g01.png" decode-test + "basn0g02.png" decode-test + "basn0g04.png" decode-test + "basn0g08.png" decode-test + "basn0g16.png" decode-test + "basn2c08.png" decode-test + "basn2c16.png" decode-test + "basn3p01.png" decode-test + "basn3p02.png" decode-test + "basn3p04.png" decode-test + "basn3p08.png" decode-test + "basn4a08.png" decode-test + "basn4a16.png" decode-test + "basn6a08.png" decode-test + "basn6a16.png" decode-test + "bgai4a08.png" decode-test + "bgai4a16.png" decode-test + "bgan6a08.png" decode-test + "bgan6a16.png" decode-test + "bgbn4a08.png" decode-test + "bggn4a16.png" decode-test + "bgwn6a08.png" decode-test + "bgyn6a16.png" decode-test + "ccwn2c08.png" decode-test + "ccwn3p08.png" decode-test + "cdfn2c08.png" decode-test + "cdhn2c08.png" decode-test + "cdsn2c08.png" decode-test + "cdun2c08.png" decode-test + "ch1n3p04.png" decode-test + "ch2n3p08.png" decode-test + "cm0n0g04.png" decode-test + "cm7n0g04.png" decode-test + "cm9n0g04.png" decode-test + "cs3n2c16.png" decode-test + "cs3n3p08.png" decode-test + "cs5n2c08.png" decode-test + "cs5n3p08.png" decode-test + "cs8n2c08.png" decode-test + "cs8n3p08.png" decode-test + "ct0n0g04.png" decode-test + "ct1n0g04.png" decode-test + "cten0g04.png" decode-test + "ctfn0g04.png" decode-test + "ctgn0g04.png" decode-test + "cthn0g04.png" decode-test + "ctjn0g04.png" decode-test + "ctzn0g04.png" decode-test + "f00n0g08.png" decode-test + "f00n2c08.png" decode-test + "f01n0g08.png" decode-test + "f01n2c08.png" decode-test + "f02n0g08.png" decode-test + "f02n2c08.png" decode-test + "f03n0g08.png" decode-test + "f03n2c08.png" decode-test + "f04n0g08.png" decode-test + "f04n2c08.png" decode-test + "f99n0g04.png" decode-test + "g03n0g16.png" decode-test + "g03n2c08.png" decode-test + "g03n3p04.png" decode-test + "g04n0g16.png" decode-test + "g04n2c08.png" decode-test + "g04n3p04.png" decode-test + "g05n0g16.png" decode-test + "g05n2c08.png" decode-test + "g05n3p04.png" decode-test + "g07n0g16.png" decode-test + "g07n2c08.png" decode-test + "g07n3p04.png" decode-test + "g10n0g16.png" decode-test + "g10n2c08.png" decode-test + "g10n3p04.png" decode-test + "g25n0g16.png" decode-test + "g25n2c08.png" decode-test + "g25n3p04.png" decode-test + "oi1n0g16.png" decode-test + "oi1n2c16.png" decode-test + "oi2n0g16.png" decode-test + "oi2n2c16.png" decode-test + "oi4n0g16.png" decode-test + "oi4n2c16.png" decode-test + "oi9n0g16.png" decode-test + "oi9n2c16.png" decode-test + "pngsuite_logo.png" decode-test + "pp0n2c16.png" decode-test + "pp0n6a08.png" decode-test + "ps1n0g08.png" decode-test + "ps1n2c16.png" decode-test + "ps2n0g08.png" decode-test + "ps2n2c16.png" decode-test + "s01i3p01.png" decode-test + "s01n3p01.png" decode-test + "s02i3p01.png" decode-test + "s02n3p01.png" decode-test + "s03i3p01.png" decode-test + "s03n3p01.png" decode-test + "s04i3p01.png" decode-test + "s04n3p01.png" decode-test + "s05i3p02.png" decode-test + "s05n3p02.png" decode-test + "s06i3p02.png" decode-test + "s06n3p02.png" decode-test + "s07i3p02.png" decode-test + "s07n3p02.png" decode-test + "s08i3p02.png" decode-test + "s08n3p02.png" decode-test + "s09i3p02.png" decode-test + "s09n3p02.png" decode-test + "s32i3p04.png" decode-test + "s32n3p04.png" decode-test + "s33i3p04.png" decode-test + "s33n3p04.png" decode-test + "s34i3p04.png" decode-test + "s34n3p04.png" decode-test + "s35i3p04.png" decode-test + "s35n3p04.png" decode-test + "s36i3p04.png" decode-test + "s36n3p04.png" decode-test + "s37i3p04.png" decode-test + "s37n3p04.png" decode-test + "s38i3p04.png" decode-test + "s38n3p04.png" decode-test + "s39i3p04.png" decode-test + "s39n3p04.png" decode-test + "s40i3p04.png" decode-test + "s40n3p04.png" decode-test + "tbbn0g04.png" decode-test + "tbbn1g04.png" decode-test + "tbbn2c16.png" decode-test + "tbbn3p08.png" decode-test + "tbgn2c16.png" decode-test + "tbgn3p08.png" decode-test + "tbrn2c08.png" decode-test + "tbwn0g16.png" decode-test + "tbwn1g16.png" decode-test + "tbwn3p08.png" decode-test + "tbyn3p08.png" decode-test + "tp0n0g08.png" decode-test + "tp0n1g08.png" decode-test + "tp0n2c08.png" decode-test + "tp0n3p08.png" decode-test + "tp1n3p08.png" decode-test + "z00n2c08.png" decode-test + "z03n2c08.png" decode-test + "z06n2c08.png" decode-test + "z09n2c08.png" decode-test +] with-directory + +"vocab:images/testing/png/suite/bads" [ + "x00n0g01.png" image-load-must-fail + "xcsn0g01.png" image-load-must-fail + "xd0n2c08.png" image-load-must-fail + "xd3n2c08.png" image-load-must-fail + "xd9n2c08.png" image-load-must-fail + "xdtn0g01.png" image-load-must-fail + "xcrn0g04.png" image-load-must-fail + "xc1n0g08.png" image-load-must-fail + "xc9n2c08.png" image-load-must-fail + "xlfn0g04.png" image-load-must-fail + "xhdn0g08.png" image-load-must-fail + "xs1n0g01.png" image-load-must-fail + "xs2n0g01.png" image-load-must-fail + "xs4n0g01.png" image-load-must-fail + "xs7n0g01.png" image-load-must-fail +] with-directory diff --git a/extra/images/png/png.factor b/extra/images/png/png.factor index 0b18b01a45..90ebfe2382 100644 --- a/extra/images/png/png.factor +++ b/extra/images/png/png.factor @@ -1,10 +1,11 @@ ! Copyright (C) 2009 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors arrays checksums checksums.crc32 combinators -compression.inflate fry grouping images images.loader io -io.binary io.encodings.ascii io.encodings.string kernel locals -math math.bitwise math.ranges sequences sorting assocs -math.functions math.order byte-arrays io.streams.throwing ; +USING: accessors arrays assocs byte-arrays checksums +checksums.crc32 combinators compression.inflate fry grouping +images images.loader io io.binary io.encodings.ascii +io.encodings.binary io.encodings.string io.streams.byte-array +io.streams.throwing kernel locals math math.bitwise +math.functions math.order math.ranges sequences sorting ; QUALIFIED-WITH: bitstreams bs IN: images.png @@ -115,6 +116,8 @@ ERROR: unimplemented-color-type image ; a b + c - { a b c } [ [ - abs ] keep 2array ] with map sort-keys first second ; +ERROR: bad-filter n ; + :: png-unfilter-line ( width prev curr filter -- curr' ) prev :> c prev width tail-slice :> b @@ -127,6 +130,7 @@ ERROR: unimplemented-color-type image ; { filter-up [ [| n | n x nth n b nth + 256 wrap n x set-nth ] each ] } { filter-average [ [| n | n x nth n a nth n b nth + 2/ + 256 wrap n x set-nth ] each ] } { filter-paeth [ [| n | n x nth n a nth n b nth n c nth paeth + 256 wrap n x set-nth ] each ] } + [ bad-filter ] } case curr width tail ; @@ -145,32 +149,36 @@ ERROR: unimplemented-color-type image ; row image nth :> irow pixel col irow set-nth ; -ERROR: bad-filter n ; - -:: read-scanlines ( bit-reader loading-png width height -- array ) +:: read-scanlines ( byte-reader loading-png width height -- array ) loading-png png-components-per-pixel :> #components loading-png bit-depth>> :> bit-depth bit-depth :> depth! #components width * :> count! + #components bit-depth * width * 8 math:align 8 /i :> stride + + height [ + stride 1 + byte-reader stream-read + ] replicate + #components bit-depth 16 = [ 2 * ] when reverse-png-filter + ! Only read up to 8 bits at a time bit-depth 16 = [ 8 depth! count 2 * count! ] when + bs: :> br height [ - 8 bit-reader bs:read dup 0 4 between? [ bad-filter ] unless - count [ depth bit-reader bs:read ] replicate swap prefix - 8 bit-reader bs:align - ] replicate - #components bit-depth 16 = [ 2 * ] when reverse-png-filter ; + count [ depth br bs:read ] B{ } replicate-as + 8 br bs:align + ] replicate concat ; -:: reverse-interlace-none ( byte-array loading-png -- array ) - byte-array bs: :> bs +:: reverse-interlace-none ( bytes loading-png -- array ) + bytes binary :> br loading-png width>> :> width loading-png height>> :> height - bs loading-png width height read-scanlines ; + br loading-png width height read-scanlines ; :: adam7-subimage-height ( png-height pass -- subimage-height ) pass starting-row nth png-height >= [ @@ -190,18 +198,18 @@ ERROR: bad-filter n ; pass col-increment nth /i ] if ; -:: read-adam7-subimage ( bit-reader loading-png pass -- lines ) +:: read-adam7-subimage ( byte-reader loading-png pass -- lines ) loading-png height>> pass adam7-subimage-height :> height loading-png width>> pass adam7-subimage-width :> width height width * zero? [ B{ } clone ] [ - bit-reader loading-png width height read-scanlines + byte-reader loading-png width height read-scanlines ] if ; :: reverse-interlace-adam7 ( byte-array loading-png -- byte-array ) - byte-array bs: :> bs + byte-array binary :> ba loading-png height>> :> height loading-png width>> :> width loading-png bit-depth>> :> bit-depth @@ -217,7 +225,7 @@ ERROR: bad-filter n ; 0 :> pass! [ pass 7 < ] [ - bs loading-png pass read-adam7-subimage + ba loading-png pass read-adam7-subimage #bytes diff --git a/extra/images/testing/testing.factor b/extra/images/testing/testing.factor index 4dd271aeef..a23a548c25 100644 --- a/extra/images/testing/testing.factor +++ b/extra/images/testing/testing.factor @@ -60,4 +60,7 @@ PRIVATE> ubyte-components >>component-type ; inline : randomize-image ( image -- image ) - dup bytes-per-image random-bytes >>bitmap ; \ No newline at end of file + dup bytes-per-image random-bytes >>bitmap ; + +: image-load-must-fail ( path -- ) + '[ _ load-image ] must-fail ;