Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(394)

Delta Between Two Patch Sets: src/pkg/image/png/reader.go

Issue 4964073: code review 4964073: image: change the NewXxx functions to take a Rectangle ... (Closed)
Left Patch Set: diff -r 2892d1e242e6 https://go.googlecode.com/hg/ Created 13 years, 6 months ago
Right Patch Set: diff -r b539ac52c3fd https://go.googlecode.com/hg/ Created 13 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/image/jpeg/reader.go ('k') | src/pkg/image/png/writer_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
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
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
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
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 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b