8c76afa72c6a02e99b49fc45cc2d21cde4bccc20
[platform/upstream/gcc.git] / libgo / go / image / png / reader.go
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 implements a PNG image decoder and encoder.
6 //
7 // The PNG specification is at http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html
8 package png
9
10 import (
11         "compress/zlib"
12         "fmt"
13         "hash"
14         "hash/crc32"
15         "image"
16         "io"
17         "os"
18 )
19
20 // Color type, as per the PNG spec.
21 const (
22         ctGrayscale      = 0
23         ctTrueColor      = 2
24         ctPaletted       = 3
25         ctGrayscaleAlpha = 4
26         ctTrueColorAlpha = 6
27 )
28
29 // A cb is a combination of color type and bit depth.
30 const (
31         cbInvalid = iota
32         cbG1
33         cbG2
34         cbG4
35         cbG8
36         cbGA8
37         cbTC8
38         cbP1
39         cbP2
40         cbP4
41         cbP8
42         cbTCA8
43         cbG16
44         cbGA16
45         cbTC16
46         cbTCA16
47 )
48
49 // Filter type, as per the PNG spec.
50 const (
51         ftNone    = 0
52         ftSub     = 1
53         ftUp      = 2
54         ftAverage = 3
55         ftPaeth   = 4
56         nFilter   = 5
57 )
58
59 // Decoding stage.
60 // 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 // IDAT chunks must be sequential (i.e. they may not have any other chunks
63 // between them).
64 const (
65         dsStart = iota
66         dsSeenIHDR
67         dsSeenPLTE
68         dsSeenIDAT
69         dsSeenIEND
70 )
71
72 const pngHeader = "\x89PNG\r\n\x1a\n"
73
74 type imgOrErr struct {
75         img image.Image
76         err os.Error
77 }
78
79 type decoder struct {
80         width, height int
81         depth         int
82         palette       image.PalettedColorModel
83         cb            int
84         stage         int
85         idatWriter    io.WriteCloser
86         idatDone      chan imgOrErr
87         tmp           [3 * 256]byte
88 }
89
90 // A FormatError reports that the input is not a valid PNG.
91 type FormatError string
92
93 func (e FormatError) String() string { return "png: invalid format: " + string(e) }
94
95 var chunkOrderError = FormatError("chunk out of order")
96
97 // An IDATDecodingError wraps an inner error (such as a ZLIB decoding error) encountered 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.
105 type UnsupportedError string
106
107 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
114 func abs(x int) int {
115         if x < 0 {
116                 return -x
117         }
118         return x
119 }
120
121 func min(a, b int) int {
122         if a < b {
123                 return a
124         }
125         return b
126 }
127
128 func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Error {
129         if length != 13 {
130                 return FormatError("bad IHDR length")
131         }
132         _, err := io.ReadFull(r, d.tmp[0:13])
133         if err != nil {
134                 return err
135         }
136         crc.Write(d.tmp[0:13])
137         if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
138                 return UnsupportedError("compression, filter or interlace method")
139         }
140         w := int32(parseUint32(d.tmp[0:4]))
141         h := int32(parseUint32(d.tmp[4:8]))
142         if w < 0 || h < 0 {
143                 return FormatError("negative dimension")
144         }
145         nPixels := int64(w) * int64(h)
146         if nPixels != int64(int(nPixels)) {
147                 return UnsupportedError("dimension overflow")
148         }
149         d.cb = cbInvalid
150         d.depth = int(d.tmp[8])
151         switch d.depth {
152         case 1:
153                 switch d.tmp[9] {
154                 case ctGrayscale:
155                         d.cb = cbG1
156                 case ctPaletted:
157                         d.cb = cbP1
158                 }
159         case 2:
160                 switch d.tmp[9] {
161                 case ctGrayscale:
162                         d.cb = cbG2
163                 case ctPaletted:
164                         d.cb = cbP2
165                 }
166         case 4:
167                 switch d.tmp[9] {
168                 case ctGrayscale:
169                         d.cb = cbG4
170                 case ctPaletted:
171                         d.cb = cbP4
172                 }
173         case 8:
174                 switch d.tmp[9] {
175                 case ctGrayscale:
176                         d.cb = cbG8
177                 case ctTrueColor:
178                         d.cb = cbTC8
179                 case ctPaletted:
180                         d.cb = cbP8
181                 case ctGrayscaleAlpha:
182                         d.cb = cbGA8
183                 case ctTrueColorAlpha:
184                         d.cb = cbTCA8
185                 }
186         case 16:
187                 switch d.tmp[9] {
188                 case ctGrayscale:
189                         d.cb = cbG16
190                 case ctTrueColor:
191                         d.cb = cbTC16
192                 case ctGrayscaleAlpha:
193                         d.cb = cbGA16
194                 case ctTrueColorAlpha:
195                         d.cb = cbTCA16
196                 }
197         }
198         if d.cb == cbInvalid {
199                 return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d", d.tmp[8], d.tmp[9]))
200         }
201         d.width, d.height = int(w), int(h)
202         return nil
203 }
204
205 func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Error {
206         np := int(length / 3) // The number of palette entries.
207         if length%3 != 0 || np <= 0 || np > 256 || np > 1<<uint(d.depth) {
208                 return FormatError("bad PLTE length")
209         }
210         n, err := io.ReadFull(r, d.tmp[0:3*np])
211         if err != nil {
212                 return err
213         }
214         crc.Write(d.tmp[0:n])
215         switch d.cb {
216         case cbP1, cbP2, cbP4, cbP8:
217                 d.palette = image.PalettedColorModel(make([]image.Color, np))
218                 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}
220                 }
221         case cbTC8, cbTCA8, cbTC16, cbTCA16:
222                 // As per the PNG spec, a PLTE chunk is optional (and for practical purposes,
223                 // ignorable) for the ctTrueColor and ctTrueColorAlpha color types (section 4.1.2).
224         default:
225                 return FormatError("PLTE, color type mismatch")
226         }
227         return nil
228 }
229
230 func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Error {
231         if length > 256 {
232                 return FormatError("bad tRNS length")
233         }
234         n, err := io.ReadFull(r, d.tmp[0:length])
235         if err != nil {
236                 return err
237         }
238         crc.Write(d.tmp[0:n])
239         switch d.cb {
240         case cbG8, cbG16:
241                 return UnsupportedError("grayscale transparency")
242         case cbTC8, cbTC16:
243                 return UnsupportedError("truecolor transparency")
244         case cbP1, cbP2, cbP4, cbP8:
245                 if n > len(d.palette) {
246                         return FormatError("bad tRNS length")
247                 }
248                 for i := 0; i < n; i++ {
249                         rgba := d.palette[i].(image.RGBAColor)
250                         d.palette[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d.tmp[i]}
251                 }
252         case cbGA8, cbGA16, cbTCA8, cbTCA16:
253                 return FormatError("tRNS, color type mismatch")
254         }
255         return nil
256 }
257
258 // The Paeth filter function, as per the PNG specification.
259 func paeth(a, b, c uint8) uint8 {
260         p := int(a) + int(b) - int(c)
261         pa := abs(p - int(a))
262         pb := abs(p - int(b))
263         pc := abs(p - int(c))
264         if pa <= pb && pa <= pc {
265                 return a
266         } else if pb <= pc {
267                 return b
268         }
269         return c
270 }
271
272 func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
273         r, err := zlib.NewReader(idat)
274         if err != nil {
275                 return nil, err
276         }
277         defer r.Close()
278         bitsPerPixel := 0
279         maxPalette := uint8(0)
280         var (
281                 gray     *image.Gray
282                 rgba     *image.RGBA
283                 paletted *image.Paletted
284                 nrgba    *image.NRGBA
285                 gray16   *image.Gray16
286                 rgba64   *image.RGBA64
287                 nrgba64  *image.NRGBA64
288                 img      image.Image
289         )
290         switch d.cb {
291         case cbG1, cbG2, cbG4, cbG8:
292                 bitsPerPixel = d.depth
293                 gray = image.NewGray(d.width, d.height)
294                 img = gray
295         case cbGA8:
296                 bitsPerPixel = 16
297                 nrgba = image.NewNRGBA(d.width, d.height)
298                 img = nrgba
299         case cbTC8:
300                 bitsPerPixel = 24
301                 rgba = image.NewRGBA(d.width, d.height)
302                 img = rgba
303         case cbP1, cbP2, cbP4, cbP8:
304                 bitsPerPixel = d.depth
305                 paletted = image.NewPaletted(d.width, d.height, d.palette)
306                 img = paletted
307                 maxPalette = uint8(len(d.palette) - 1)
308         case cbTCA8:
309                 bitsPerPixel = 32
310                 nrgba = image.NewNRGBA(d.width, d.height)
311                 img = nrgba
312         case cbG16:
313                 bitsPerPixel = 16
314                 gray16 = image.NewGray16(d.width, d.height)
315                 img = gray16
316         case cbGA16:
317                 bitsPerPixel = 32
318                 nrgba64 = image.NewNRGBA64(d.width, d.height)
319                 img = nrgba64
320         case cbTC16:
321                 bitsPerPixel = 48
322                 rgba64 = image.NewRGBA64(d.width, d.height)
323                 img = rgba64
324         case cbTCA16:
325                 bitsPerPixel = 64
326                 nrgba64 = image.NewNRGBA64(d.width, d.height)
327                 img = nrgba64
328         }
329         bytesPerPixel := (bitsPerPixel + 7) / 8
330
331         // cr and pr are the bytes for the current and previous row.
332         // The +1 is for the per-row filter type, which is at cr[0].
333         cr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
334         pr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8)
335
336         for y := 0; y < d.height; y++ {
337                 // Read the decompressed bytes.
338                 _, err := io.ReadFull(r, cr)
339                 if err != nil {
340                         return nil, err
341                 }
342
343                 // Apply the filter.
344                 cdat := cr[1:]
345                 pdat := pr[1:]
346                 switch cr[0] {
347                 case ftNone:
348                         // No-op.
349                 case ftSub:
350                         for i := bytesPerPixel; i < len(cdat); i++ {
351                                 cdat[i] += cdat[i-bytesPerPixel]
352                         }
353                 case ftUp:
354                         for i := 0; i < len(cdat); i++ {
355                                 cdat[i] += pdat[i]
356                         }
357                 case ftAverage:
358                         for i := 0; i < bytesPerPixel; i++ {
359                                 cdat[i] += pdat[i] / 2
360                         }
361                         for i := bytesPerPixel; i < len(cdat); i++ {
362                                 cdat[i] += uint8((int(cdat[i-bytesPerPixel]) + int(pdat[i])) / 2)
363                         }
364                 case ftPaeth:
365                         for i := 0; i < bytesPerPixel; i++ {
366                                 cdat[i] += paeth(0, pdat[i], 0)
367                         }
368                         for i := bytesPerPixel; i < len(cdat); i++ {
369                                 cdat[i] += paeth(cdat[i-bytesPerPixel], pdat[i], pdat[i-bytesPerPixel])
370                         }
371                 default:
372                         return nil, FormatError("bad filter type")
373                 }
374
375                 // Convert from bytes to colors.
376                 switch d.cb {
377                 case cbG1:
378                         for x := 0; x < d.width; x += 8 {
379                                 b := cdat[x/8]
380                                 for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
381                                         gray.SetGray(x+x2, y, image.GrayColor{(b >> 7) * 0xff})
382                                         b <<= 1
383                                 }
384                         }
385                 case cbG2:
386                         for x := 0; x < d.width; x += 4 {
387                                 b := cdat[x/4]
388                                 for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
389                                         gray.SetGray(x+x2, y, image.GrayColor{(b >> 6) * 0x55})
390                                         b <<= 2
391                                 }
392                         }
393                 case cbG4:
394                         for x := 0; x < d.width; x += 2 {
395                                 b := cdat[x/2]
396                                 for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
397                                         gray.SetGray(x+x2, y, image.GrayColor{(b >> 4) * 0x11})
398                                         b <<= 4
399                                 }
400                         }
401                 case cbG8:
402                         for x := 0; x < d.width; x++ {
403                                 gray.SetGray(x, y, image.GrayColor{cdat[x]})
404                         }
405                 case cbGA8:
406                         for x := 0; x < d.width; x++ {
407                                 ycol := cdat[2*x+0]
408                                 nrgba.SetNRGBA(x, y, image.NRGBAColor{ycol, ycol, ycol, cdat[2*x+1]})
409                         }
410                 case cbTC8:
411                         for x := 0; x < d.width; x++ {
412                                 rgba.SetRGBA(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
413                         }
414                 case cbP1:
415                         for x := 0; x < d.width; x += 8 {
416                                 b := cdat[x/8]
417                                 for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
418                                         idx := b >> 7
419                                         if idx > maxPalette {
420                                                 return nil, FormatError("palette index out of range")
421                                         }
422                                         paletted.SetColorIndex(x+x2, y, idx)
423                                         b <<= 1
424                                 }
425                         }
426                 case cbP2:
427                         for x := 0; x < d.width; x += 4 {
428                                 b := cdat[x/4]
429                                 for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
430                                         idx := b >> 6
431                                         if idx > maxPalette {
432                                                 return nil, FormatError("palette index out of range")
433                                         }
434                                         paletted.SetColorIndex(x+x2, y, idx)
435                                         b <<= 2
436                                 }
437                         }
438                 case cbP4:
439                         for x := 0; x < d.width; x += 2 {
440                                 b := cdat[x/2]
441                                 for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
442                                         idx := b >> 4
443                                         if idx > maxPalette {
444                                                 return nil, FormatError("palette index out of range")
445                                         }
446                                         paletted.SetColorIndex(x+x2, y, idx)
447                                         b <<= 4
448                                 }
449                         }
450                 case cbP8:
451                         for x := 0; x < d.width; x++ {
452                                 if cdat[x] > maxPalette {
453                                         return nil, FormatError("palette index out of range")
454                                 }
455                                 paletted.SetColorIndex(x, y, cdat[x])
456                         }
457                 case cbTCA8:
458                         for x := 0; x < d.width; x++ {
459                                 nrgba.SetNRGBA(x, y, image.NRGBAColor{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
460                         }
461                 case cbG16:
462                         for x := 0; x < d.width; x++ {
463                                 ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
464                                 gray16.SetGray16(x, y, image.Gray16Color{ycol})
465                         }
466                 case cbGA16:
467                         for x := 0; x < d.width; x++ {
468                                 ycol := uint16(cdat[4*x+0])<<8 | uint16(cdat[4*x+1])
469                                 acol := uint16(cdat[4*x+2])<<8 | uint16(cdat[4*x+3])
470                                 nrgba64.SetNRGBA64(x, y, image.NRGBA64Color{ycol, ycol, ycol, acol})
471                         }
472                 case cbTC16:
473                         for x := 0; x < d.width; x++ {
474                                 rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
475                                 gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
476                                 bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
477                                 rgba64.SetRGBA64(x, y, image.RGBA64Color{rcol, gcol, bcol, 0xffff})
478                         }
479                 case cbTCA16:
480                         for x := 0; x < d.width; x++ {
481                                 rcol := uint16(cdat[8*x+0])<<8 | uint16(cdat[8*x+1])
482                                 gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3])
483                                 bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5])
484                                 acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7])
485                                 nrgba64.SetNRGBA64(x, y, image.NRGBA64Color{rcol, gcol, bcol, acol})
486                         }
487                 }
488
489                 // The current row for y is the previous row for y+1.
490                 pr, cr = cr, pr
491         }
492         return img, nil
493 }
494
495 func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Error {
496         // There may be more than one IDAT chunk, but their contents must be
497         // treated as if it was one continuous stream (to the zlib decoder).
498         // We bring up an io.Pipe and write the IDAT chunks into the pipe as
499         // we see them, and decode the stream in a separate go-routine, which
500         // signals its completion (successful or not) via a channel.
501         if d.idatWriter == nil {
502                 pr, pw := io.Pipe()
503                 d.idatWriter = pw
504                 d.idatDone = make(chan imgOrErr)
505                 go func() {
506                         img, err := d.idatReader(pr)
507                         if err == os.EOF {
508                                 err = FormatError("too little IDAT")
509                         }
510                         pr.CloseWithError(FormatError("too much IDAT"))
511                         d.idatDone <- imgOrErr{img, err}
512                 }()
513         }
514         var buf [4096]byte
515         for length > 0 {
516                 n, err1 := r.Read(buf[0:min(len(buf), int(length))])
517                 // We delay checking err1. It is possible to get n bytes and an error,
518                 // but if the n bytes themselves contain a FormatError, for example, we
519                 // want to report that error, and not the one that made the Read stop.
520                 n, err2 := d.idatWriter.Write(buf[0:n])
521                 if err2 != nil {
522                         return err2
523                 }
524                 if err1 != nil {
525                         return err1
526                 }
527                 crc.Write(buf[0:n])
528                 length -= uint32(n)
529         }
530         return nil
531 }
532
533 func (d *decoder) parseIEND(r io.Reader, crc hash.Hash32, length uint32) os.Error {
534         if length != 0 {
535                 return FormatError("bad IEND length")
536         }
537         return nil
538 }
539
540 func (d *decoder) parseChunk(r io.Reader) os.Error {
541         // Read the length.
542         n, err := io.ReadFull(r, d.tmp[0:4])
543         if err == os.EOF {
544                 return io.ErrUnexpectedEOF
545         }
546         if err != nil {
547                 return err
548         }
549         length := parseUint32(d.tmp[0:4])
550
551         // Read the chunk type.
552         n, err = io.ReadFull(r, d.tmp[0:4])
553         if err == os.EOF {
554                 return io.ErrUnexpectedEOF
555         }
556         if err != nil {
557                 return err
558         }
559         crc := crc32.NewIEEE()
560         crc.Write(d.tmp[0:4])
561
562         // Read the chunk data.
563         switch string(d.tmp[0:4]) {
564         case "IHDR":
565                 if d.stage != dsStart {
566                         return chunkOrderError
567                 }
568                 d.stage = dsSeenIHDR
569                 err = d.parseIHDR(r, crc, length)
570         case "PLTE":
571                 if d.stage != dsSeenIHDR {
572                         return chunkOrderError
573                 }
574                 d.stage = dsSeenPLTE
575                 err = d.parsePLTE(r, crc, length)
576         case "tRNS":
577                 if d.stage != dsSeenPLTE {
578                         return chunkOrderError
579                 }
580                 err = d.parsetRNS(r, crc, length)
581         case "IDAT":
582                 if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
583                         return chunkOrderError
584                 }
585                 d.stage = dsSeenIDAT
586                 err = d.parseIDAT(r, crc, length)
587         case "IEND":
588                 if d.stage != dsSeenIDAT {
589                         return chunkOrderError
590                 }
591                 d.stage = dsSeenIEND
592                 err = d.parseIEND(r, crc, length)
593         default:
594                 // Ignore this chunk (of a known length).
595                 var ignored [4096]byte
596                 for length > 0 {
597                         n, err = io.ReadFull(r, ignored[0:min(len(ignored), int(length))])
598                         if err != nil {
599                                 return err
600                         }
601                         crc.Write(ignored[0:n])
602                         length -= uint32(n)
603                 }
604         }
605         if err != nil {
606                 return err
607         }
608
609         // Read the checksum.
610         n, err = io.ReadFull(r, d.tmp[0:4])
611         if err == os.EOF {
612                 return io.ErrUnexpectedEOF
613         }
614         if err != nil {
615                 return err
616         }
617         if parseUint32(d.tmp[0:4]) != crc.Sum32() {
618                 return FormatError("invalid checksum")
619         }
620         return nil
621 }
622
623 func (d *decoder) checkHeader(r io.Reader) os.Error {
624         _, err := io.ReadFull(r, d.tmp[0:8])
625         if err != nil {
626                 return err
627         }
628         if string(d.tmp[0:8]) != pngHeader {
629                 return FormatError("not a PNG file")
630         }
631         return nil
632 }
633
634 // Decode reads a PNG image from r and returns it as an image.Image.
635 // The type of Image returned depends on the PNG contents.
636 func Decode(r io.Reader) (image.Image, os.Error) {
637         var d decoder
638         err := d.checkHeader(r)
639         if err != nil {
640                 return nil, err
641         }
642         for d.stage != dsSeenIEND {
643                 err = d.parseChunk(r)
644                 if err != nil {
645                         break
646                 }
647         }
648         var img image.Image
649         if d.idatWriter != nil {
650                 d.idatWriter.Close()
651                 ie := <-d.idatDone
652                 if err == nil {
653                         img, err = ie.img, ie.err
654                 }
655         }
656         if err != nil {
657                 return nil, err
658         }
659         return img, nil
660 }
661
662 // DecodeConfig returns the color model and dimensions of a PNG image without
663 // decoding the entire image.
664 func DecodeConfig(r io.Reader) (image.Config, os.Error) {
665         var d decoder
666         err := d.checkHeader(r)
667         if err != nil {
668                 return image.Config{}, err
669         }
670         for {
671                 err = d.parseChunk(r)
672                 if err != nil {
673                         return image.Config{}, err
674                 }
675                 if d.stage == dsSeenIHDR && d.cb != cbP8 {
676                         break
677                 }
678                 if d.stage == dsSeenPLTE && d.cb == cbP8 {
679                         break
680                 }
681         }
682         var cm image.ColorModel
683         switch d.cb {
684         case cbG1, cbG2, cbG4, cbG8:
685                 cm = image.GrayColorModel
686         case cbGA8:
687                 cm = image.NRGBAColorModel
688         case cbTC8:
689                 cm = image.RGBAColorModel
690         case cbP1, cbP2, cbP4, cbP8:
691                 cm = d.palette
692         case cbTCA8:
693                 cm = image.NRGBAColorModel
694         case cbG16:
695                 cm = image.Gray16ColorModel
696         case cbGA16:
697                 cm = image.NRGBA64ColorModel
698         case cbTC16:
699                 cm = image.RGBA64ColorModel
700         case cbTCA16:
701                 cm = image.NRGBA64ColorModel
702         }
703         return image.Config{cm, d.width, d.height}, nil
704 }
705
706 func init() {
707         image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)
708 }