1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
19 var filenames
= []string{
41 var filenamesPaletted
= []string{
49 var filenamesShort
= []string{
55 func readPNG(filename
string) (image
.Image
, error
) {
56 f
, err
:= os
.Open(filename
)
64 // An approximation of the sng command-line tool.
65 func sng(w io
.WriteCloser
, filename
string, png image
.Image
) {
67 bounds
:= png
.Bounds()
68 cm
:= png
.ColorModel()
71 case color
.RGBAModel
, color
.NRGBAModel
, color
.AlphaModel
, color
.GrayModel
:
76 cpm
, _
:= cm
.(color
.Palette
)
77 var paletted
*image
.Paletted
89 paletted
= png
.(*image
.Paletted
)
92 // Write the filename and IHDR.
93 io
.WriteString(w
, "#SNG: from "+filename
+".png\nIHDR {\n")
94 fmt
.Fprintf(w
, " width: %d; height: %d; bitdepth: %d;\n", bounds
.Dx(), bounds
.Dy(), bitdepth
)
96 case cm
== color
.RGBAModel
, cm
== color
.RGBA64Model
:
97 io
.WriteString(w
, " using color;\n")
98 case cm
== color
.NRGBAModel
, cm
== color
.NRGBA64Model
:
99 io
.WriteString(w
, " using color alpha;\n")
100 case cm
== color
.GrayModel
, cm
== color
.Gray16Model
:
101 io
.WriteString(w
, " using grayscale;\n")
103 io
.WriteString(w
, " using color palette;\n")
105 io
.WriteString(w
, "unknown PNG decoder color model\n")
107 io
.WriteString(w
, "}\n")
109 // We fake a gAMA output. The test files have a gAMA chunk but the go PNG parser ignores it
110 // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder").
111 io
.WriteString(w
, "gAMA {1.0000}\n")
113 // Write the PLTE and tRNS (if applicable).
116 io
.WriteString(w
, "PLTE {\n")
117 for i
, c
:= range cpm
{
119 switch c
:= c
.(type) {
121 r
, g
, b
, a
= c
.R
, c
.G
, c
.B
, 0xff
123 r
, g
, b
, a
= c
.R
, c
.G
, c
.B
, c
.A
125 panic("unknown palette color type")
130 fmt
.Fprintf(w
, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r
, g
, b
, r
, g
, b
)
132 io
.WriteString(w
, "}\n")
134 io
.WriteString(w
, "tRNS {\n")
135 for i
:= 0; i
<= lastAlpha
; i
++ {
136 _
, _
, _
, a
:= cpm
[i
].RGBA()
138 fmt
.Fprintf(w
, " %d", a
)
140 io
.WriteString(w
, "}\n")
145 io
.WriteString(w
, "IMAGE {\n pixels hex\n")
146 for y
:= bounds
.Min
.Y
; y
< bounds
.Max
.Y
; y
++ {
148 case cm
== color
.GrayModel
:
149 for x
:= bounds
.Min
.X
; x
< bounds
.Max
.X
; x
++ {
150 gray
:= png
.At(x
, y
).(color
.Gray
)
151 fmt
.Fprintf(w
, "%02x", gray
.Y
)
153 case cm
== color
.Gray16Model
:
154 for x
:= bounds
.Min
.X
; x
< bounds
.Max
.X
; x
++ {
155 gray16
:= png
.At(x
, y
).(color
.Gray16
)
156 fmt
.Fprintf(w
, "%04x ", gray16
.Y
)
158 case cm
== color
.RGBAModel
:
159 for x
:= bounds
.Min
.X
; x
< bounds
.Max
.X
; x
++ {
160 rgba
:= png
.At(x
, y
).(color
.RGBA
)
161 fmt
.Fprintf(w
, "%02x%02x%02x ", rgba
.R
, rgba
.G
, rgba
.B
)
163 case cm
== color
.RGBA64Model
:
164 for x
:= bounds
.Min
.X
; x
< bounds
.Max
.X
; x
++ {
165 rgba64
:= png
.At(x
, y
).(color
.RGBA64
)
166 fmt
.Fprintf(w
, "%04x%04x%04x ", rgba64
.R
, rgba64
.G
, rgba64
.B
)
168 case cm
== color
.NRGBAModel
:
169 for x
:= bounds
.Min
.X
; x
< bounds
.Max
.X
; x
++ {
170 nrgba
:= png
.At(x
, y
).(color
.NRGBA
)
171 fmt
.Fprintf(w
, "%02x%02x%02x%02x ", nrgba
.R
, nrgba
.G
, nrgba
.B
, nrgba
.A
)
173 case cm
== color
.NRGBA64Model
:
174 for x
:= bounds
.Min
.X
; x
< bounds
.Max
.X
; x
++ {
175 nrgba64
:= png
.At(x
, y
).(color
.NRGBA64
)
176 fmt
.Fprintf(w
, "%04x%04x%04x%04x ", nrgba64
.R
, nrgba64
.G
, nrgba64
.B
, nrgba64
.A
)
180 for x
:= bounds
.Min
.X
; x
< bounds
.Max
.X
; x
++ {
181 b
= b
<<uint(bitdepth
) |
int(paletted
.ColorIndexAt(x
, y
))
184 fmt
.Fprintf(w
, "%02x", b
)
190 io
.WriteString(w
, "\n")
192 io
.WriteString(w
, "}\n")
195 func TestReader(t
*testing
.T
) {
198 names
= filenamesShort
200 for _
, fn
:= range names
{
201 // Read the .png file.
202 img
, err
:= readPNG("testdata/pngsuite/" + fn
+ ".png")
208 if fn
== "basn4a16" {
209 // basn4a16.sng is gray + alpha but sng() will produce true color + alpha
210 // so we just check a single random pixel.
211 c
:= img
.At(2, 1).(color
.NRGBA64
)
212 if c
.R
!= 0x11a7 || c
.G
!= 0x11a7 || c
.B
!= 0x11a7 || c
.A
!= 0x1085 {
213 t
.Error(fn
, fmt
.Errorf("wrong pixel value at (2, 1): %x", c
))
218 piper
, pipew
:= io
.Pipe()
219 pb
:= bufio
.NewScanner(piper
)
220 go sng(pipew
, fn
, img
)
223 // Read the .sng file.
224 sf
, err
:= os
.Open("testdata/pngsuite/" + fn
+ ".sng")
230 sb
:= bufio
.NewScanner(sf
)
236 // Compare the two, in SNG format, line by line.
244 t
.Errorf("%s: Different sizes", fn
)
250 t
.Errorf("%s: Mismatch\n%sversus\n%s\n", fn
, ps
, ss
)
255 t
.Error(fn
, pb
.Err())
258 t
.Error(fn
, sb
.Err())
263 var readerErrors
= []struct {
267 {"invalid-zlib.png", "zlib: invalid checksum"},
268 {"invalid-crc32.png", "invalid checksum"},
269 {"invalid-noend.png", "unexpected EOF"},
270 {"invalid-trunc.png", "unexpected EOF"},
273 func TestReaderError(t
*testing
.T
) {
274 for _
, tt
:= range readerErrors
{
275 img
, err
:= readPNG("testdata/" + tt
.file
)
277 t
.Errorf("decoding %s: missing error", tt
.file
)
280 if !strings
.Contains(err
.Error(), tt
.err
) {
281 t
.Errorf("decoding %s: %s, want %s", tt
.file
, err
, tt
.err
)
284 t
.Errorf("decoding %s: have image + error", tt
.file
)
289 func TestPalettedDecodeConfig(t
*testing
.T
) {
290 for _
, fn
:= range filenamesPaletted
{
291 f
, err
:= os
.Open("testdata/pngsuite/" + fn
+ ".png")
293 t
.Errorf("%s: open failed: %v", fn
, err
)
297 cfg
, err
:= DecodeConfig(f
)
299 t
.Errorf("%s: %v", fn
, err
)
302 pal
, ok
:= cfg
.ColorModel
.(color
.Palette
)
304 t
.Errorf("%s: expected paletted color model", fn
)
308 t
.Errorf("%s: palette not initialized", fn
)
314 func benchmarkDecode(b
*testing
.B
, filename
string, bytesPerPixel
int) {
316 data
, err
:= ioutil
.ReadFile(filename
)
321 cfg
, err
:= DecodeConfig(strings
.NewReader(s
))
325 b
.SetBytes(int64(cfg
.Width
* cfg
.Height
* bytesPerPixel
))
327 for i
:= 0; i
< b
.N
; i
++ {
328 Decode(strings
.NewReader(s
))
332 func BenchmarkDecodeGray(b
*testing
.B
) {
333 benchmarkDecode(b
, "testdata/benchGray.png", 1)
336 func BenchmarkDecodeNRGBAGradient(b
*testing
.B
) {
337 benchmarkDecode(b
, "testdata/benchNRGBA-gradient.png", 4)
340 func BenchmarkDecodeNRGBAOpaque(b
*testing
.B
) {
341 benchmarkDecode(b
, "testdata/benchNRGBA-opaque.png", 4)
344 func BenchmarkDecodePaletted(b
*testing
.B
) {
345 benchmarkDecode(b
, "testdata/benchPaletted.png", 1)
348 func BenchmarkDecodeRGB(b
*testing
.B
) {
349 benchmarkDecode(b
, "testdata/benchRGB.png", 4)