package draw9 import ( "bitbucket.org/mischief/draw9/color9" "image" "image/color" "runtime" ) type Image struct { Display *Display ID uint32 Pix color9.Pix R, Clipr image.Rectangle Depth int Chan uint Repl bool Next *Image Screen *Screen } // Free implements the 'f' draw(3) message. func (i *Image) Free() error { if i == nil { return nil } if i.Display != nil && i == i.Display.ScreenImage { panic("freeimage of ScreenImage") } i.Display.mu.Lock() defer i.Display.mu.Unlock() return i.free() } func (i *Image) free() error { if i == nil || i.Display == nil { return nil } // make sure no refresh events occur on this if we block in the write d := i.Display // flush pending data so we don't get error deleting the image d.flush(false) a := d.bufimage(1 + 4) a[0] = 'f' bplong(a[1:], i.ID) if i.Screen != nil { w := d.Windows if w == i { d.Windows = i.Next } else { for ; w != nil; w = w.Next { if w.Next == i { w.Next = i.Next break } } } } i.Display = nil // So a second free (perhaps through a Finalizer) will be OK. runtime.SetFinalizer(i, nil) return d.flush(i.Screen != nil) } // ColorModel returns the color model of the Image. func (i *Image) ColorModel() color.Model { switch i.Pix { case color9.GREY1: return color9.Gray1Model case color9.GREY2: return color9.Gray2Model case color9.GREY4: return color9.Gray4Model case color9.GREY8: return color.GrayModel case color9.CMAP8: return color9.CMap8Model case color9.RGB15: return color9.CRGB15Model case color9.RGB16: return color9.CRGB16Model case color9.RGB24, color9.RGBA32, color9.ARGB32, color9.ABGR32, color9.XRGB32, color9.XBGR32: return color.RGBAModel } panic("unknown image Pix type") } /* * Support for the Image type so it can satisfy the standard Color and Image interfaces. */ // At returns the standard Color value for the pixel at (x, y). // If the location is outside the clipping rectangle, it returns color.Transparent. // This operation does a round trip to the image server and can be expensive. func (i *Image) At(x, y int) color.Color { if !(image.Point{x, y}.In(i.Clipr)) { return color.Transparent } if i.Repl && !(image.Point{x, y}.In(i.R)) { // Translate (x, y) to be within i.R. x = (x-i.R.Min.X)%(i.R.Max.X-i.R.Min.X) + i.R.Min.X y = (y-i.R.Min.Y)%(i.R.Max.Y-i.R.Min.Y) + i.R.Min.Y } var buf [4]byte _, err := i.Unload(image.Rect(x, y, x+1, y+1), buf[:]) if err != nil { println("image.At: error in Unload: ", err.Error()) return color.Transparent // As good a value as any. } // For multi-byte pixels, the ordering is little-endian. // For sub-byte pixels, the ordering is big-endian (0x80 is the first bit). // Three cheers for PCs. switch i.Pix { case color9.GREY1: // CGrey, 1 mask := uint8(1 << uint8(7-x&7)) return color9.Gray1{(buf[0] & mask) != 0} case color9.GREY2: // CGrey, 2 shift := uint(x&3) << 1 // Place pixel at top of word. y := buf[0] << shift y &= 0xC0 // Replicate throughout. y |= y >> 2 y |= y >> 4 return color9.Gray2{y} case color9.GREY4: // CGrey, 4 shift := uint(x&1) << 2 // Place pixel at top of word. y := buf[0] << shift y &= 0xF0 // Replicate throughout. y |= y >> 4 return color9.Gray4{y} case color9.GREY8: // CGrey, 8 return color.Gray{buf[0]} case color9.CMAP8: // CMap, 8 return color9.CMap8{buf[0]} case color9.RGB15: v := uint16(buf[0]) | uint16(buf[1])<<8 return color9.CRGB15{v} case color9.RGB16: v := uint16(buf[0]) | uint16(buf[1])<<8 return color9.CRGB16{v} case color9.RGB24: // CRed, 8, CGreen, 8, CBlue, 8 return color.RGBA{buf[2], buf[1], buf[0], 0xFF} case color9.BGR24: // CBlue, 8, CGreen, 8, CRed, 8 return color.RGBA{buf[0], buf[1], buf[2], 0xFF} case color9.RGBA32: // CRed, 8, CGreen, 8, CBlue, 8, CAlpha, 8 return color.RGBA{buf[3], buf[2], buf[1], buf[0]} case color9.ARGB32: // CAlpha, 8, CRed, 8, CGreen, 8, CBlue, 8 // stupid VGAs return color.RGBA{buf[2], buf[1], buf[0], buf[3]} case color9.ABGR32: // CAlpha, 8, CBlue, 8, CGreen, 8, CRed, 8 return color.RGBA{buf[0], buf[1], buf[2], buf[3]} case color9.XRGB32: // CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8 return color.RGBA{buf[2], buf[1], buf[0], 0xFF} case color9.XBGR32: // CIgnore, 8, CBlue, 8, CGreen, 8, CRed, 8 return color.RGBA{buf[0], buf[1], buf[2], 0xFF} default: panic("unknown color") } } func (i *Image) Bounds() image.Rectangle { return i.Clipr } // Set implements the image/draw.Image interface. // It can change a single pixel in an Image. // The coordinates x and y are relative to the Image's upper left pixel. // The color.Color will be converted to the Image's color space. func (i *Image) Set(x, y int, c color.Color) { pt := image.Pt(x, y) model := i.ColorModel() convc := model.Convert(c) r, g, b, _ := convc.RGBA() colr := color9.Color((r << 24) | (g << 16) | (b << 8) | 0xFF) img, err := i.Display.AllocImage(image.Rect(0, 0, 1, 1), i.Pix, true, colr) if err != nil { panic(err) } i.Draw(image.Rect(pt.X, pt.Y, pt.X+1, pt.Y+1), img, nil, image.ZP) }