// Checks if image is grayscale func (c *Convertor) isGrayScale(img image.Image) bool { model := img.ColorModel() if model == color.GrayModel || model == color.Gray16Model { return true } return false }
// Encode writes the Image m to w in PNG format. func (enc *Encoder) Encode(w io.Writer, m image.Image) error { // Obviously, negative widths and heights are invalid. Furthermore, the PNG // spec section 11.2.2 says that zero is invalid. Excessively large images are // also rejected. mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy()) if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 { return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mh, 10)) } var e encoder e.enc = enc e.w = w e.m = m e.st = simpleTransparency(m) var pal color.Palette // cbP8 encoding needs PalettedImage's ColorIndexAt method. if _, ok := m.(image.PalettedImage); ok { pal, _ = m.ColorModel().(color.Palette) } if pal != nil { e.cb = cbP8 } else { switch m.ColorModel() { case color.GrayModel: e.cb = cbG8 case color.Gray16Model: e.cb = cbG16 case color.RGBAModel, color.NRGBAModel, color.AlphaModel: if opaque(m) || e.st != nil { e.cb = cbTC8 } else { e.cb = cbTCA8 } default: if opaque(m) || e.st != nil { e.cb = cbTC16 } else { e.cb = cbTCA16 } } } _, e.err = io.WriteString(w, pngHeader) e.writeIHDR() if pal != nil { e.writePLTEAndTRNS(pal) } else if e.st != nil { e.writetRNS() } e.writeIDATs() e.writeIEND() return e.err }
func ImageTransformByProfile(src_image image.Image, src_prof, dst_prof *Profile) (image.Image, error) { var dst_image image.Image rect := src_image.Bounds() width := rect.Dx() height := rect.Dy() colorModel := src_image.ColorModel() // 今のところ RGBA, YCbCr のみ対応 if (colorModel != color.YCbCrModel) && (colorModel != color.RGBAModel) { return nil, fmt.Errorf("ImageTransformByProfile: Unsupported ColorModel(%d)", colorModel) } var src_rgba *image.RGBA var src_ycbcr *image.YCbCr if colorModel == color.YCbCrModel { // YCbCr の場合は RGB に変換する src_ycbcr = src_image.(*image.YCbCr) src_rgba = image.NewRGBA(rect) DrawYCbCr(src_rgba, rect, src_ycbcr, image.Pt(0, 0)) } else { src_rgba = src_image.(*image.RGBA) // type assertions } transform := CreateTransform(src_prof, DATA_RGBA_8, dst_prof, DATA_RGBA_8) defer transform.DeleteTransform() if transform == nil { return nil, fmt.Errorf("ImageTransformByProfile: CreateTransform Failedl(%d)", colorModel) } dst_rgba := image.NewRGBA(rect) src_pix := src_rgba.Pix dst_pix := dst_rgba.Pix len_pix := len(src_pix) transform.DoTransform(src_pix, dst_pix, len_pix) // YCbCr の場合は RGB から戻す if colorModel == color.YCbCrModel { dst_ycbcr := image.NewYCbCr(rect, src_ycbcr.SubsampleRatio) var x int var y int for y = 0; y < height; y++ { for x = 0; x < width; x++ { r, g, b, _ := dst_rgba.At(x, y).RGBA() yy, cb, cr := color.RGBToYCbCr(uint8(r), uint8(g), uint8(b)) yi := dst_ycbcr.YOffset(x, y) ci := dst_ycbcr.COffset(x, y) dst_ycbcr.Y[yi] = yy dst_ycbcr.Cb[ci] = cb dst_ycbcr.Cr[ci] = cr } } dst_image = image.Image(dst_ycbcr) } else { dst_image = image.Image(dst_rgba) } return dst_image, nil }
func NewTexture(image image.Image, data interface{}) (texture *Texture, err error) { iF, typ, f, t, e := ColorModelToGLTypes(image.ColorModel()) if e != nil { return nil, nil } return NewTexture2(data, image.Bounds().Dx(), image.Bounds().Dy(), t, iF, typ, f), nil }
func convertColor(im image.Image, col image.RGBA64Color) image.Color { var outCol image.Color switch im.ColorModel() { case image.RGBAColorModel: outCol = image.RGBAColorModel.Convert(col).(image.RGBAColor) case image.NRGBAColorModel: outCol = image.NRGBAColorModel.Convert(col).(image.NRGBAColor) case image.GrayColorModel: outCol = image.GrayColorModel.Convert(col).(image.GrayColor) case image.Gray16ColorModel: outCol = image.Gray16ColorModel.Convert(col).(image.Gray16Color) default: outCol = col } return outCol }
func imgType(im image.Image, w, h int) imageng { var scaled imageng switch im.ColorModel() { case image.RGBAColorModel: scaled = image.NewRGBA(w, h) case image.NRGBAColorModel: scaled = image.NewNRGBA(w, h) case image.GrayColorModel: scaled = image.NewGray(w, h) case image.Gray16ColorModel: scaled = image.NewGray16(w, h) default: scaled = image.NewRGBA64(w, h) } return scaled }
// Encode writes the Image m to w in PNG format. Any Image may be encoded, but // images that are not image.NRGBA might be encoded lossily. func Encode(w io.Writer, m image.Image) os.Error { // Obviously, negative widths and heights are invalid. Furthermore, the PNG // spec section 11.2.2 says that zero is invalid. Excessively large images are // also rejected. mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy()) if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 { return FormatError("invalid image size: " + strconv.Itoa64(mw) + "x" + strconv.Itoa64(mw)) } var e encoder e.w = w e.m = m pal, _ := m.(*image.Paletted) if pal != nil { e.cb = cbP8 } else { switch m.ColorModel() { case image.GrayColorModel: e.cb = cbG8 case image.Gray16ColorModel: e.cb = cbG16 case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel: if opaque(m) { e.cb = cbTC8 } else { e.cb = cbTCA8 } default: if opaque(m) { e.cb = cbTC16 } else { e.cb = cbTCA16 } } } _, e.err = io.WriteString(w, pngHeader) e.writeIHDR() if pal != nil { e.writePLTE(pal.Palette) e.maybeWritetRNS(pal.Palette) } e.writeIDATs() e.writeIEND() return e.err }
// An approximation of the sng command-line tool. func sng(w io.WriteCloser, filename string, png image.Image) { defer w.Close() bounds := png.Bounds() cm := png.ColorModel() var bitdepth int switch cm { case color.RGBAModel, color.NRGBAModel, color.AlphaModel, color.GrayModel: bitdepth = 8 default: bitdepth = 16 } cpm, _ := cm.(color.Palette) var paletted *image.Paletted if cpm != nil { switch { case len(cpm) <= 2: bitdepth = 1 case len(cpm) <= 4: bitdepth = 2 case len(cpm) <= 16: bitdepth = 4 default: bitdepth = 8 } paletted = png.(*image.Paletted) } // Write the filename and IHDR. io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n") fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth) switch { case cm == color.RGBAModel, cm == color.RGBA64Model: io.WriteString(w, " using color;\n") case cm == color.NRGBAModel, cm == color.NRGBA64Model: io.WriteString(w, " using color alpha;\n") case cm == color.GrayModel, cm == color.Gray16Model: io.WriteString(w, " using grayscale;\n") case cpm != nil: io.WriteString(w, " using color palette;\n") 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 and tRNS (if applicable). if cpm != nil { lastAlpha := -1 io.WriteString(w, "PLTE {\n") for i, c := range cpm { r, g, b, a := c.RGBA() if a != 0xffff { lastAlpha = i } r >>= 8 g >>= 8 b >>= 8 fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b) } io.WriteString(w, "}\n") if lastAlpha != -1 { io.WriteString(w, "tRNS {\n") for i := 0; i <= lastAlpha; i++ { _, _, _, a := cpm[i].RGBA() a >>= 8 fmt.Fprintf(w, " %d", a) } io.WriteString(w, "}\n") } } // Write the IMAGE. io.WriteString(w, "IMAGE {\n pixels hex\n") for y := bounds.Min.Y; y < bounds.Max.Y; y++ { switch { case cm == color.GrayModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { gray := png.At(x, y).(color.Gray) fmt.Fprintf(w, "%02x", gray.Y) } case cm == color.Gray16Model: for x := bounds.Min.X; x < bounds.Max.X; x++ { gray16 := png.At(x, y).(color.Gray16) fmt.Fprintf(w, "%04x ", gray16.Y) } case cm == color.RGBAModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { rgba := png.At(x, y).(color.RGBA) fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B) } case cm == color.RGBA64Model: for x := bounds.Min.X; x < bounds.Max.X; x++ { rgba64 := png.At(x, y).(color.RGBA64) fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B) } case cm == color.NRGBAModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { nrgba := png.At(x, y).(color.NRGBA) fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A) } case cm == color.NRGBA64Model: for x := bounds.Min.X; x < bounds.Max.X; x++ { nrgba64 := png.At(x, y).(color.NRGBA64) fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A) } case cpm != nil: var b, c int for x := bounds.Min.X; x < bounds.Max.X; x++ { b = b<<uint(bitdepth) | int(paletted.ColorIndexAt(x, y)) c++ if c == 8/bitdepth { fmt.Fprintf(w, "%02x", b) b = 0 c = 0 } } } io.WriteString(w, "\n") } io.WriteString(w, "}\n") }
// An approximation of the sng command-line tool. func sng(w io.WriteCloser, filename string, png image.Image) { defer w.Close() bounds := png.Bounds() cm := png.ColorModel() var bitdepth int switch cm { case color.RGBAModel, color.NRGBAModel, color.AlphaModel, color.GrayModel: bitdepth = 8 default: bitdepth = 16 } cpm, _ := cm.(color.Palette) var paletted *image.Paletted if cpm != nil { switch { case len(cpm) <= 2: bitdepth = 1 case len(cpm) <= 4: bitdepth = 2 case len(cpm) <= 16: bitdepth = 4 default: bitdepth = 8 } paletted = png.(*image.Paletted) } // Write the filename and IHDR. io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n") fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth) if s, ok := fakeIHDRUsings[filename]; ok { io.WriteString(w, s) } else { switch { case cm == color.RGBAModel, cm == color.RGBA64Model: io.WriteString(w, " using color;\n") case cm == color.NRGBAModel, cm == color.NRGBA64Model: io.WriteString(w, " using color alpha;\n") case cm == color.GrayModel, cm == color.Gray16Model: io.WriteString(w, " using grayscale;\n") case cpm != nil: io.WriteString(w, " using color palette;\n") default: io.WriteString(w, "unknown PNG decoder color model\n") } } io.WriteString(w, "}\n") // We fake a gAMA chunk. 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"). if s, ok := fakegAMAs[filename]; ok { io.WriteString(w, s) } else { io.WriteString(w, "gAMA {1.0000}\n") } // Write the PLTE and tRNS (if applicable). useTransparent := false if cpm != nil { lastAlpha := -1 io.WriteString(w, "PLTE {\n") for i, c := range cpm { var r, g, b, a uint8 switch c := c.(type) { case color.RGBA: r, g, b, a = c.R, c.G, c.B, 0xff case color.NRGBA: r, g, b, a = c.R, c.G, c.B, c.A default: panic("unknown palette color type") } if a != 0xff { lastAlpha = i } fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b) } io.WriteString(w, "}\n") if s, ok := fakebKGDs[filename]; ok { io.WriteString(w, s) } if lastAlpha != -1 { io.WriteString(w, "tRNS {\n") for i := 0; i <= lastAlpha; i++ { _, _, _, a := cpm[i].RGBA() a >>= 8 fmt.Fprintf(w, " %d", a) } io.WriteString(w, "}\n") } } else if strings.HasPrefix(filename, "ft") { if s, ok := fakebKGDs[filename]; ok { io.WriteString(w, s) } // We fake a tRNS chunk. The test files' grayscale and truecolor // transparent images all have their top left corner transparent. switch c := png.At(0, 0).(type) { case color.NRGBA: if c.A == 0 { useTransparent = true io.WriteString(w, "tRNS {\n") switch filename { case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04": // The standard image package doesn't have a "gray with // alpha" type. Instead, we use an image.NRGBA. fmt.Fprintf(w, " gray: %d;\n", c.R) default: fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B) } io.WriteString(w, "}\n") } case color.NRGBA64: if c.A == 0 { useTransparent = true io.WriteString(w, "tRNS {\n") switch filename { case "ftbwn0g16": // The standard image package doesn't have a "gray16 with // alpha" type. Instead, we use an image.NRGBA64. fmt.Fprintf(w, " gray: %d;\n", c.R) default: fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B) } io.WriteString(w, "}\n") } } } // Write the IMAGE. io.WriteString(w, "IMAGE {\n pixels hex\n") for y := bounds.Min.Y; y < bounds.Max.Y; y++ { switch { case cm == color.GrayModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { gray := png.At(x, y).(color.Gray) fmt.Fprintf(w, "%02x", gray.Y) } case cm == color.Gray16Model: for x := bounds.Min.X; x < bounds.Max.X; x++ { gray16 := png.At(x, y).(color.Gray16) fmt.Fprintf(w, "%04x ", gray16.Y) } case cm == color.RGBAModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { rgba := png.At(x, y).(color.RGBA) fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B) } case cm == color.RGBA64Model: for x := bounds.Min.X; x < bounds.Max.X; x++ { rgba64 := png.At(x, y).(color.RGBA64) fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B) } case cm == color.NRGBAModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { nrgba := png.At(x, y).(color.NRGBA) switch filename { case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04": fmt.Fprintf(w, "%02x", nrgba.R) default: if useTransparent { fmt.Fprintf(w, "%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B) } else { fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A) } } } case cm == color.NRGBA64Model: for x := bounds.Min.X; x < bounds.Max.X; x++ { nrgba64 := png.At(x, y).(color.NRGBA64) switch filename { case "ftbwn0g16": fmt.Fprintf(w, "%04x ", nrgba64.R) default: if useTransparent { fmt.Fprintf(w, "%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B) } else { fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A) } } } case cpm != nil: var b, c int for x := bounds.Min.X; x < bounds.Max.X; x++ { b = b<<uint(bitdepth) | int(paletted.ColorIndexAt(x, y)) c++ if c == 8/bitdepth { fmt.Fprintf(w, "%02x", b) b = 0 c = 0 } } if c != 0 { for c != 8/bitdepth { b = b << uint(bitdepth) c++ } fmt.Fprintf(w, "%02x", b) } } io.WriteString(w, "\n") } io.WriteString(w, "}\n") }
func LoadTextureFromImage(image image.Image) (tex *Texture, err error) { /* val := reflect.ValueOf(image) pixs := val.FieldByName("Pix") if pixs.IsValid() { return } else { } return nil, false, nil */ internalFormat, typ, format, target, e := ColorModelToGLTypes(image.ColorModel()) if e != nil { return nil, nil } // w := image.Bounds().Dx() h := image.Bounds().Dy() model := image.ColorModel() var data []byte switch model.(type) { case color.Palette: memHandle := Allocate(4 * h * w) data = memHandle.Bytes() defer memHandle.Release() for x := 0; x < w; x++ { for y := 0; y < h; y++ { offset := (x + (y * w)) * 4 r, g, b, a := image.At(x, y).RGBA() data[offset] = byte(r / 257) data[offset+1] = byte(g / 257) data[offset+2] = byte(b / 257) data[offset+3] = byte(a / 257) } } } switch model { case color.YCbCrModel: memHandle := Allocate(3 * h * w) data = memHandle.Bytes() defer memHandle.Release() for x := 0; x < w; x++ { for y := 0; y < h; y++ { offset := (x + y*w) * 3 r, g, b, _ := image.At(x, y).RGBA() data[offset] = byte(r / 257) data[offset+1] = byte(g / 257) data[offset+2] = byte(b / 257) } } case color.RGBAModel, color.NRGBAModel: memHandle := Allocate(4 * h * w) data = memHandle.Bytes() defer memHandle.Release() for x := 0; x < w; x++ { for y := 0; y < h; y++ { offset := (x + (y * w)) * 4 r, g, b, a := image.At(x, y).RGBA() data[offset] = byte(r / 257) data[offset+1] = byte(g / 257) data[offset+2] = byte(b / 257) data[offset+3] = byte(a / 257) } } case color.RGBA64Model, color.NRGBA64Model: memHandle := Allocate(4 * h * w) data = memHandle.Bytes() defer memHandle.Release() for x := 0; x < w; x++ { for y := 0; y < h; y++ { offset := (x + y*w) * 4 r, g, b, a := image.At(x, y).RGBA() data[offset] = byte(r / 257) data[offset+1] = byte(g / 257) data[offset+2] = byte(b / 257) data[offset+3] = byte(a / 257) } } default: m, e := CustomColorModels[model] if e { return NewTexture2(m.Model.Data(), image.Bounds().Dx(), image.Bounds().Dy(), target, internalFormat, typ, format), nil } else { return nil, errors.New("unsupported format") } } return NewTexture2(data, image.Bounds().Dx(), image.Bounds().Dy(), target, internalFormat, typ, format), nil }
// An approximation of the sng command-line tool. func sng(w io.WriteCloser, filename string, png image.Image) { defer w.Close() bounds := png.Bounds() cm := png.ColorModel() var bitdepth int switch cm { case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel, image.GrayColorModel: bitdepth = 8 default: bitdepth = 16 } cpm, _ := cm.(image.PalettedColorModel) var paletted *image.Paletted if cpm != nil { bitdepth = 8 paletted = png.(*image.Paletted) } // Write the filename and IHDR. io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n") fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth) switch { case cm == image.RGBAColorModel, cm == image.RGBA64ColorModel: io.WriteString(w, " using color;\n") case cm == image.NRGBAColorModel, cm == image.NRGBA64ColorModel: io.WriteString(w, " using color alpha;\n") case cm == image.GrayColorModel, cm == image.Gray16ColorModel: io.WriteString(w, " using grayscale;\n") case cpm != nil: io.WriteString(w, " using color palette;\n") 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 >>= 8 g >>= 8 b >>= 8 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 := bounds.Min.Y; y < bounds.Max.Y; y++ { switch { case cm == image.GrayColorModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { gray := png.At(x, y).(image.GrayColor) fmt.Fprintf(w, "%02x", gray.Y) } case cm == image.Gray16ColorModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { gray16 := png.At(x, y).(image.Gray16Color) fmt.Fprintf(w, "%04x ", gray16.Y) } case cm == image.RGBAColorModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { rgba := png.At(x, y).(image.RGBAColor) fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B) } case cm == image.RGBA64ColorModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { rgba64 := png.At(x, y).(image.RGBA64Color) fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B) } case cm == image.NRGBAColorModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { nrgba := png.At(x, y).(image.NRGBAColor) fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A) } case cm == image.NRGBA64ColorModel: for x := bounds.Min.X; x < bounds.Max.X; x++ { nrgba64 := png.At(x, y).(image.NRGBA64Color) fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A) } case cpm != nil: for x := bounds.Min.X; x < bounds.Max.X; x++ { fmt.Fprintf(w, "%02x", paletted.ColorIndexAt(x, y)) } } io.WriteString(w, "\n") } io.WriteString(w, "}\n") }
func grid(img1 image.Image, fitHeight int, fitWidth int) [][]bool { bounds := img1.Bounds() width, height := bounds.Dx(), bounds.Dy() grid := make([][]bool, fitWidth, fitWidth) for col := 0; col < fitWidth; col++ { r := make([]bool, fitHeight, fitHeight) for row := 0; row < fitHeight; row++ { isOn := pixelIsIntense(img1.At(interp(col, fitWidth, width), interp(row, fitHeight, height)), img1.ColorModel()).ActiveState() r[fitHeight-1-row] = isOn } grid[col] = r } return grid }
// 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") }