github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/image/png/writer_test.go (about) 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. 4 5 package png 6 7 import ( 8 "bytes" 9 "compress/zlib" 10 "encoding/binary" 11 "fmt" 12 "image" 13 "image/color" 14 "io" 15 "io/ioutil" 16 "testing" 17 ) 18 19 func diff(m0, m1 image.Image) error { 20 b0, b1 := m0.Bounds(), m1.Bounds() 21 if !b0.Size().Eq(b1.Size()) { 22 return fmt.Errorf("dimensions differ: %v vs %v", b0, b1) 23 } 24 dx := b1.Min.X - b0.Min.X 25 dy := b1.Min.Y - b0.Min.Y 26 for y := b0.Min.Y; y < b0.Max.Y; y++ { 27 for x := b0.Min.X; x < b0.Max.X; x++ { 28 c0 := m0.At(x, y) 29 c1 := m1.At(x+dx, y+dy) 30 r0, g0, b0, a0 := c0.RGBA() 31 r1, g1, b1, a1 := c1.RGBA() 32 if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 { 33 return fmt.Errorf("colors differ at (%d, %d): %v vs %v", x, y, c0, c1) 34 } 35 } 36 } 37 return nil 38 } 39 40 func encodeDecode(m image.Image) (image.Image, error) { 41 var b bytes.Buffer 42 err := Encode(&b, m) 43 if err != nil { 44 return nil, err 45 } 46 return Decode(&b) 47 } 48 49 func TestWriter(t *testing.T) { 50 // The filenames variable is declared in reader_test.go. 51 names := filenames 52 if testing.Short() { 53 names = filenamesShort 54 } 55 for _, fn := range names { 56 qfn := "testdata/pngsuite/" + fn + ".png" 57 // Read the image. 58 m0, err := readPNG(qfn) 59 if err != nil { 60 t.Error(fn, err) 61 continue 62 } 63 // Read the image again, encode it, and decode it. 64 m1, err := readPNG(qfn) 65 if err != nil { 66 t.Error(fn, err) 67 continue 68 } 69 m2, err := encodeDecode(m1) 70 if err != nil { 71 t.Error(fn, err) 72 continue 73 } 74 // Compare the two. 75 err = diff(m0, m2) 76 if err != nil { 77 t.Error(fn, err) 78 continue 79 } 80 } 81 } 82 83 func TestWriterPaletted(t *testing.T) { 84 const width, height = 32, 16 85 86 testCases := []struct { 87 plen int 88 bitdepth uint8 89 datalen int 90 }{ 91 92 { 93 plen: 256, 94 bitdepth: 8, 95 datalen: (1 + width) * height, 96 }, 97 98 { 99 plen: 128, 100 bitdepth: 8, 101 datalen: (1 + width) * height, 102 }, 103 104 { 105 plen: 16, 106 bitdepth: 4, 107 datalen: (1 + width/2) * height, 108 }, 109 110 { 111 plen: 4, 112 bitdepth: 2, 113 datalen: (1 + width/4) * height, 114 }, 115 116 { 117 plen: 2, 118 bitdepth: 1, 119 datalen: (1 + width/8) * height, 120 }, 121 } 122 123 for _, tc := range testCases { 124 t.Run(fmt.Sprintf("plen-%d", tc.plen), func(t *testing.T) { 125 // Create a paletted image with the correct palette length 126 palette := make(color.Palette, tc.plen) 127 for i := range palette { 128 palette[i] = color.NRGBA{ 129 R: uint8(i), 130 G: uint8(i), 131 B: uint8(i), 132 A: 255, 133 } 134 } 135 m0 := image.NewPaletted(image.Rect(0, 0, width, height), palette) 136 137 i := 0 138 for y := 0; y < height; y++ { 139 for x := 0; x < width; x++ { 140 m0.SetColorIndex(x, y, uint8(i%tc.plen)) 141 i++ 142 } 143 } 144 145 // Encode the image 146 var b bytes.Buffer 147 if err := Encode(&b, m0); err != nil { 148 t.Error(err) 149 return 150 } 151 const chunkFieldsLength = 12 // 4 bytes for length, name and crc 152 data := b.Bytes() 153 i = len(pngHeader) 154 155 for i < len(data)-chunkFieldsLength { 156 length := binary.BigEndian.Uint32(data[i : i+4]) 157 name := string(data[i+4 : i+8]) 158 159 switch name { 160 case "IHDR": 161 bitdepth := data[i+8+8] 162 if bitdepth != tc.bitdepth { 163 t.Errorf("got bitdepth %d, want %d", bitdepth, tc.bitdepth) 164 } 165 case "IDAT": 166 // Uncompress the image data 167 r, err := zlib.NewReader(bytes.NewReader(data[i+8 : i+8+int(length)])) 168 if err != nil { 169 t.Error(err) 170 return 171 } 172 n, err := io.Copy(ioutil.Discard, r) 173 if err != nil { 174 t.Errorf("got error while reading image data: %v", err) 175 } 176 if n != int64(tc.datalen) { 177 t.Errorf("got uncompressed data length %d, want %d", n, tc.datalen) 178 } 179 } 180 181 i += chunkFieldsLength + int(length) 182 } 183 }) 184 185 } 186 } 187 188 func TestWriterLevels(t *testing.T) { 189 m := image.NewNRGBA(image.Rect(0, 0, 100, 100)) 190 191 var b1, b2 bytes.Buffer 192 if err := (&Encoder{}).Encode(&b1, m); err != nil { 193 t.Fatal(err) 194 } 195 noenc := &Encoder{CompressionLevel: NoCompression} 196 if err := noenc.Encode(&b2, m); err != nil { 197 t.Fatal(err) 198 } 199 200 if b2.Len() <= b1.Len() { 201 t.Error("DefaultCompression encoding was larger than NoCompression encoding") 202 } 203 if _, err := Decode(&b1); err != nil { 204 t.Error("cannot decode DefaultCompression") 205 } 206 if _, err := Decode(&b2); err != nil { 207 t.Error("cannot decode NoCompression") 208 } 209 } 210 211 func TestSubImage(t *testing.T) { 212 m0 := image.NewRGBA(image.Rect(0, 0, 256, 256)) 213 for y := 0; y < 256; y++ { 214 for x := 0; x < 256; x++ { 215 m0.Set(x, y, color.RGBA{uint8(x), uint8(y), 0, 255}) 216 } 217 } 218 m0 = m0.SubImage(image.Rect(50, 30, 250, 130)).(*image.RGBA) 219 m1, err := encodeDecode(m0) 220 if err != nil { 221 t.Error(err) 222 return 223 } 224 err = diff(m0, m1) 225 if err != nil { 226 t.Error(err) 227 return 228 } 229 } 230 231 func BenchmarkEncodeGray(b *testing.B) { 232 img := image.NewGray(image.Rect(0, 0, 640, 480)) 233 b.SetBytes(640 * 480 * 1) 234 b.ReportAllocs() 235 b.ResetTimer() 236 for i := 0; i < b.N; i++ { 237 Encode(ioutil.Discard, img) 238 } 239 } 240 241 type pool struct { 242 b *EncoderBuffer 243 } 244 245 func (p *pool) Get() *EncoderBuffer { 246 return p.b 247 } 248 249 func (p *pool) Put(b *EncoderBuffer) { 250 p.b = b 251 } 252 253 func BenchmarkEncodeGrayWithBufferPool(b *testing.B) { 254 img := image.NewGray(image.Rect(0, 0, 640, 480)) 255 e := Encoder{ 256 BufferPool: &pool{}, 257 } 258 b.SetBytes(640 * 480 * 1) 259 b.ReportAllocs() 260 b.ResetTimer() 261 for i := 0; i < b.N; i++ { 262 e.Encode(ioutil.Discard, img) 263 } 264 } 265 266 func BenchmarkEncodeNRGBOpaque(b *testing.B) { 267 img := image.NewNRGBA(image.Rect(0, 0, 640, 480)) 268 // Set all pixels to 0xFF alpha to force opaque mode. 269 bo := img.Bounds() 270 for y := bo.Min.Y; y < bo.Max.Y; y++ { 271 for x := bo.Min.X; x < bo.Max.X; x++ { 272 img.Set(x, y, color.NRGBA{0, 0, 0, 255}) 273 } 274 } 275 if !img.Opaque() { 276 b.Fatal("expected image to be opaque") 277 } 278 b.SetBytes(640 * 480 * 4) 279 b.ReportAllocs() 280 b.ResetTimer() 281 for i := 0; i < b.N; i++ { 282 Encode(ioutil.Discard, img) 283 } 284 } 285 286 func BenchmarkEncodeNRGBA(b *testing.B) { 287 img := image.NewNRGBA(image.Rect(0, 0, 640, 480)) 288 if img.Opaque() { 289 b.Fatal("expected image not to be opaque") 290 } 291 b.SetBytes(640 * 480 * 4) 292 b.ReportAllocs() 293 b.ResetTimer() 294 for i := 0; i < b.N; i++ { 295 Encode(ioutil.Discard, img) 296 } 297 } 298 299 func BenchmarkEncodePaletted(b *testing.B) { 300 img := image.NewPaletted(image.Rect(0, 0, 640, 480), color.Palette{ 301 color.RGBA{0, 0, 0, 255}, 302 color.RGBA{255, 255, 255, 255}, 303 }) 304 b.SetBytes(640 * 480 * 1) 305 b.ReportAllocs() 306 b.ResetTimer() 307 for i := 0; i < b.N; i++ { 308 Encode(ioutil.Discard, img) 309 } 310 } 311 312 func BenchmarkEncodeRGBOpaque(b *testing.B) { 313 img := image.NewRGBA(image.Rect(0, 0, 640, 480)) 314 // Set all pixels to 0xFF alpha to force opaque mode. 315 bo := img.Bounds() 316 for y := bo.Min.Y; y < bo.Max.Y; y++ { 317 for x := bo.Min.X; x < bo.Max.X; x++ { 318 img.Set(x, y, color.RGBA{0, 0, 0, 255}) 319 } 320 } 321 if !img.Opaque() { 322 b.Fatal("expected image to be opaque") 323 } 324 b.SetBytes(640 * 480 * 4) 325 b.ReportAllocs() 326 b.ResetTimer() 327 for i := 0; i < b.N; i++ { 328 Encode(ioutil.Discard, img) 329 } 330 } 331 332 func BenchmarkEncodeRGBA(b *testing.B) { 333 img := image.NewRGBA(image.Rect(0, 0, 640, 480)) 334 if img.Opaque() { 335 b.Fatal("expected image not to be opaque") 336 } 337 b.SetBytes(640 * 480 * 4) 338 b.ReportAllocs() 339 b.ResetTimer() 340 for i := 0; i < b.N; i++ { 341 Encode(ioutil.Discard, img) 342 } 343 }