From 0c9ae150bfea0a58ff6a640cec69f1f339b14752 Mon Sep 17 00:00:00 2001 From: "legoff.laurent" Date: Tue, 22 Mar 2011 21:23:03 +0100 Subject: [PATCH] use draw.Image instead of image.Image --- cmd/testX11draw.go | 67 +++++++++++++++------------------ draw2d/Makefile | 1 + draw2d/draw2d.go | 46 ++++++++++++++--------- draw2d/paint.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 53 deletions(-) create mode 100644 draw2d/paint.go diff --git a/cmd/testX11draw.go b/cmd/testX11draw.go index f12ce18..42d0dae 100644 --- a/cmd/testX11draw.go +++ b/cmd/testX11draw.go @@ -16,47 +16,42 @@ func main() { return } screen := window.Screen() - if rgba, ok := screen.(*image.RGBA); ok { - gc := draw2d.NewImageGraphicContext(rgba) - gc.SetStrokeColor(image.Black) - gc.SetFillColor(image.White) - gc.Clear() - for i := 0.0; i < 360; i = i + 10 { // Go from 0 to 360 degrees in 10 degree steps - gc.BeginPath() // Start a new path - gc.Save() // Keep rotations temporary - gc.MoveTo(144, 144) - gc.Rotate(i * (math.Pi / 180.0)) // Rotate by degrees on stack from 'for' - gc.RLineTo(72, 0) - gc.Stroke() - gc.Restore() // Get back the unrotated state - } - fmt.Printf("This is an rgba image\n") + gc := draw2d.NewImageGraphicContext(screen) + gc.SetStrokeColor(image.Black) + gc.SetFillColor(image.White) + gc.Clear() + for i := 0.0; i < 360; i = i + 10 { // Go from 0 to 360 degrees in 10 degree steps + gc.BeginPath() // Start a new path + gc.Save() // Keep rotations temporary + gc.MoveTo(144, 144) + gc.Rotate(i * (math.Pi / 180.0)) // Rotate by degrees on stack from 'for' + gc.RLineTo(72, 0) + gc.Stroke() + gc.Restore() // Get back the unrotated state + } - window.FlushImage() + window.FlushImage() - gc.SetLineWidth(3) - nbclick := 0 - for { + gc.SetLineWidth(3) + nbclick := 0 + for { - switch evt := (<-window.EventChan()).(type) { - case draw.KeyEvent: - if evt.Key == 'q' { - window.Close() - } - case draw.MouseEvent: - if evt.Buttons&1 != 0 { - if nbclick%2 == 0 { - gc.MoveTo(float64(evt.Loc.X), float64(evt.Loc.Y)) - } else { - gc.LineTo(float64(evt.Loc.X), float64(evt.Loc.Y)) - gc.Stroke() - window.FlushImage() - } - nbclick = nbclick + 1 + switch evt := (<-window.EventChan()).(type) { + case draw.KeyEvent: + if evt.Key == 'q' { + window.Close() + } + case draw.MouseEvent: + if evt.Buttons&1 != 0 { + if nbclick%2 == 0 { + gc.MoveTo(float64(evt.Loc.X), float64(evt.Loc.Y)) + } else { + gc.LineTo(float64(evt.Loc.X), float64(evt.Loc.Y)) + gc.Stroke() + window.FlushImage() } + nbclick = nbclick + 1 } } - } else { - fmt.Printf("Not an RGBA image!\n") } } diff --git a/draw2d/Makefile b/draw2d/Makefile index 4a4eac0..32d152f 100644 --- a/draw2d/Makefile +++ b/draw2d/Makefile @@ -18,5 +18,6 @@ GOFILES=\ advanced_path.go\ vertex2d.go\ gc.go\ + paint.go\ include $(GOROOT)/src/Make.pkg diff --git a/draw2d/draw2d.go b/draw2d/draw2d.go index c39205a..83e1c72 100644 --- a/draw2d/draw2d.go +++ b/draw2d/draw2d.go @@ -10,8 +10,14 @@ import ( "freetype-go.googlecode.com/hg/freetype/raster" ) +type Painter interface{ + raster.Painter + SetColor(color image.Color) +} + type ImageGraphicContext struct { - PaintedImage *image.RGBA + img draw.Image + painter Painter fillRasterizer *raster.Rasterizer strokeRasterizer *raster.Rasterizer freetype *freetype.Context @@ -39,10 +45,19 @@ type contextStack struct { /** * Create a new Graphic context from an image */ -func NewImageGraphicContext(pi *image.RGBA) *ImageGraphicContext { +func NewImageGraphicContext(img draw.Image) *ImageGraphicContext { gc := new(ImageGraphicContext) - gc.PaintedImage = pi - width, height := gc.PaintedImage.Bounds().Dx(), gc.PaintedImage.Bounds().Dy() + gc.img = img + switch selectImage := img.(type) { + case *image.RGBA: + gc.painter = raster.NewRGBAPainter(selectImage) + case *image.NRGBA: + gc.painter = NewNRGBAPainter(selectImage) + default: + panic("Image type not supported") + } + + width, height := gc.img.Bounds().Dx(), gc.img.Bounds().Dy() gc.fillRasterizer = raster.NewRasterizer(width, height) gc.strokeRasterizer = raster.NewRasterizer(width, height) @@ -50,8 +65,8 @@ func NewImageGraphicContext(pi *image.RGBA) *ImageGraphicContext { gc.defaultFontData = FontData{"luxi", FontFamilySans, FontStyleNormal} gc.freetype = freetype.NewContext() gc.freetype.SetDPI(gc.DPI) - gc.freetype.SetClip(pi.Bounds()) - gc.freetype.SetDst(pi) + gc.freetype.SetClip(img.Bounds()) + gc.freetype.SetDst(img) gc.current = new(contextStack) @@ -94,13 +109,13 @@ func (gc *ImageGraphicContext) Scale(sx, sy float64) { } func (gc *ImageGraphicContext) Clear() { - width, height := gc.PaintedImage.Bounds().Dx(), gc.PaintedImage.Bounds().Dy() + width, height := gc.img.Bounds().Dx(), gc.img.Bounds().Dy() gc.ClearRect(0, 0, width, height) } func (gc *ImageGraphicContext) ClearRect(x1, y1, x2, y2 int) { imageColor := image.NewColorImage(gc.current.fillColor) - draw.Draw(gc.PaintedImage, image.Rect(x1, y1, x2, y2), imageColor, image.ZP) + draw.Draw(gc.img, image.Rect(x1, y1, x2, y2), imageColor, image.ZP) } func (gc *ImageGraphicContext) SetStrokeColor(c image.Color) { @@ -185,10 +200,8 @@ func (gc *ImageGraphicContext) Restore() { } func (gc *ImageGraphicContext) DrawImage(image image.Image) { - width := raster.Fix32(gc.PaintedImage.Bounds().Dx() * 256) - height := raster.Fix32(gc.PaintedImage.Bounds().Dy() * 256) - - painter := raster.NewRGBAPainter(gc.PaintedImage) + width := raster.Fix32(gc.img.Bounds().Dx() * 256) + height := raster.Fix32(gc.img.Bounds().Dy() * 256) p0 := raster.Point{0, 0} p1 := raster.Point{0, 0} @@ -209,8 +222,8 @@ func (gc *ImageGraphicContext) DrawImage(image image.Image) { gc.fillRasterizer.Add1(p2) gc.fillRasterizer.Add1(p3) gc.fillRasterizer.Add1(p0) - painter.SetColor(image.At(int(i>>8), int(j>>8))) - gc.fillRasterizer.Rasterize(painter) + gc.painter.SetColor(image.At(int(i>>8), int(j>>8))) + gc.fillRasterizer.Rasterize(gc.painter) gc.fillRasterizer.Clear() } } @@ -302,9 +315,8 @@ func (gc *ImageGraphicContext) FillString(text string) (cursor float64) { func (gc *ImageGraphicContext) paint(rasterizer *raster.Rasterizer, color image.Color) { - painter := raster.NewRGBAPainter(gc.PaintedImage) - painter.SetColor(color) - rasterizer.Rasterize(painter) + gc.painter.SetColor(color) + rasterizer.Rasterize(gc.painter) rasterizer.Clear() gc.current.path = new(PathStorage) } diff --git a/draw2d/paint.go b/draw2d/paint.go new file mode 100644 index 0000000..8a156a5 --- /dev/null +++ b/draw2d/paint.go @@ -0,0 +1,94 @@ +// Copyright 2010 The draw2d Authors. All rights reserved. +// created: 21/11/2010 by Laurent Le Goff +package draw2d + +import ( + "exp/draw" + "image" + "freetype-go.googlecode.com/hg/freetype/raster" +) + +const M = 1<<16 - 1 + +type NRGBAPainter struct { + // The image to compose onto. + Image *image.NRGBA + // The Porter-Duff composition operator. + Op draw.Op + // The 16-bit color to paint the spans. + cr, cg, cb, ca uint32 +} + +func min(a, b uint32) uint32 { + if a < b { + return a + } + return b +} + +// Paint satisfies the Painter interface by painting ss onto an image.RGBA. +func (r *NRGBAPainter) Paint(ss []raster.Span, done bool) { + b := r.Image.Bounds() + for _, s := range ss { + if s.Y < b.Min.Y { + continue + } + if s.Y >= b.Max.Y { + return + } + if s.X0 < b.Min.X { + s.X0 = b.Min.X + } + if s.X1 > b.Max.X { + s.X1 = b.Max.X + } + if s.X0 >= s.X1 { + continue + } + base := s.Y * r.Image.Stride + p := r.Image.Pix[base+s.X0 : base+s.X1] + // This code is duplicated from drawGlyphOver in $GOROOT/src/pkg/exp/draw/draw.go. + // TODO(nigeltao): Factor out common code into a utility function, once the compiler + // can inline such function calls. + ma := s.A >> 16 + if r.Op == draw.Over { + for i, nrgba := range p { + dr, dg, db, da := nrgba.RGBA() + a := M - (r.ca*ma)/M + da = (da*a + r.ca*ma) / M + if da != 0 { + dr = min(M, (dr*a+r.cr*ma)/da) + dg = min(M, (dg*a+r.cg*ma)/da) + db = min(M, (db*a+r.cb*ma)/da) + } else { + dr, dg, db = 0, 0, 0 + } + p[i] = image.NRGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)} + } + } else { + for i, nrgba := range p { + dr, dg, db, da := nrgba.RGBA() + a := M - ma + da = (da*a + r.ca*ma) / M + if da != 0 { + dr = min(M, (dr*a+r.cr*ma)/da) + dg = min(M, (dg*a+r.cg*ma)/da) + db = min(M, (db*a+r.cb*ma)/da) + } else { + dr, dg, db = 0, 0, 0 + } + p[i] = image.NRGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)} + } + } + } +} + +// SetColor sets the color to paint the spans. +func (r *NRGBAPainter) SetColor(c image.Color) { + r.cr, r.cg, r.cb, r.ca = c.RGBA() +} + +// NewRGBAPainter creates a new RGBAPainter for the given image. +func NewNRGBAPainter(m *image.NRGBA) *NRGBAPainter { + return &NRGBAPainter{Image: m} +}