179 lines · 4.2 KB · Go
RawDownload
package draw9 import (	"bitbucket.org/mischief/draw9/color9"	"bitbucket.org/mischief/draw9/image9"	"bytes"	"fmt"	"image"	"runtime") // LoadImage loads an image.Image onto the Display, and returns a handle to the Image.func (d *Display) LoadImage(load image.Image) (i *Image, err error) {	i, err = d.AllocImage(load.Bounds(), color9.RGBA32, false, 0) 	if err != nil {		return nil, err	} 	img9buf := new(bytes.Buffer) 	if err = image9.Encode(img9buf, load); err != nil {		return nil, err	} 	if _, err = i.Load(load.Bounds(), img9buf.Bytes()[60:]); err != nil {		return nil, err	} 	return i, nil} // AllocImage allocates a new Image on display d.func (d *Display) AllocImage(r image.Rectangle, pix color9.Pix, repl bool, val color9.Color) (*Image, error) {	d.mu.Lock()	defer d.mu.Unlock()	return allocImage(d, nil, r, pix, repl, val, 0, 0)} func (d *Display) allocImage(r image.Rectangle, pix color9.Pix, repl bool, val color9.Color) (i *Image, err error) {	return allocImage(d, nil, r, pix, repl, val, 0, 0)} // implements message 'b'func allocImage(d *Display, ai *Image, r image.Rectangle, pix color9.Pix, repl bool, val color9.Color, screenid uint32, refresh int) (i *Image, err error) {	defer func() {		if err != nil {			err = fmt.Errorf("allocimage %v %v: %v", r, pix, err)			i.free()			i = nil		}	}() 	depth := pix.Depth()	if depth == 0 {		err = fmt.Errorf("bad channel descriptor")		panic(err)		return	} 	// flush pending data so we don't get error allocating the image	d.flush(false)	a := d.bufimage(1 + 4 + 4 + 1 + 4 + 1 + 4*4 + 4*4 + 4)	d.imageid++	id := d.imageid	a[0] = 'b'	bplong(a[1:], id)	bplong(a[5:], screenid)	a[9] = byte(refresh)	bplong(a[10:], uint32(pix))	if repl {		a[14] = 1	} else {		a[14] = 0	}	bplong(a[15:], uint32(r.Min.X))	bplong(a[19:], uint32(r.Min.Y))	bplong(a[23:], uint32(r.Max.X))	bplong(a[27:], uint32(r.Max.Y))	clipr := r	if repl {		// huge but not infinite, so various offsets will leave it huge, not overflow		clipr = image.Rect(-0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF)	}	bplong(a[31:], uint32(clipr.Min.X))	bplong(a[35:], uint32(clipr.Min.Y))	bplong(a[39:], uint32(clipr.Max.X))	bplong(a[43:], uint32(clipr.Max.Y))	bplong(a[47:], uint32(val))	if err = d.flush(false); err != nil {		return	} 	i = ai	if i == nil {		i = new(Image)	}	*i = Image{		Display: d,		ID:      id,		Pix:     pix,		Depth:   pix.Depth(),		R:       r,		Clipr:   clipr,		Repl:    repl,	}	runtime.SetFinalizer(i, (*Image).Free)	return i, nil} func (d *Display) AllocImageMix(color1, color3 color9.Color) *Image {	d.mu.Lock()	defer d.mu.Unlock()	if d.ScreenImage.Depth <= 8 { // create a 2x2 texture		t, _ := d.allocImage(image.Rect(0, 0, 1, 1), d.ScreenImage.Pix, false, color1)		b, _ := d.allocImage(image.Rect(0, 0, 2, 2), d.ScreenImage.Pix, true, color3)		b.draw(image.Rect(0, 0, 1, 1), t, nil, image.ZP)		t.free()		return b	} 	// use a solid color, blended using alpha	if d.qmask == nil {		d.qmask, _ = d.allocImage(image.Rect(0, 0, 1, 1), color9.GREY8, true, 0x3F3F3FFF)	}	t, _ := d.allocImage(image.Rect(0, 0, 1, 1), d.ScreenImage.Pix, true, color1)	b, _ := d.allocImage(image.Rect(0, 0, 1, 1), d.ScreenImage.Pix, true, color3)	b.draw(b.R, t, d.qmask, image.ZP)	return b} /* implements message 'n' */func (d *Display) namedimage(name []byte) (*Image, error) {	d.flush(false)	a := d.bufimage(1 + 4 + 1 + len(name))	d.imageid++	id := d.imageid 	a[0] = 'n'	bplong(a[1:], id)	a[5] = byte(len(name))	copy(a[6:], name)	if err := d.flush(false); err != nil {		return nil, fmt.Errorf("namedimage: %s", err)	} 	ctlbuf, err := d.readctl()	if err != nil {		return nil, fmt.Errorf("namedimage: %s", err)	} 	pix, _ := color9.ParsePix(string(ctlbuf[2*12 : 3*12]))	image := &Image{		Display: d,		ID:      id,		Pix:     pix,		Depth:   pix.Depth(),		Repl:    atoi(ctlbuf[3*12:]) > 0,		R:       ator(ctlbuf[4*12:]),		Clipr:   ator(ctlbuf[8*12:]),		Next:    nil,		Screen:  nil,	} 	return image, nil} /* implements message 'N' */func nameimage(i *Image, name string, in bool) error {	a := i.Display.bufimage(1 + 4 + 1 + 1 + len(name))	a[0] = 'N'	bplong(a[1:], i.ID)	if in {		a[5] = 1	}	a[6] = byte(len(name))	copy(a[7:], name)	return i.Display.flush(false)}