LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Package png implements a PNG image decoder and encoder. | 5 // Package png implements a PNG image decoder and encoder. |
6 // | 6 // |
7 // The PNG specification is at http://www.libpng.org/pub/png/spec/1.2/PNG-Conten
ts.html | 7 // The PNG specification is at http://www.w3.org/TR/PNG/. |
8 package png | 8 package png |
9 | 9 |
10 import ( | 10 import ( |
11 "compress/zlib" | 11 "compress/zlib" |
| 12 "encoding/binary" |
12 "fmt" | 13 "fmt" |
13 "hash" | 14 "hash" |
14 "hash/crc32" | 15 "hash/crc32" |
15 "image" | 16 "image" |
16 "io" | 17 "io" |
17 "os" | 18 "os" |
18 ) | 19 ) |
19 | 20 |
20 // Color type, as per the PNG spec. | 21 // Color type, as per the PNG spec. |
21 const ( | 22 const ( |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 ftAverage = 3 | 55 ftAverage = 3 |
55 ftPaeth = 4 | 56 ftPaeth = 4 |
56 nFilter = 5 | 57 nFilter = 5 |
57 ) | 58 ) |
58 | 59 |
59 // Decoding stage. | 60 // Decoding stage. |
60 // The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND | 61 // The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND |
61 // chunks must appear in that order. There may be multiple IDAT chunks, and | 62 // chunks must appear in that order. There may be multiple IDAT chunks, and |
62 // IDAT chunks must be sequential (i.e. they may not have any other chunks | 63 // IDAT chunks must be sequential (i.e. they may not have any other chunks |
63 // between them). | 64 // between them). |
| 65 // http://www.w3.org/TR/PNG/#5ChunkOrdering |
64 const ( | 66 const ( |
65 dsStart = iota | 67 dsStart = iota |
66 dsSeenIHDR | 68 dsSeenIHDR |
67 dsSeenPLTE | 69 dsSeenPLTE |
68 dsSeenIDAT | 70 dsSeenIDAT |
69 dsSeenIEND | 71 dsSeenIEND |
70 ) | 72 ) |
71 | 73 |
72 const pngHeader = "\x89PNG\r\n\x1a\n" | 74 const pngHeader = "\x89PNG\r\n\x1a\n" |
73 | 75 |
74 type imgOrErr struct { | |
75 img image.Image | |
76 err os.Error | |
77 } | |
78 | |
79 type decoder struct { | 76 type decoder struct { |
| 77 r io.Reader |
| 78 img image.Image |
| 79 crc hash.Hash32 |
80 width, height int | 80 width, height int |
81 depth int | 81 depth int |
82 palette image.PalettedColorModel | 82 palette image.PalettedColorModel |
83 cb int | 83 cb int |
84 stage int | 84 stage int |
85 » idatWriter io.WriteCloser | 85 » idatLength uint32 |
86 » idatDone chan imgOrErr | |
87 tmp [3 * 256]byte | 86 tmp [3 * 256]byte |
88 } | 87 } |
89 | 88 |
90 // A FormatError reports that the input is not a valid PNG. | 89 // A FormatError reports that the input is not a valid PNG. |
91 type FormatError string | 90 type FormatError string |
92 | 91 |
93 func (e FormatError) String() string { return "png: invalid format: " + string(e
) } | 92 func (e FormatError) String() string { return "png: invalid format: " + string(e
) } |
94 | 93 |
95 var chunkOrderError = FormatError("chunk out of order") | 94 var chunkOrderError = FormatError("chunk out of order") |
96 | 95 |
97 // An IDATDecodingError wraps an inner error (such as a ZLIB decoding error) enc
ountered while processing an IDAT chunk. | |
98 type IDATDecodingError struct { | |
99 Err os.Error | |
100 } | |
101 | |
102 func (e IDATDecodingError) String() string { return "png: IDAT decoding error: "
+ e.Err.String() } | |
103 | |
104 // An UnsupportedError reports that the input uses a valid but unimplemented PNG
feature. | 96 // An UnsupportedError reports that the input uses a valid but unimplemented PNG
feature. |
105 type UnsupportedError string | 97 type UnsupportedError string |
106 | 98 |
107 func (e UnsupportedError) String() string { return "png: unsupported feature: "
+ string(e) } | 99 func (e UnsupportedError) String() string { return "png: unsupported feature: "
+ string(e) } |
108 | |
109 // Big-endian. | |
110 func parseUint32(b []uint8) uint32 { | |
111 return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[
3]) | |
112 } | |
113 | 100 |
114 func abs(x int) int { | 101 func abs(x int) int { |
115 if x < 0 { | 102 if x < 0 { |
116 return -x | 103 return -x |
117 } | 104 } |
118 return x | 105 return x |
119 } | 106 } |
120 | 107 |
121 func min(a, b int) int { | 108 func min(a, b int) int { |
122 if a < b { | 109 if a < b { |
123 return a | 110 return a |
124 } | 111 } |
125 return b | 112 return b |
126 } | 113 } |
127 | 114 |
128 func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Erro
r { | 115 func (d *decoder) parseIHDR(length uint32) os.Error { |
129 if length != 13 { | 116 if length != 13 { |
130 return FormatError("bad IHDR length") | 117 return FormatError("bad IHDR length") |
131 } | 118 } |
132 » _, err := io.ReadFull(r, d.tmp[0:13]) | 119 » if _, err := io.ReadFull(d.r, d.tmp[:13]); err != nil { |
133 » if err != nil { | |
134 return err | 120 return err |
135 } | 121 } |
136 » crc.Write(d.tmp[0:13]) | 122 » d.crc.Write(d.tmp[:13]) |
137 if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 { | 123 if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 { |
138 return UnsupportedError("compression, filter or interlace method
") | 124 return UnsupportedError("compression, filter or interlace method
") |
139 } | 125 } |
140 » w := int32(parseUint32(d.tmp[0:4])) | 126 » w := int32(binary.BigEndian.Uint32(d.tmp[0:4])) |
141 » h := int32(parseUint32(d.tmp[4:8])) | 127 » h := int32(binary.BigEndian.Uint32(d.tmp[4:8])) |
142 if w < 0 || h < 0 { | 128 if w < 0 || h < 0 { |
143 return FormatError("negative dimension") | 129 return FormatError("negative dimension") |
144 } | 130 } |
145 nPixels := int64(w) * int64(h) | 131 nPixels := int64(w) * int64(h) |
146 if nPixels != int64(int(nPixels)) { | 132 if nPixels != int64(int(nPixels)) { |
147 return UnsupportedError("dimension overflow") | 133 return UnsupportedError("dimension overflow") |
148 } | 134 } |
149 d.cb = cbInvalid | 135 d.cb = cbInvalid |
150 d.depth = int(d.tmp[8]) | 136 d.depth = int(d.tmp[8]) |
151 switch d.depth { | 137 switch d.depth { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 case ctGrayscaleAlpha: | 178 case ctGrayscaleAlpha: |
193 d.cb = cbGA16 | 179 d.cb = cbGA16 |
194 case ctTrueColorAlpha: | 180 case ctTrueColorAlpha: |
195 d.cb = cbTCA16 | 181 d.cb = cbTCA16 |
196 } | 182 } |
197 } | 183 } |
198 if d.cb == cbInvalid { | 184 if d.cb == cbInvalid { |
199 return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d
", d.tmp[8], d.tmp[9])) | 185 return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d
", d.tmp[8], d.tmp[9])) |
200 } | 186 } |
201 d.width, d.height = int(w), int(h) | 187 d.width, d.height = int(w), int(h) |
202 » return nil | 188 » return d.verifyChecksum() |
203 } | 189 } |
204 | 190 |
205 func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Erro
r { | 191 func (d *decoder) parsePLTE(length uint32) os.Error { |
206 np := int(length / 3) // The number of palette entries. | 192 np := int(length / 3) // The number of palette entries. |
207 if length%3 != 0 || np <= 0 || np > 256 || np > 1<<uint(d.depth) { | 193 if length%3 != 0 || np <= 0 || np > 256 || np > 1<<uint(d.depth) { |
208 return FormatError("bad PLTE length") | 194 return FormatError("bad PLTE length") |
209 } | 195 } |
210 » n, err := io.ReadFull(r, d.tmp[0:3*np]) | 196 » n, err := io.ReadFull(d.r, d.tmp[:3*np]) |
211 if err != nil { | 197 if err != nil { |
212 return err | 198 return err |
213 } | 199 } |
214 » crc.Write(d.tmp[0:n]) | 200 » d.crc.Write(d.tmp[:n]) |
215 switch d.cb { | 201 switch d.cb { |
216 case cbP1, cbP2, cbP4, cbP8: | 202 case cbP1, cbP2, cbP4, cbP8: |
217 d.palette = image.PalettedColorModel(make([]image.Color, np)) | 203 d.palette = image.PalettedColorModel(make([]image.Color, np)) |
218 for i := 0; i < np; i++ { | 204 for i := 0; i < np; i++ { |
219 d.palette[i] = image.RGBAColor{d.tmp[3*i+0], d.tmp[3*i+1
], d.tmp[3*i+2], 0xff} | 205 d.palette[i] = image.RGBAColor{d.tmp[3*i+0], d.tmp[3*i+1
], d.tmp[3*i+2], 0xff} |
220 } | 206 } |
221 case cbTC8, cbTCA8, cbTC16, cbTCA16: | 207 case cbTC8, cbTCA8, cbTC16, cbTCA16: |
222 // As per the PNG spec, a PLTE chunk is optional (and for practi
cal purposes, | 208 // As per the PNG spec, a PLTE chunk is optional (and for practi
cal purposes, |
223 // ignorable) for the ctTrueColor and ctTrueColorAlpha color typ
es (section 4.1.2). | 209 // ignorable) for the ctTrueColor and ctTrueColorAlpha color typ
es (section 4.1.2). |
224 default: | 210 default: |
225 return FormatError("PLTE, color type mismatch") | 211 return FormatError("PLTE, color type mismatch") |
226 } | 212 } |
227 » return nil | 213 » return d.verifyChecksum() |
228 } | 214 } |
229 | 215 |
230 func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Erro
r { | 216 func (d *decoder) parsetRNS(length uint32) os.Error { |
231 if length > 256 { | 217 if length > 256 { |
232 return FormatError("bad tRNS length") | 218 return FormatError("bad tRNS length") |
233 } | 219 } |
234 » n, err := io.ReadFull(r, d.tmp[0:length]) | 220 » n, err := io.ReadFull(d.r, d.tmp[:length]) |
235 if err != nil { | 221 if err != nil { |
236 return err | 222 return err |
237 } | 223 } |
238 » crc.Write(d.tmp[0:n]) | 224 » d.crc.Write(d.tmp[:n]) |
239 switch d.cb { | 225 switch d.cb { |
240 case cbG8, cbG16: | 226 case cbG8, cbG16: |
241 return UnsupportedError("grayscale transparency") | 227 return UnsupportedError("grayscale transparency") |
242 case cbTC8, cbTC16: | 228 case cbTC8, cbTC16: |
243 return UnsupportedError("truecolor transparency") | 229 return UnsupportedError("truecolor transparency") |
244 case cbP1, cbP2, cbP4, cbP8: | 230 case cbP1, cbP2, cbP4, cbP8: |
245 if n > len(d.palette) { | 231 if n > len(d.palette) { |
246 return FormatError("bad tRNS length") | 232 return FormatError("bad tRNS length") |
247 } | 233 } |
248 for i := 0; i < n; i++ { | 234 for i := 0; i < n; i++ { |
249 rgba := d.palette[i].(image.RGBAColor) | 235 rgba := d.palette[i].(image.RGBAColor) |
250 d.palette[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d
.tmp[i]} | 236 d.palette[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d
.tmp[i]} |
251 } | 237 } |
252 case cbGA8, cbGA16, cbTCA8, cbTCA16: | 238 case cbGA8, cbGA16, cbTCA8, cbTCA16: |
253 return FormatError("tRNS, color type mismatch") | 239 return FormatError("tRNS, color type mismatch") |
254 } | 240 } |
255 » return nil | 241 » return d.verifyChecksum() |
256 } | 242 } |
257 | 243 |
258 // The Paeth filter function, as per the PNG specification. | 244 // The Paeth filter function, as per the PNG specification. |
259 func paeth(a, b, c uint8) uint8 { | 245 func paeth(a, b, c uint8) uint8 { |
260 p := int(a) + int(b) - int(c) | 246 p := int(a) + int(b) - int(c) |
261 pa := abs(p - int(a)) | 247 pa := abs(p - int(a)) |
262 pb := abs(p - int(b)) | 248 pb := abs(p - int(b)) |
263 pc := abs(p - int(c)) | 249 pc := abs(p - int(c)) |
264 if pa <= pb && pa <= pc { | 250 if pa <= pb && pa <= pc { |
265 return a | 251 return a |
266 } else if pb <= pc { | 252 } else if pb <= pc { |
267 return b | 253 return b |
268 } | 254 } |
269 return c | 255 return c |
270 } | 256 } |
271 | 257 |
272 func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) { | 258 // Read presents one or more IDAT chunks as one continuous stream (minus the |
273 » r, err := zlib.NewReader(idat) | 259 // intermediate chunk headers and footers). If the PNG data looked like: |
| 260 // ... len0 IDAT xxx crc0 len1 IDAT yy crc1 len2 IEND crc2 |
| 261 // then this reader presents xxxyy. For well-formed PNG data, the decoder state |
| 262 // immediately before the first Read call is that d.r is positioned between the |
| 263 // first IDAT and xxx, and the decoder state immediately after the last Read |
| 264 // call is that d.r is positioned between yy and crc1. |
| 265 func (d *decoder) Read(p []byte) (int, os.Error) { |
| 266 » if len(p) == 0 { |
| 267 » » return 0, nil |
| 268 » } |
| 269 » for d.idatLength == 0 { |
| 270 » » // We have exhausted an IDAT chunk. Verify the checksum of that
chunk. |
| 271 » » if err := d.verifyChecksum(); err != nil { |
| 272 » » » return 0, err |
| 273 » » } |
| 274 » » // Read the length and chunk type of the next chunk, and check t
hat |
| 275 » » // it is an IDAT chunk. |
| 276 » » if _, err := io.ReadFull(d.r, d.tmp[:8]); err != nil { |
| 277 » » » return 0, err |
| 278 » » } |
| 279 » » d.idatLength = binary.BigEndian.Uint32(d.tmp[:4]) |
| 280 » » if string(d.tmp[4:8]) != "IDAT" { |
| 281 » » » return 0, FormatError("not enough pixel data") |
| 282 » » } |
| 283 » » d.crc.Reset() |
| 284 » » d.crc.Write(d.tmp[4:8]) |
| 285 » } |
| 286 » if int(d.idatLength) < 0 { |
| 287 » » return 0, UnsupportedError("IDAT chunk length overflow") |
| 288 » } |
| 289 » n, err := d.r.Read(p[:min(len(p), int(d.idatLength))]) |
| 290 » d.crc.Write(p[:n]) |
| 291 » d.idatLength -= uint32(n) |
| 292 » return n, err |
| 293 } |
| 294 |
| 295 // decode decodes the IDAT data into an image. |
| 296 func (d *decoder) decode() (image.Image, os.Error) { |
| 297 » r, err := zlib.NewReader(d) |
274 if err != nil { | 298 if err != nil { |
275 return nil, err | 299 return nil, err |
276 } | 300 } |
277 defer r.Close() | 301 defer r.Close() |
278 bitsPerPixel := 0 | 302 bitsPerPixel := 0 |
279 maxPalette := uint8(0) | 303 maxPalette := uint8(0) |
280 var ( | 304 var ( |
281 gray *image.Gray | 305 gray *image.Gray |
282 rgba *image.RGBA | 306 rgba *image.RGBA |
283 paletted *image.Paletted | 307 paletted *image.Paletted |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
488 | 512 |
489 // The current row for y is the previous row for y+1. | 513 // The current row for y is the previous row for y+1. |
490 pr, cr = cr, pr | 514 pr, cr = cr, pr |
491 } | 515 } |
492 | 516 |
493 // Check for EOF, to verify the zlib checksum. | 517 // Check for EOF, to verify the zlib checksum. |
494 n, err := r.Read(pr[:1]) | 518 n, err := r.Read(pr[:1]) |
495 if err != os.EOF { | 519 if err != os.EOF { |
496 return nil, FormatError(err.String()) | 520 return nil, FormatError(err.String()) |
497 } | 521 } |
498 » if n != 0 { | 522 » if n != 0 || d.idatLength != 0 { |
499 return nil, FormatError("too much pixel data") | 523 return nil, FormatError("too much pixel data") |
500 } | 524 } |
501 | 525 |
502 return img, nil | 526 return img, nil |
503 } | 527 } |
504 | 528 |
505 func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Erro
r { | 529 func (d *decoder) parseIDAT(length uint32) (err os.Error) { |
506 » // There may be more than one IDAT chunk, but their contents must be | 530 » d.idatLength = length |
507 » // treated as if it was one continuous stream (to the zlib decoder). | 531 » d.img, err = d.decode() |
508 » // We bring up an io.Pipe and write the IDAT chunks into the pipe as | 532 » if err != nil { |
509 » // we see them, and decode the stream in a separate go-routine, which | 533 » » return err |
510 » // signals its completion (successful or not) via a channel. | 534 » } |
511 » if d.idatWriter == nil { | 535 » return d.verifyChecksum() |
512 » » pr, pw := io.Pipe() | 536 } |
513 » » d.idatWriter = pw | 537 |
514 » » d.idatDone = make(chan imgOrErr) | 538 func (d *decoder) parseIEND(length uint32) os.Error { |
515 » » go func() { | |
516 » » » img, err := d.idatReader(pr) | |
517 » » » if err == os.EOF { | |
518 » » » » err = FormatError("too little IDAT") | |
519 » » » } | |
520 » » » pr.CloseWithError(FormatError("too much IDAT")) | |
521 » » » d.idatDone <- imgOrErr{img, err} | |
522 » » }() | |
523 » } | |
524 » var buf [4096]byte | |
525 » for length > 0 { | |
526 » » n, err1 := r.Read(buf[0:min(len(buf), int(length))]) | |
527 » » // We delay checking err1. It is possible to get n bytes and an
error, | |
528 » » // but if the n bytes themselves contain a FormatError, for exam
ple, we | |
529 » » // want to report that error, and not the one that made the Read
stop. | |
530 » » n, err2 := d.idatWriter.Write(buf[0:n]) | |
531 » » if err2 != nil { | |
532 » » » return err2 | |
533 » » } | |
534 » » if err1 != nil { | |
535 » » » return err1 | |
536 » » } | |
537 » » crc.Write(buf[0:n]) | |
538 » » length -= uint32(n) | |
539 » } | |
540 » return nil | |
541 } | |
542 | |
543 func (d *decoder) parseIEND(r io.Reader, crc hash.Hash32, length uint32) os.Erro
r { | |
544 if length != 0 { | 539 if length != 0 { |
545 return FormatError("bad IEND length") | 540 return FormatError("bad IEND length") |
546 } | 541 } |
547 » return nil | 542 » return d.verifyChecksum() |
548 } | 543 } |
549 | 544 |
550 func (d *decoder) parseChunk(r io.Reader) os.Error { | 545 func (d *decoder) parseChunk() os.Error { |
551 » // Read the length. | 546 » // Read the length and chunk type. |
552 » n, err := io.ReadFull(r, d.tmp[0:4]) | 547 » n, err := io.ReadFull(d.r, d.tmp[:8]) |
553 » if err == os.EOF { | |
554 » » return io.ErrUnexpectedEOF | |
555 » } | |
556 if err != nil { | 548 if err != nil { |
557 return err | 549 return err |
558 } | 550 } |
559 » length := parseUint32(d.tmp[0:4]) | 551 » length := binary.BigEndian.Uint32(d.tmp[:4]) |
560 | 552 » d.crc.Reset() |
561 » // Read the chunk type. | 553 » d.crc.Write(d.tmp[4:8]) |
562 » n, err = io.ReadFull(r, d.tmp[0:4]) | |
563 » if err == os.EOF { | |
564 » » return io.ErrUnexpectedEOF | |
565 » } | |
566 » if err != nil { | |
567 » » return err | |
568 » } | |
569 » crc := crc32.NewIEEE() | |
570 » crc.Write(d.tmp[0:4]) | |
571 | 554 |
572 // Read the chunk data. | 555 // Read the chunk data. |
573 » switch string(d.tmp[0:4]) { | 556 » switch string(d.tmp[4:8]) { |
574 case "IHDR": | 557 case "IHDR": |
575 if d.stage != dsStart { | 558 if d.stage != dsStart { |
576 return chunkOrderError | 559 return chunkOrderError |
577 } | 560 } |
578 d.stage = dsSeenIHDR | 561 d.stage = dsSeenIHDR |
579 » » err = d.parseIHDR(r, crc, length) | 562 » » return d.parseIHDR(length) |
580 case "PLTE": | 563 case "PLTE": |
581 if d.stage != dsSeenIHDR { | 564 if d.stage != dsSeenIHDR { |
582 return chunkOrderError | 565 return chunkOrderError |
583 } | 566 } |
584 d.stage = dsSeenPLTE | 567 d.stage = dsSeenPLTE |
585 » » err = d.parsePLTE(r, crc, length) | 568 » » return d.parsePLTE(length) |
586 case "tRNS": | 569 case "tRNS": |
587 if d.stage != dsSeenPLTE { | 570 if d.stage != dsSeenPLTE { |
588 return chunkOrderError | 571 return chunkOrderError |
589 } | 572 } |
590 » » err = d.parsetRNS(r, crc, length) | 573 » » return d.parsetRNS(length) |
591 case "IDAT": | 574 case "IDAT": |
592 if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8
&& d.stage == dsSeenIHDR) { | 575 if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8
&& d.stage == dsSeenIHDR) { |
593 return chunkOrderError | 576 return chunkOrderError |
594 } | 577 } |
595 d.stage = dsSeenIDAT | 578 d.stage = dsSeenIDAT |
596 » » err = d.parseIDAT(r, crc, length) | 579 » » return d.parseIDAT(length) |
597 case "IEND": | 580 case "IEND": |
598 if d.stage != dsSeenIDAT { | 581 if d.stage != dsSeenIDAT { |
599 return chunkOrderError | 582 return chunkOrderError |
600 } | 583 } |
601 d.stage = dsSeenIEND | 584 d.stage = dsSeenIEND |
602 » » err = d.parseIEND(r, crc, length) | 585 » » return d.parseIEND(length) |
603 » default: | 586 » } |
604 » » // Ignore this chunk (of a known length). | 587 » // Ignore this chunk (of a known length). |
605 » » var ignored [4096]byte | 588 » var ignored [4096]byte |
606 » » for length > 0 { | 589 » for length > 0 { |
607 » » » n, err = io.ReadFull(r, ignored[0:min(len(ignored), int(
length))]) | 590 » » n, err = io.ReadFull(d.r, ignored[:min(len(ignored), int(length)
)]) |
608 » » » if err != nil { | 591 » » if err != nil { |
609 » » » » return err | 592 » » » return err |
610 » » » } | 593 » » } |
611 » » » crc.Write(ignored[0:n]) | 594 » » d.crc.Write(ignored[:n]) |
612 » » » length -= uint32(n) | 595 » » length -= uint32(n) |
613 » » } | 596 » } |
614 » } | 597 » return d.verifyChecksum() |
| 598 } |
| 599 |
| 600 func (d *decoder) verifyChecksum() os.Error { |
| 601 » if _, err := io.ReadFull(d.r, d.tmp[:4]); err != nil { |
| 602 » » return err |
| 603 » } |
| 604 » if binary.BigEndian.Uint32(d.tmp[:4]) != d.crc.Sum32() { |
| 605 » » return FormatError("invalid checksum") |
| 606 » } |
| 607 » return nil |
| 608 } |
| 609 |
| 610 func (d *decoder) checkHeader() os.Error { |
| 611 » _, err := io.ReadFull(d.r, d.tmp[:len(pngHeader)]) |
615 if err != nil { | 612 if err != nil { |
616 return err | 613 return err |
617 } | 614 } |
618 | 615 » if string(d.tmp[:len(pngHeader)]) != pngHeader { |
619 » // Read the checksum. | |
620 » n, err = io.ReadFull(r, d.tmp[0:4]) | |
621 » if err == os.EOF { | |
622 » » return io.ErrUnexpectedEOF | |
623 » } | |
624 » if err != nil { | |
625 » » return err | |
626 » } | |
627 » if parseUint32(d.tmp[0:4]) != crc.Sum32() { | |
628 » » return FormatError("invalid checksum") | |
629 » } | |
630 » return nil | |
631 } | |
632 | |
633 func (d *decoder) checkHeader(r io.Reader) os.Error { | |
634 » _, err := io.ReadFull(r, d.tmp[0:8]) | |
635 » if err != nil { | |
636 » » return err | |
637 » } | |
638 » if string(d.tmp[0:8]) != pngHeader { | |
639 return FormatError("not a PNG file") | 616 return FormatError("not a PNG file") |
640 } | 617 } |
641 return nil | 618 return nil |
642 } | 619 } |
643 | 620 |
644 // Decode reads a PNG image from r and returns it as an image.Image. | 621 // Decode reads a PNG image from r and returns it as an image.Image. |
645 // The type of Image returned depends on the PNG contents. | 622 // The type of Image returned depends on the PNG contents. |
646 func Decode(r io.Reader) (image.Image, os.Error) { | 623 func Decode(r io.Reader) (image.Image, os.Error) { |
647 » var d decoder | 624 » d := &decoder{ |
648 » err := d.checkHeader(r) | 625 » » r: r, |
649 » if err != nil { | 626 » » crc: crc32.NewIEEE(), |
| 627 » } |
| 628 » if err := d.checkHeader(); err != nil { |
| 629 » » if err == os.EOF { |
| 630 » » » err = io.ErrUnexpectedEOF |
| 631 » » } |
650 return nil, err | 632 return nil, err |
651 } | 633 } |
652 for d.stage != dsSeenIEND { | 634 for d.stage != dsSeenIEND { |
653 » » err = d.parseChunk(r) | 635 » » if err := d.parseChunk(); err != nil { |
654 » » if err != nil { | 636 » » » if err == os.EOF { |
655 » » » break | 637 » » » » err = io.ErrUnexpectedEOF |
656 » » } | 638 » » » } |
657 » } | 639 » » » return nil, err |
658 » var img image.Image | 640 » » } |
659 » if d.idatWriter != nil { | 641 » } |
660 » » d.idatWriter.Close() | 642 » return d.img, nil |
661 » » ie := <-d.idatDone | |
662 » » if err == nil { | |
663 » » » img, err = ie.img, ie.err | |
664 » » } | |
665 » } | |
666 » if err != nil { | |
667 » » return nil, err | |
668 » } | |
669 » return img, nil | |
670 } | 643 } |
671 | 644 |
672 // DecodeConfig returns the color model and dimensions of a PNG image without | 645 // DecodeConfig returns the color model and dimensions of a PNG image without |
673 // decoding the entire image. | 646 // decoding the entire image. |
674 func DecodeConfig(r io.Reader) (image.Config, os.Error) { | 647 func DecodeConfig(r io.Reader) (image.Config, os.Error) { |
675 » var d decoder | 648 » d := &decoder{ |
676 » err := d.checkHeader(r) | 649 » » r: r, |
677 » if err != nil { | 650 » » crc: crc32.NewIEEE(), |
| 651 » } |
| 652 » if err := d.checkHeader(); err != nil { |
| 653 » » if err == os.EOF { |
| 654 » » » err = io.ErrUnexpectedEOF |
| 655 » » } |
678 return image.Config{}, err | 656 return image.Config{}, err |
679 } | 657 } |
680 for { | 658 for { |
681 » » err = d.parseChunk(r) | 659 » » if err := d.parseChunk(); err != nil { |
682 » » if err != nil { | 660 » » » if err == os.EOF { |
| 661 » » » » err = io.ErrUnexpectedEOF |
| 662 » » » } |
683 return image.Config{}, err | 663 return image.Config{}, err |
684 } | 664 } |
685 if d.stage == dsSeenIHDR && d.cb != cbP8 { | 665 if d.stage == dsSeenIHDR && d.cb != cbP8 { |
686 break | 666 break |
687 } | 667 } |
688 if d.stage == dsSeenPLTE && d.cb == cbP8 { | 668 if d.stage == dsSeenPLTE && d.cb == cbP8 { |
689 break | 669 break |
690 } | 670 } |
691 } | 671 } |
692 var cm image.ColorModel | 672 var cm image.ColorModel |
(...skipping 16 matching lines...) Expand all Loading... |
709 cm = image.RGBA64ColorModel | 689 cm = image.RGBA64ColorModel |
710 case cbTCA16: | 690 case cbTCA16: |
711 cm = image.NRGBA64ColorModel | 691 cm = image.NRGBA64ColorModel |
712 } | 692 } |
713 return image.Config{cm, d.width, d.height}, nil | 693 return image.Config{cm, d.width, d.height}, nil |
714 } | 694 } |
715 | 695 |
716 func init() { | 696 func init() { |
717 image.RegisterFormat("png", pngHeader, Decode, DecodeConfig) | 697 image.RegisterFormat("png", pngHeader, Decode, DecodeConfig) |
718 } | 698 } |
LEFT | RIGHT |