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 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 #3
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 #4
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 #5
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 #6
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
}
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 #8
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 #9
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 #10
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 #11
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.
}
Example #12
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}
}