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
}
Example #2
0
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)
}
Example #3
0
File: block.go Project: noikiy/gogs
// 全填充正方形
//
//  --------
//  |######|
//  |######|
//  |######|
//  --------
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)
		}
	}
}
Example #4
0
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),
		}))
	}
}
Example #5
0
File: block.go Project: noikiy/gogs
// 中间小方块
//  ----------
//  |        |
//  |  ####  |
//  |  ####  |
//  |        |
//  ----------
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)
		}
	}
}
Example #6
0
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
}
Example #7
0
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
}
Example #8
0
// 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)
}
Example #9
0
File: block.go Project: noikiy/gogs
// 将多边形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)
			}
		}
	}
}
Example #10
0
// 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
}
Example #11
0
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
}
Example #12
0
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
			}
		}
	}
}
Example #13
0
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)
}
Example #14
0
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
}
Example #15
0
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))
		}
	}
}
Example #16
0
// 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
}
Example #17
0
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
}
Example #18
0
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()
}
Example #19
0
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
}
Example #20
0
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.
}
Example #21
0
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
}
Example #22
0
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
}
Example #23
0
File: reader.go Project: 2thetop/go
// 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
}
Example #24
0
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")
}
Example #26
0
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}
}
Example #27
0
// 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
}
Example #28
0
// 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")
}
Example #29
0
// 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
}
Example #30
0
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.
}