func palettedToRGBA(last *image.RGBA, in *image.Paletted) *image.RGBA { out := image.NewRGBA(image.Rect(0, 0, 16, 16)) draw.Draw(out, out.Bounds(), last, last.Rect.Min, draw.Src) draw.Draw(out, in.Bounds(), in, in.Rect.Min, draw.Over) return out }
func pixel_is_light(img *image.Paletted, x int, y int) bool { r, g, b, _ := img.At(x, y).RGBA() sum := r + g + b return (sum > 0x18000) && (sum < 0x2e000) }
// 全填充正方形 // // -------- // |######| // |######| // |######| // -------- func b1(img *image.Paletted, x, y, size float64, angle int) { isize := int(size) ix := int(x) iy := int(y) for i := ix + 1; i < ix+isize; i++ { for j := iy + 1; j < iy+isize; j++ { img.SetColorIndex(i, j, 1) } } }
func newSetFuncPaletted(p *image.Paletted) SetFunc { return func(x, y int, r, g, b, a uint32) { i := p.PixOffset(x, y) p.Pix[i] = uint8(p.Palette.Index(color.RGBA64{ R: uint16(r), G: uint16(g), B: uint16(b), A: uint16(a), })) } }
// 中间小方块 // ---------- // | | // | #### | // | #### | // | | // ---------- func b2(img *image.Paletted, x, y, size float64, angle int) { l := size / 4 x = x + l y = y + l for i := x; i < x+2*l; i++ { for j := y; j < y+2*l; j++ { img.SetColorIndex(int(i), int(j), 1) } } }
func toPaletted(o *ora.ORA, name string, palette color.Palette) (*image.Paletted, error) { var p *image.Paletted if l := o.Layer(name); l != nil { p = image.NewPaletted(o.Bounds(), palette) i, err := l.Image() if err != nil { return nil, err } draw.Draw(p, image.Rect(0, 0, p.Bounds().Max.X, p.Bounds().Max.Y), i, image.Point{}, draw.Src) } return p, nil }
func (s *Simulation) DrawAll(initialImage *image.Paletted, frameCount int) []*image.Paletted { bounds := initialImage.Bounds() images := make([]*image.Paletted, frameCount) s.Draw(initialImage) images[0] = initialImage for f := 1; f < frameCount; f++ { newSimulation := s.Step() img := image.NewPaletted(bounds, initialImage.Palette) newSimulation.DiffDraw(s, img) images[f] = img s = newSimulation } return images }
// Write a text inside the image func WriteText(text string, f *truetype.Font, img *image.Paletted) { // Initialize the context. fg := image.Black c := freetype.NewContext() c.SetDPI(72) c.SetFont(f) c.SetFontSize(64) c.SetClip(img.Bounds()) c.SetDst(img) c.SetSrc(fg) // Draw the text. pt := freetype.Pt(40, 120) c.DrawString(text, pt) }
// 将多边形points旋转angle个角度,然后输出到img上,起点为x,y坐标 func drawBlock(img *image.Paletted, x, y, size float64, angle int, points []float64) { if angle > 0 { // 0角度不需要转换 // 中心坐标与x,y的距离,方便下面指定中心坐标(x+m,y+m), // 0.5的偏移值不能少,否则坐靠右,非正中央 m := size/2 - 0.5 rotate(points, x+m, y+m, angle) } for i := x; i < x+size; i++ { for j := y; j < y+size; j++ { if pointInPolygon(i, j, points) { img.SetColorIndex(int(i), int(j), 1) } } } }
// uninterlace rearranges the pixels in m to account for interlaced input. func uninterlace(m *image.Paletted) { var nPix []uint8 dx := m.Bounds().Dx() dy := m.Bounds().Dy() nPix = make([]uint8, dx*dy) offset := 0 // steps through the input by sequential scan lines. for _, pass := range interlacing { nOffset := pass.start * dx // steps through the output as defined by pass. for y := pass.start; y < dy; y += pass.skip { copy(nPix[nOffset:nOffset+dx], m.Pix[offset:offset+dx]) offset += dx nOffset += dx * pass.skip } } m.Pix = nPix }
func modeTerrain(p *image.Paletted, l int) uint8 { b := p.Bounds() modeMap := make([]uint8, l) var most, mode uint8 for i := b.Min.X; i < b.Max.X; i++ { for j := b.Min.Y; j < b.Max.Y; j++ { pos := p.ColorIndexAt(i, j) modeMap[pos]++ if m := modeMap[pos]; m > most { most = m mode = pos } } } return mode }
func untile(m *image.Paletted, data []byte) { w, h := m.Rect.Dx(), m.Rect.Dy() for i, x := 0, 0; x < w; x += 8 { for y := 0; y < h; y += 8 { for ty := 0; ty < 8; ty++ { pix := mingle(uint16(data[i]), uint16(data[i+1])) for tx := 7; tx >= 0; tx-- { i := m.PixOffset(x+tx, y+ty) m.Pix[i] = uint8(pix & 3) pix >>= 2 } i += 2 } } } }
func ripShinyPokemonBack(rip *sprites.Ripper, number int, form string, outname string) error { var m *image.Paletted var err error if number == 201 && form != "" { m, err = rip.UnownBack(form) } else { m, err = rip.PokemonBack(number) } if err != nil { return err } m.Palette = rip.ShinyPalette(number) if m.Palette == nil { return errors.New("couldn't get palette") } return write(m, outname) }
func debarf_frame(frame *image.Paletted) error { xmin := frame.Rect.Min.X ymin := frame.Rect.Min.Y xmax := frame.Rect.Max.X ymax := frame.Rect.Max.Y for y := ymin; y < ymax; y++ { for x := xmin; x < xmax; x++ { c := frame.At(x, y) r, g, b, a := c.RGBA() if pixel_is_transparent(frame, x, y) { fmt.Printf("...") frame.Set(x, y, color.RGBA64{uint16(r), uint16(g), uint16(b), 0xffff}) } else if should_turn_pixel_transparent(frame, x, y) { fmt.Printf("xxx") frame.Set(x, y, color.RGBA64{0, 0, 0, 0xffff}) } else { r /= 0x1000 g /= 0x1000 b /= 0x1000 if a != 0xffff { fmt.Printf("barf") } fmt.Printf("%x%x%x", r, g, b) } } fmt.Printf("\n") } return nil }
func (q *MedianCutQuantizer) Quantize(dst *image.Paletted, r image.Rectangle, src image.Image, sp image.Point) { clip(dst, &r, src, &sp) if r.Empty() { return } points := make([]point, r.Dx()*r.Dy()) colorSet := make(map[uint32]color.Color, q.NumColor) i := 0 for y := r.Min.Y; y < r.Max.Y; y++ { for x := r.Min.X; x < r.Max.X; x++ { c := src.At(x, y) r, g, b, _ := c.RGBA() colorSet[(r>>8)<<16|(g>>8)<<8|b>>8] = c points[i][0] = int(r) points[i][1] = int(g) points[i][2] = int(b) i++ } } if len(colorSet) <= q.NumColor { // No need to quantize since the total number of colors // fits within the palette. dst.Palette = make(color.Palette, len(colorSet)) i := 0 for _, c := range colorSet { dst.Palette[i] = c i++ } } else { dst.Palette = q.medianCut(points) } for y := 0; y < r.Dy(); y++ { for x := 0; x < r.Dx(); x++ { // TODO: this should be done more efficiently. dst.Set(sp.X+x, sp.Y+y, src.At(r.Min.X+x, r.Min.Y+y)) } } }
// Merge les deux images de telle sorte qu'après l'opération les pixels de img1 : // - soient inchangés là où l'index dans img2 est 0 // - prennent la valeur de img2 ailleurs // Les deux images doivent être de mêmes dimensions exactement // La palette de img1 est enrichie si nécessaire func Fusionne(img1 *image.Paletted, img2 *image.Paletted) error { r1 := img1.Bounds() r2 := img2.Bounds() if r1.Min.X != r2.Min.X || r1.Max.X != r2.Max.X || r1.Min.Y != r2.Min.Y || r1.Max.Y != r2.Max.Y { return errors.New("image dimensions not compatible") } p1 := img1.Palette p2 := img2.Palette n1 := len(p1) n2 := len(p2) op := make([]uint8, n2) // tableau donnant l'index dans la palette de img1 d'une couleur de la palette de img2 for i2 := 0; i2 < n2; i2++ { c := p2[i2].(color.RGBA) if i2 < n1 && couleursEgales(c, p1[i2].(color.RGBA)) { op[i2] = uint8(i2) } else { found := false for i1 := 0; i1 < n1; i1++ { if couleursEgales(c, p1[i1].(color.RGBA)) { op[i2] = uint8(i1) found = true break } } if !found { op[i2] = uint8(len(p1)) p1 = append(p1, c) img1.Palette = p1 } } } l2 := len(img2.Pix) for x := 0; x < l2; x++ { if img2.Pix[x] != 0 { img1.Pix[x] = op[img2.Pix[x]] } } return nil }
func (d *decoder) uninterlace(m *image.Paletted) { if d.imageFields&ifInterlace == 0 { return } var nPix []uint8 dx := d.width dy := d.height nPix = make([]uint8, dx*dy) offset := 0 // steps through the input by sequentical scan lines. for _, pass := range interlacing { nOffset := pass.start * dx // steps through the output as defined by pass. for y := pass.start; y < dy; y += pass.skip { copy(nPix[nOffset:nOffset+dx], m.Pix[offset:offset+dx]) offset += dx nOffset += dx * pass.skip } } m.Pix = nPix }
func encodeImageBlock(w io.Writer, img *image.Paletted) error { // start image litWidth := int(paletteBits(img.Palette)) if litWidth < 2 { litWidth = 2 } bounds := img.Bounds() if err := writeData(w, byte(0x2C), uint16(bounds.Min.X), uint16(bounds.Min.Y), uint16(bounds.Dx()), uint16(bounds.Dy()), byte(0), byte(litWidth), ); err != nil { return err } // start compression blocks := &blockWriter{w: w} compress := lzw.NewWriter(blocks, lzw.LSB, litWidth) // write each scan line (might not be contiguous) startX := img.Rect.Min.X stopX := img.Rect.Max.X stopY := img.Rect.Max.Y for y := img.Rect.Min.Y; y < stopY; y++ { start := img.PixOffset(startX, y) stop := img.PixOffset(stopX, y) if _, err := compress.Write(img.Pix[start:stop]); err != nil { return err } } if err := compress.Close(); err != nil { return err } return blocks.Close() }
func (g *generator) buildTerrain(mpath minecraft.Path, level *level, terrain, biomes, plants *image.Paletted, height, water *image.Gray, c chan paint) error { b := terrain.Bounds() proceed := make(chan uint8, 10) errChan := make(chan error, 1) go func() { defer close(proceed) cc := newCache(g.Terrain.Blocks) for j := 0; j < b.Max.Y; j += 16 { chunkZ := int32(j >> 4) for i := 0; i < b.Max.X; i += 16 { chunkX := int32(i >> 4) h := int32(meanHeight(height.SubImage(image.Rect(i, j, i+16, j+16)).(*image.Gray))) wh := int32(meanHeight(water.SubImage(image.Rect(i, j, i+16, j+16)).(*image.Gray))) var t uint8 if wh >= h<<1 { // more water than land... c <- paint{ color.RGBA{0, 0, 255, 255}, chunkX, chunkZ, } t = uint8(len(g.Terrain.Blocks) - 1) h = wh } else { t = modeTerrain(terrain.SubImage(image.Rect(i, j, i+16, j+16)).(*image.Paletted), len(g.Terrain.Palette)) c <- paint{ g.Terrain.Palette[t], chunkX, chunkZ, } } if err := mpath.SetChunk(cc.getFromCache(chunkX, chunkZ, t, h)); err != nil { errChan <- err return } proceed <- t } } }() ts := make([]uint8, 0, 1024) for i := 0; i < (b.Max.X>>4)+2; i++ { ts = append(ts, <-proceed) // get far enough ahead so all chunks are surrounded before shaping, to get correct lighting } select { case err := <-errChan: return err default: } for j := int32(0); j < int32(b.Max.Y); j += 16 { chunkZ := j >> 4 for i := int32(0); i < int32(b.Max.X); i += 16 { chunkX := i >> 4 var totalHeight int32 ot := ts[0] ts = ts[1:] oy, _ := level.GetHeight(i, j) for x := i; x < i+16; x++ { for z := j; z < j+16; z++ { if biomes != nil { level.SetBiome(x, z, g.Biomes.Values[biomes.ColorIndexAt(int(x), int(z))]) } h := int32(height.GrayAt(int(x), int(z)).Y) totalHeight += h wl := int32(water.GrayAt(int(x), int(z)).Y) y := oy if h > y { y = h } if wl > y { y = wl } for ; y > h && y > wl; y-- { level.SetBlock(x, y, z, minecraft.Block{}) } if plants != nil { p := g.Plants.Blocks[plants.ColorIndexAt(int(x), int(z))] py := int32(1) for ; py <= int32(p.Level); py++ { level.SetBlock(x, y+py, z, p.Base) } level.SetBlock(x, y+py, z, p.Top) } for ; y > h; y-- { level.SetBlock(x, y, z, minecraft.Block{ID: 9}) } t := terrain.ColorIndexAt(int(x), int(z)) tb := g.Terrain.Blocks[t] for ; y > h-int32(tb.Level); y-- { level.SetBlock(x, y, z, tb.Top) } if t != ot { h = 0 } else { h = oy } for ; y >= h; y-- { level.SetBlock(x, y, z, tb.Base) } } } c <- paint{ color.Alpha{uint8(totalHeight >> 8)}, chunkX, chunkZ, } select { case p, ok := <-proceed: if ok { ts = append(ts, p) } case err := <-errChan: return err } } } return nil }
func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) { if e.err != nil { return } if len(pm.Palette) == 0 { e.err = errors.New("gif: cannot encode image block with empty palette") return } b := pm.Bounds() if b.Min.X < 0 || b.Max.X >= 1<<16 || b.Min.Y < 0 || b.Max.Y >= 1<<16 { e.err = errors.New("gif: image block is too large to encode") return } if !b.In(image.Rectangle{Max: image.Point{e.g.Config.Width, e.g.Config.Height}}) { e.err = errors.New("gif: image block is out of bounds") return } transparentIndex := -1 for i, c := range pm.Palette { if _, _, _, a := c.RGBA(); a == 0 { transparentIndex = i break } } if delay > 0 || disposal != 0 || transparentIndex != -1 { e.buf[0] = sExtension // Extension Introducer. e.buf[1] = gcLabel // Graphic Control Label. e.buf[2] = gcBlockSize // Block Size. if transparentIndex != -1 { e.buf[3] = 0x01 | disposal<<2 } else { e.buf[3] = 0x00 | disposal<<2 } writeUint16(e.buf[4:6], uint16(delay)) // Delay Time (1/100ths of a second) // Transparent color index. if transparentIndex != -1 { e.buf[6] = uint8(transparentIndex) } else { e.buf[6] = 0x00 } e.buf[7] = 0x00 // Block Terminator. e.write(e.buf[:8]) } e.buf[0] = sImageDescriptor writeUint16(e.buf[1:3], uint16(b.Min.X)) writeUint16(e.buf[3:5], uint16(b.Min.Y)) writeUint16(e.buf[5:7], uint16(b.Dx())) writeUint16(e.buf[7:9], uint16(b.Dy())) e.write(e.buf[:9]) paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n). ct := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize) if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) { // Use a local color table. e.writeByte(fColorTable | uint8(paddedSize)) e.write(e.localColorTable[:ct]) } else { // Use the global color table. e.writeByte(0) } litWidth := paddedSize + 1 if litWidth < 2 { litWidth = 2 } e.writeByte(uint8(litWidth)) // LZW Minimum Code Size. lzww := lzw.NewWriter(blockWriter{e: e}, lzw.LSB, litWidth) if dx := b.Dx(); dx == pm.Stride { _, e.err = lzww.Write(pm.Pix) if e.err != nil { lzww.Close() return } } else { for i, y := 0, b.Min.Y; y < b.Max.Y; i, y = i+pm.Stride, y+1 { _, e.err = lzww.Write(pm.Pix[i : i+dx]) if e.err != nil { lzww.Close() return } } } lzww.Close() e.writeByte(0x00) // Block Terminator. }
func writeImage(w io.Writer, m image.Image, ct uint8) os.Error { zw, err := zlib.NewDeflater(w) if err != nil { return err } defer zw.Close() bpp := 0 // Bytes per pixel. var paletted *image.Paletted switch ct { case ctTrueColor: bpp = 3 case ctPaletted: bpp = 1 paletted = m.(*image.Paletted) case ctTrueColorAlpha: bpp = 4 } // cr[*] and pr are the bytes for the current and previous row. // cr[0] is unfiltered (or equivalently, filtered with the ftNone filter). // cr[ft], for non-zero filter types ft, are buffers for transforming cr[0] under the // other PNG filter types. These buffers are allocated once and re-used for each row. // The +1 is for the per-row filter type, which is at cr[*][0]. var cr [nFilter][]uint8 for i := 0; i < len(cr); i++ { cr[i] = make([]uint8, 1+bpp*m.Width()) cr[i][0] = uint8(i) } pr := make([]uint8, 1+bpp*m.Width()) for y := 0; y < m.Height(); y++ { // Convert from colors to bytes. switch ct { case ctTrueColor: for x := 0; x < m.Width(); x++ { // We have previously verified that the alpha value is fully opaque. r, g, b, _ := m.At(x, y).RGBA() cr[0][3*x+1] = uint8(r >> 24) cr[0][3*x+2] = uint8(g >> 24) cr[0][3*x+3] = uint8(b >> 24) } case ctPaletted: for x := 0; x < m.Width(); x++ { cr[0][x+1] = paletted.ColorIndexAt(x, y) } case ctTrueColorAlpha: // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied. for x := 0; x < m.Width(); x++ { c := image.NRGBAColorModel.Convert(m.At(x, y)).(image.NRGBAColor) cr[0][4*x+1] = c.R cr[0][4*x+2] = c.G cr[0][4*x+3] = c.B cr[0][4*x+4] = c.A } } // Apply the filter. f := filter(cr[0:nFilter], pr, bpp) // Write the compressed bytes. _, err = zw.Write(cr[f]) if err != nil { return err } // The current row for y is the previous row for y+1. pr, cr[0] = cr[0], pr } return nil }
func (d *decoder) idatReader(idat io.Reader) os.Error { r, err := zlib.NewInflater(idat) if err != nil { return err } defer r.Close() bpp := 0 // Bytes per pixel. maxPalette := uint8(0) var ( rgba *image.RGBA nrgba *image.NRGBA paletted *image.Paletted ) switch d.colorType { case ctTrueColor: bpp = 3 rgba = d.image.(*image.RGBA) case ctPaletted: bpp = 1 paletted = d.image.(*image.Paletted) maxPalette = uint8(len(paletted.Palette) - 1) case ctTrueColorAlpha: bpp = 4 nrgba = d.image.(*image.NRGBA) } // cr and pr are the bytes for the current and previous row. // The +1 is for the per-row filter type, which is at cr[0]. cr := make([]uint8, 1+bpp*d.width) pr := make([]uint8, 1+bpp*d.width) for y := 0; y < d.height; y++ { // Read the decompressed bytes. _, err := io.ReadFull(r, cr) if err != nil { return err } // Apply the filter. cdat := cr[1:] pdat := pr[1:] switch cr[0] { case ftNone: // No-op. case ftSub: for i := bpp; i < len(cdat); i++ { cdat[i] += cdat[i-bpp] } case ftUp: for i := 0; i < len(cdat); i++ { cdat[i] += pdat[i] } case ftAverage: for i := 0; i < bpp; i++ { cdat[i] += pdat[i] / 2 } for i := bpp; i < len(cdat); i++ { cdat[i] += uint8((int(cdat[i-bpp]) + int(pdat[i])) / 2) } case ftPaeth: for i := 0; i < bpp; i++ { cdat[i] += paeth(0, pdat[i], 0) } for i := bpp; i < len(cdat); i++ { cdat[i] += paeth(cdat[i-bpp], pdat[i], pdat[i-bpp]) } default: return FormatError("bad filter type") } // Convert from bytes to colors. switch d.colorType { case ctTrueColor: for x := 0; x < d.width; x++ { rgba.Set(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff}) } case ctPaletted: for x := 0; x < d.width; x++ { if cdat[x] > maxPalette { return FormatError("palette index out of range") } paletted.SetColorIndex(x, y, cdat[x]) } case ctTrueColorAlpha: for x := 0; x < d.width; x++ { nrgba.Set(x, y, image.NRGBAColor{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]}) } } // The current row for y is the previous row for y+1. pr, cr = cr, pr } return nil }
// readImagePass reads a single image pass, sized according to the pass number. func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image.Image, error) { var bitsPerPixel int = 0 pixOffset := 0 var ( gray *image.Gray rgba *image.RGBA paletted *image.Paletted nrgba *image.NRGBA gray16 *image.Gray16 rgba64 *image.RGBA64 nrgba64 *image.NRGBA64 img image.Image ) width, height := d.width, d.height if d.interlace == itAdam7 && !allocateOnly { p := interlacing[pass] // Add the multiplication factor and subtract one, effectively rounding up. width = (width - p.xOffset + p.xFactor - 1) / p.xFactor height = (height - p.yOffset + p.yFactor - 1) / p.yFactor // A PNG image can't have zero width or height, but for an interlaced // image, an individual pass might have zero width or height. If so, we // shouldn't even read a per-row filter type byte, so return early. if width == 0 || height == 0 { return nil, nil } } switch d.cb { case cbG1, cbG2, cbG4, cbG8: bitsPerPixel = d.depth gray = image.NewGray(image.Rect(0, 0, width, height)) img = gray case cbGA8: bitsPerPixel = 16 nrgba = image.NewNRGBA(image.Rect(0, 0, width, height)) img = nrgba case cbTC8: bitsPerPixel = 24 rgba = image.NewRGBA(image.Rect(0, 0, width, height)) img = rgba case cbP1, cbP2, cbP4, cbP8: bitsPerPixel = d.depth paletted = image.NewPaletted(image.Rect(0, 0, width, height), d.palette) img = paletted case cbTCA8: bitsPerPixel = 32 nrgba = image.NewNRGBA(image.Rect(0, 0, width, height)) img = nrgba case cbG16: bitsPerPixel = 16 gray16 = image.NewGray16(image.Rect(0, 0, width, height)) img = gray16 case cbGA16: bitsPerPixel = 32 nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height)) img = nrgba64 case cbTC16: bitsPerPixel = 48 rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height)) img = rgba64 case cbTCA16: bitsPerPixel = 64 nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height)) img = nrgba64 } if allocateOnly { return img, nil } bytesPerPixel := (bitsPerPixel + 7) / 8 // The +1 is for the per-row filter type, which is at cr[0]. rowSize := 1 + (bitsPerPixel*width+7)/8 // cr and pr are the bytes for the current and previous row. cr := make([]uint8, rowSize) pr := make([]uint8, rowSize) for y := 0; y < height; y++ { // Read the decompressed bytes. _, err := io.ReadFull(r, cr) if err != nil { if err == io.EOF || err == io.ErrUnexpectedEOF { return nil, FormatError("not enough pixel data") } return nil, err } // Apply the filter. cdat := cr[1:] pdat := pr[1:] switch cr[0] { case ftNone: // No-op. case ftSub: for i := bytesPerPixel; i < len(cdat); i++ { cdat[i] += cdat[i-bytesPerPixel] } case ftUp: for i, p := range pdat { cdat[i] += p } case ftAverage: // The first column has no column to the left of it, so it is a // special case. We know that the first column exists because we // check above that width != 0, and so len(cdat) != 0. for i := 0; i < bytesPerPixel; i++ { cdat[i] += pdat[i] / 2 } for i := bytesPerPixel; i < len(cdat); i++ { cdat[i] += uint8((int(cdat[i-bytesPerPixel]) + int(pdat[i])) / 2) } case ftPaeth: filterPaeth(cdat, pdat, bytesPerPixel) default: return nil, FormatError("bad filter type") } // Convert from bytes to colors. switch d.cb { case cbG1: for x := 0; x < width; x += 8 { b := cdat[x/8] for x2 := 0; x2 < 8 && x+x2 < width; x2++ { gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff}) b <<= 1 } } case cbG2: for x := 0; x < width; x += 4 { b := cdat[x/4] for x2 := 0; x2 < 4 && x+x2 < width; x2++ { gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55}) b <<= 2 } } case cbG4: for x := 0; x < width; x += 2 { b := cdat[x/2] for x2 := 0; x2 < 2 && x+x2 < width; x2++ { gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11}) b <<= 4 } } case cbG8: copy(gray.Pix[pixOffset:], cdat) pixOffset += gray.Stride case cbGA8: for x := 0; x < width; x++ { ycol := cdat[2*x+0] nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]}) } case cbTC8: pix, i, j := rgba.Pix, pixOffset, 0 for x := 0; x < width; x++ { pix[i+0] = cdat[j+0] pix[i+1] = cdat[j+1] pix[i+2] = cdat[j+2] pix[i+3] = 0xff i += 4 j += 3 } pixOffset += rgba.Stride case cbP1: for x := 0; x < width; x += 8 { b := cdat[x/8] for x2 := 0; x2 < 8 && x+x2 < width; x2++ { idx := b >> 7 if len(paletted.Palette) <= int(idx) { paletted.Palette = paletted.Palette[:int(idx)+1] } paletted.SetColorIndex(x+x2, y, idx) b <<= 1 } } case cbP2: for x := 0; x < width; x += 4 { b := cdat[x/4] for x2 := 0; x2 < 4 && x+x2 < width; x2++ { idx := b >> 6 if len(paletted.Palette) <= int(idx) { paletted.Palette = paletted.Palette[:int(idx)+1] } paletted.SetColorIndex(x+x2, y, idx) b <<= 2 } } case cbP4: for x := 0; x < width; x += 2 { b := cdat[x/2] for x2 := 0; x2 < 2 && x+x2 < width; x2++ { idx := b >> 4 if len(paletted.Palette) <= int(idx) { paletted.Palette = paletted.Palette[:int(idx)+1] } paletted.SetColorIndex(x+x2, y, idx) b <<= 4 } } case cbP8: if len(paletted.Palette) != 255 { for x := 0; x < width; x++ { if len(paletted.Palette) <= int(cdat[x]) { paletted.Palette = paletted.Palette[:int(cdat[x])+1] } } } copy(paletted.Pix[pixOffset:], cdat) pixOffset += paletted.Stride case cbTCA8: copy(nrgba.Pix[pixOffset:], cdat) pixOffset += nrgba.Stride case cbG16: for x := 0; x < width; x++ { ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1]) gray16.SetGray16(x, y, color.Gray16{ycol}) } case cbGA16: for x := 0; x < width; x++ { ycol := uint16(cdat[4*x+0])<<8 | uint16(cdat[4*x+1]) acol := uint16(cdat[4*x+2])<<8 | uint16(cdat[4*x+3]) nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol}) } case cbTC16: for x := 0; x < width; x++ { rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1]) gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3]) bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5]) rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff}) } case cbTCA16: for x := 0; x < width; x++ { rcol := uint16(cdat[8*x+0])<<8 | uint16(cdat[8*x+1]) gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3]) bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5]) acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7]) nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol}) } } // The current row for y is the previous row for y+1. pr, cr = cr, pr } return img, nil }
func (w *wire) draw(img *image.Paletted, colorIndex uint8) { for _, pixel := range w.pixels { img.SetColorIndex(pixel.X, pixel.Y, colorIndex) } }
// 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") }
func NewSimulation(img *image.Paletted) *Simulation { size := img.Bounds().Size() groups := make(map[*group]struct{}, 0) matrix := newBucketMatrix(size.X, size.Y) for y := 0; y < size.Y; y++ { for x := 0; x < size.X; x++ { c := img.ColorIndexAt(x, y) if c > 0 && c <= maxCharge+1 { topLeftBucket := matrix.get(x-1, y-1) topBucket := matrix.get(x, y-1) leftBucket := matrix.get(x-1, y) var currentBucket *bucket switch { case nil == topBucket && nil == leftBucket: currentBucket = newBucket() groups[currentBucket.group] = struct{}{} case nil == topBucket && nil != leftBucket: currentBucket = leftBucket case (nil != topBucket && nil == leftBucket) || topBucket == leftBucket || topBucket.group == leftBucket.group: currentBucket = topBucket default: currentBucket = topBucket delete(groups, topBucket.group) topBucket.group.moveBucketsTo(leftBucket.group) } if nil != topLeftBucket && nil != topBucket && nil != leftBucket { currentBucket.group.wire.isPowerSource = true } matrix.set(x, y, currentBucket) currentBucket.addPixel(image.Point{x, y}) } } } for y := 0; y < size.Y; y++ { for x := 0; x < size.X; x++ { if nil != matrix.get(x, y) { continue } topBucket := matrix.get(x, y-1) topRightBucket := matrix.get(x+1, y-1) rightBucket := matrix.get(x+1, y) bottomRightBucket := matrix.get(x+1, y+1) bottomBucket := matrix.get(x, y+1) bottomLeftBucket := matrix.get(x-1, y+1) leftBucket := matrix.get(x-1, y) topLeftBucket := matrix.get(x-1, y-1) if nil == topLeftBucket && nil == topRightBucket && nil == bottomLeftBucket && nil == bottomRightBucket && nil != topBucket && nil != rightBucket && nil != bottomBucket && nil != leftBucket { delete(groups, topBucket.group) topBucket.group.moveBucketsTo(bottomBucket.group) delete(groups, leftBucket.group) leftBucket.group.moveBucketsTo(rightBucket.group) } } } transistors := make([]*transistor, 0) for y := 0; y < size.Y; y++ { for x := 0; x < size.X; x++ { if nil != matrix.get(x, y) { continue } topBucket := matrix.get(x, y-1) topRightBucket := matrix.get(x+1, y-1) rightBucket := matrix.get(x+1, y) bottomRightBucket := matrix.get(x+1, y+1) bottomBucket := matrix.get(x, y+1) bottomLeftBucket := matrix.get(x-1, y+1) leftBucket := matrix.get(x-1, y) topLeftBucket := matrix.get(x-1, y-1) switch { case nil == bottomLeftBucket && nil == bottomRightBucket && nil == topBucket && nil != rightBucket && nil != bottomBucket && nil != leftBucket: transistors = append(transistors, newTransistor(image.Point{x, y}, bottomBucket.group.wire, rightBucket.group.wire, leftBucket.group.wire)) case nil == bottomLeftBucket && nil == topLeftBucket && nil != topBucket && nil == rightBucket && nil != bottomBucket && nil != leftBucket: transistors = append(transistors, newTransistor(image.Point{x, y}, leftBucket.group.wire, topBucket.group.wire, bottomBucket.group.wire)) case nil == topLeftBucket && nil == topRightBucket && nil != topBucket && nil != rightBucket && nil == bottomBucket && nil != leftBucket: transistors = append(transistors, newTransistor(image.Point{x, y}, topBucket.group.wire, rightBucket.group.wire, leftBucket.group.wire)) case nil == bottomRightBucket && nil == topRightBucket && nil != topBucket && nil != rightBucket && nil != bottomBucket && nil == leftBucket: transistors = append(transistors, newTransistor(image.Point{x, y}, rightBucket.group.wire, topBucket.group.wire, bottomBucket.group.wire)) } } } wires := make([]*wire, len(groups)) wireStates := make([]wireState, len(groups)) i := 0 for k := range groups { k.wire.index = i wires[i] = k.wire var charge uint8 if k.wire.isPowerSource { charge = maxCharge } else { charge = 0 } wireStates[i] = wireState{charge, k.wire} i++ } return &Simulation{&circuit{wires: wires, transistors: transistors}, wireStates} }
// decode reads a GIF image from r and stores the result in d. func (d *decoder) decode(r io.Reader, configOnly bool) error { // Add buffering if r does not provide ReadByte. if rr, ok := r.(reader); ok { d.r = rr } else { d.r = bufio.NewReader(r) } err := d.readHeaderAndScreenDescriptor() if err != nil { return err } if configOnly { return nil } if d.headerFields&fColorMapFollows != 0 { if d.globalColorMap, err = d.readColorMap(); err != nil { return err } } Loop: for err == nil { var c byte c, err = d.r.ReadByte() if err == io.EOF { break } switch c { case sExtension: err = d.readExtension() case sImageDescriptor: var m *image.Paletted m, err = d.newImageFromDescriptor() if err != nil { break } if d.imageFields&fColorMapFollows != 0 { m.Palette, err = d.readColorMap() if err != nil { break } // TODO: do we set transparency in this map too? That would be // d.setTransparency(m.Palette) } else { m.Palette = d.globalColorMap } var litWidth uint8 litWidth, err = d.r.ReadByte() if err != nil { return err } if litWidth < 2 || litWidth > 8 { return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth) } // A wonderfully Go-like piece of magic. lzwr := lzw.NewReader(&blockReader{r: d.r}, lzw.LSB, int(litWidth)) if _, err = io.ReadFull(lzwr, m.Pix); err != nil { break } // There should be a "0" block remaining; drain that. c, err = d.r.ReadByte() if err != nil { return err } if c != 0 { return errors.New("gif: extra data after image") } // Undo the interlacing if necessary. if d.imageFields&ifInterlace != 0 { uninterlace(m) } d.image = append(d.image, m) d.delay = append(d.delay, d.delayTime) d.delayTime = 0 // TODO: is this correct, or should we hold on to the value? case sTrailer: break Loop default: err = fmt.Errorf("gif: unknown block type: 0x%.2x", c) } } if err != nil { return err } if len(d.image) == 0 { return io.ErrUnexpectedEOF } return 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 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") }
// decode decodes the IDAT data into an image. func (d *decoder) decode() (image.Image, error) { r, err := zlib.NewReader(d) if err != nil { return nil, err } defer r.Close() bitsPerPixel := 0 pixOffset := 0 var ( gray *image.Gray rgba *image.RGBA paletted *image.Paletted nrgba *image.NRGBA gray16 *image.Gray16 rgba64 *image.RGBA64 nrgba64 *image.NRGBA64 img image.Image ) switch d.cb { case cbG1, cbG2, cbG4, cbG8: bitsPerPixel = d.depth gray = image.NewGray(image.Rect(0, 0, d.width, d.height)) img = gray case cbGA8: bitsPerPixel = 16 nrgba = image.NewNRGBA(image.Rect(0, 0, d.width, d.height)) img = nrgba case cbTC8: bitsPerPixel = 24 rgba = image.NewRGBA(image.Rect(0, 0, d.width, d.height)) img = rgba case cbP1, cbP2, cbP4, cbP8: bitsPerPixel = d.depth paletted = image.NewPaletted(image.Rect(0, 0, d.width, d.height), d.palette) img = paletted case cbTCA8: bitsPerPixel = 32 nrgba = image.NewNRGBA(image.Rect(0, 0, d.width, d.height)) img = nrgba case cbG16: bitsPerPixel = 16 gray16 = image.NewGray16(image.Rect(0, 0, d.width, d.height)) img = gray16 case cbGA16: bitsPerPixel = 32 nrgba64 = image.NewNRGBA64(image.Rect(0, 0, d.width, d.height)) img = nrgba64 case cbTC16: bitsPerPixel = 48 rgba64 = image.NewRGBA64(image.Rect(0, 0, d.width, d.height)) img = rgba64 case cbTCA16: bitsPerPixel = 64 nrgba64 = image.NewNRGBA64(image.Rect(0, 0, d.width, d.height)) img = nrgba64 } bytesPerPixel := (bitsPerPixel + 7) / 8 // cr and pr are the bytes for the current and previous row. // The +1 is for the per-row filter type, which is at cr[0]. cr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8) pr := make([]uint8, 1+(bitsPerPixel*d.width+7)/8) for y := 0; y < d.height; y++ { // Read the decompressed bytes. _, err := io.ReadFull(r, cr) if err != nil { return nil, err } // Apply the filter. cdat := cr[1:] pdat := pr[1:] switch cr[0] { case ftNone: // No-op. case ftSub: for i := bytesPerPixel; i < len(cdat); i++ { cdat[i] += cdat[i-bytesPerPixel] } case ftUp: for i, p := range pdat { cdat[i] += p } case ftAverage: for i := 0; i < bytesPerPixel; i++ { cdat[i] += pdat[i] / 2 } for i := bytesPerPixel; i < len(cdat); i++ { cdat[i] += uint8((int(cdat[i-bytesPerPixel]) + int(pdat[i])) / 2) } case ftPaeth: filterPaeth(cdat, pdat, bytesPerPixel) default: return nil, FormatError("bad filter type") } // Convert from bytes to colors. switch d.cb { case cbG1: for x := 0; x < d.width; x += 8 { b := cdat[x/8] for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ { gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff}) b <<= 1 } } case cbG2: for x := 0; x < d.width; x += 4 { b := cdat[x/4] for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ { gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55}) b <<= 2 } } case cbG4: for x := 0; x < d.width; x += 2 { b := cdat[x/2] for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ { gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11}) b <<= 4 } } case cbG8: copy(gray.Pix[pixOffset:], cdat) pixOffset += gray.Stride case cbGA8: for x := 0; x < d.width; x++ { ycol := cdat[2*x+0] nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]}) } case cbTC8: pix, i, j := rgba.Pix, pixOffset, 0 for x := 0; x < d.width; x++ { pix[i+0] = cdat[j+0] pix[i+1] = cdat[j+1] pix[i+2] = cdat[j+2] pix[i+3] = 0xff i += 4 j += 3 } pixOffset += rgba.Stride case cbP1: for x := 0; x < d.width; x += 8 { b := cdat[x/8] for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ { idx := b >> 7 if len(paletted.Palette) <= int(idx) { paletted.Palette = paletted.Palette[:int(idx)+1] } paletted.SetColorIndex(x+x2, y, idx) b <<= 1 } } case cbP2: for x := 0; x < d.width; x += 4 { b := cdat[x/4] for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ { idx := b >> 6 if len(paletted.Palette) <= int(idx) { paletted.Palette = paletted.Palette[:int(idx)+1] } paletted.SetColorIndex(x+x2, y, idx) b <<= 2 } } case cbP4: for x := 0; x < d.width; x += 2 { b := cdat[x/2] for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ { idx := b >> 4 if len(paletted.Palette) <= int(idx) { paletted.Palette = paletted.Palette[:int(idx)+1] } paletted.SetColorIndex(x+x2, y, idx) b <<= 4 } } case cbP8: if len(paletted.Palette) != 255 { for x := 0; x < d.width; x++ { if len(paletted.Palette) <= int(cdat[x]) { paletted.Palette = paletted.Palette[:int(cdat[x])+1] } } } copy(paletted.Pix[pixOffset:], cdat) pixOffset += paletted.Stride case cbTCA8: copy(nrgba.Pix[pixOffset:], cdat) pixOffset += nrgba.Stride case cbG16: for x := 0; x < d.width; x++ { ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1]) gray16.SetGray16(x, y, color.Gray16{ycol}) } case cbGA16: for x := 0; x < d.width; x++ { ycol := uint16(cdat[4*x+0])<<8 | uint16(cdat[4*x+1]) acol := uint16(cdat[4*x+2])<<8 | uint16(cdat[4*x+3]) nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol}) } case cbTC16: for x := 0; x < d.width; x++ { rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1]) gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3]) bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5]) rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff}) } case cbTCA16: for x := 0; x < d.width; x++ { rcol := uint16(cdat[8*x+0])<<8 | uint16(cdat[8*x+1]) gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3]) bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5]) acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7]) nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol}) } } // The current row for y is the previous row for y+1. pr, cr = cr, pr } // Check for EOF, to verify the zlib checksum. n, err := r.Read(pr[:1]) if err != io.EOF { return nil, FormatError(err.Error()) } if n != 0 || d.idatLength != 0 { return nil, FormatError("too much pixel data") } return img, nil }
func (e *encoder) writeImageBlock(pm *image.Paletted, delay, transparentIndex int) { if e.err != nil { return } if len(pm.Palette) == 0 { e.err = errors.New("gif: cannot encode image block with empty palette") return } b := pm.Bounds() if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 || b.Min.X < 0 || b.Min.X >= 1<<16 || b.Min.Y < 0 || b.Min.Y >= 1<<16 { e.err = errors.New("gif: image block is too large to encode") return } // -1 means unknown transparent index; -2 means definitely no transparent index. if transparentIndex == -1 { for i, c := range pm.Palette { if _, _, _, a := c.RGBA(); a == 0 { transparentIndex = i break } } transparentIndex = -2 } if delay > 0 || transparentIndex >= 0 { e.buf[0] = sExtension // Extension Introducer. e.buf[1] = gcLabel // Graphic Control Label. e.buf[2] = gcBlockSize // Block Size. if transparentIndex >= 0 { e.buf[3] = 0x01 } else { e.buf[3] = 0x00 } writeUint16(e.buf[4:6], uint16(delay)) // Delay Time (1/100ths of a second) // Transparent color index. if transparentIndex >= 0 { e.buf[6] = uint8(transparentIndex) } else { e.buf[6] = 0x00 } e.buf[7] = 0x00 // Block Terminator. e.write(e.buf[:8]) } e.buf[0] = sImageDescriptor writeUint16(e.buf[1:3], uint16(b.Min.X)) writeUint16(e.buf[3:5], uint16(b.Min.Y)) writeUint16(e.buf[5:7], uint16(b.Dx())) writeUint16(e.buf[7:9], uint16(b.Dy())) e.write(e.buf[:9]) paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n). // Interlacing is not supported. e.writeByte(0x80 | uint8(paddedSize)) // Local Color Table. e.writeColorTable(pm.Palette, paddedSize) litWidth := paddedSize + 1 if litWidth < 2 { litWidth = 2 } e.writeByte(uint8(litWidth)) // LZW Minimum Code Size. lzww := lzw.NewWriter(blockWriter{e: e}, lzw.LSB, litWidth) _, e.err = lzww.Write(pm.Pix) if e.err != nil { lzww.Close() return } lzww.Close() e.writeByte(0x00) // Block Terminator. }