| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package png |
| |
| import ( |
| "bufio"; |
| "fmt"; |
| "image"; |
| "io"; |
| "os"; |
| "testing"; |
| ) |
| |
| // The go PNG library currently supports only a subset of the full PNG specification. |
| // In particular, bit depths other than 8 are not supported, and neither are grayscale images. |
| var filenames = []string{ |
| //"basn0g01", // bit depth is not 8 |
| //"basn0g02", // bit depth is not 8 |
| //"basn0g04", // bit depth is not 8 |
| //"basn0g08", // grayscale color model |
| //"basn0g16", // bit depth is not 8 |
| "basn2c08", |
| //"basn2c16", // bit depth is not 8 |
| //"basn3p01", // bit depth is not 8 |
| //"basn3p02", // bit depth is not 8 |
| //"basn3p04", // bit depth is not 8 |
| "basn3p08", |
| //"basn4a08", // grayscale color model |
| //"basn4a16", // bit depth is not 8 |
| "basn6a08", |
| //"basn6a16", // bit depth is not 8 |
| } |
| |
| func readPng(filename string) (image.Image, os.Error) { |
| f, err := os.Open(filename, os.O_RDONLY, 0444); |
| if err != nil { |
| return nil, err; |
| } |
| defer f.Close(); |
| return Decode(f); |
| } |
| |
| // An approximation of the sng command-line tool. |
| func sng(w io.WriteCloser, filename string, png image.Image) { |
| defer w.Close(); |
| // For now, the go PNG parser only reads bitdepths of 8. |
| bitdepth := 8; |
| |
| // Write the filename and IHDR. |
| io.WriteString(w, "#SNG: from " + filename + ".png\nIHDR {\n"); |
| fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", png.Width(), png.Height(), bitdepth); |
| cm := png.ColorModel(); |
| var paletted *image.Paletted; |
| cpm, _ := cm.(image.PalettedColorModel); |
| switch { |
| case cm == image.RGBAColorModel: |
| io.WriteString(w, " using color;\n"); |
| case cm == image.NRGBAColorModel: |
| io.WriteString(w, " using color alpha;\n"); |
| case cpm != nil: |
| io.WriteString(w, " using color palette;\n"); |
| paletted = png.(*image.Paletted); |
| default: |
| io.WriteString(w, "unknown PNG decoder color model\n"); |
| } |
| io.WriteString(w, "}\n"); |
| |
| // We fake a gAMA output. The test files have a gAMA chunk but the go PNG parser ignores it |
| // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder"). |
| io.WriteString(w, "gAMA {1.0000}\n"); |
| |
| // Write the PLTE (if applicable). |
| if cpm != nil { |
| io.WriteString(w, "PLTE {\n"); |
| for i := 0; i < len(cpm); i++ { |
| r, g, b, _ := cpm[i].RGBA(); |
| r >>= 24; |
| g >>= 24; |
| b >>= 24; |
| fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b); |
| } |
| io.WriteString(w, "}\n"); |
| } |
| |
| // Write the IMAGE. |
| io.WriteString(w, "IMAGE {\n pixels hex\n"); |
| for y := 0; y < png.Height(); y++ { |
| switch { |
| case cm == image.RGBAColorModel: |
| for x := 0; x < png.Width(); x++ { |
| rgba := png.At(x, y).(image.RGBAColor); |
| fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B); |
| } |
| case cm == image.NRGBAColorModel: |
| for x := 0; x < png.Width(); x++ { |
| nrgba := png.At(x, y).(image.NRGBAColor); |
| fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A); |
| } |
| case cpm != nil: |
| for x := 0; x < png.Width(); x++ { |
| fmt.Fprintf(w, "%02x", paletted.ColorIndexAt(x, y)); |
| } |
| } |
| io.WriteString(w, "\n"); |
| } |
| io.WriteString(w, "}\n"); |
| } |
| |
| func TestReader(t *testing.T) { |
| for _, fn := range filenames { |
| // Read the .png file. |
| image, err := readPng("testdata/pngsuite/" + fn + ".png"); |
| if err != nil { |
| t.Error(fn, err); |
| continue; |
| } |
| piper, pipew := io.Pipe(); |
| pb := bufio.NewReader(piper); |
| go sng(pipew, fn, image); |
| defer piper.Close(); |
| |
| // Read the .sng file. |
| sf, err := os.Open("testdata/pngsuite/" + fn + ".sng", os.O_RDONLY, 0444); |
| if err != nil { |
| t.Error(fn, err); |
| continue; |
| } |
| defer sf.Close(); |
| sb := bufio.NewReader(sf); |
| if err != nil { |
| t.Error(fn, err); |
| continue; |
| } |
| |
| // Compare the two, in SNG format, line by line. |
| for { |
| ps, perr := pb.ReadString('\n'); |
| ss, serr := sb.ReadString('\n'); |
| if perr == os.EOF && serr == os.EOF { |
| break; |
| } |
| if perr != nil { |
| t.Error(fn, perr); |
| break; |
| } |
| if serr != nil { |
| t.Error(fn, serr); |
| break; |
| } |
| if ps != ss { |
| t.Errorf("%s: Mismatch\n%sversus\n%s\n", fn, ps, ss); |
| break; |
| } |
| } |
| } |
| } |