Merge pull request #16 from wsw0108/rotated-image-text
Draw image/text with current transformation appied
This commit is contained in:
commit
7fb6ce3c57
45
context.go
45
context.go
@ -4,14 +4,15 @@ package gg
|
|||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/draw"
|
|
||||||
"image/png"
|
"image/png"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/golang/freetype/raster"
|
"github.com/golang/freetype/raster"
|
||||||
|
"golang.org/x/image/draw"
|
||||||
"golang.org/x/image/font"
|
"golang.org/x/image/font"
|
||||||
"golang.org/x/image/font/basicfont"
|
"golang.org/x/image/font/basicfont"
|
||||||
|
"golang.org/x/image/math/f64"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LineCap int
|
type LineCap int
|
||||||
@ -564,7 +565,6 @@ func (dc *Context) DrawRegularPolygon(n int, x, y, r, rotation float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DrawImage draws the specified image at the specified point.
|
// DrawImage draws the specified image at the specified point.
|
||||||
// Currently, rotation and scaling transforms are not supported.
|
|
||||||
func (dc *Context) DrawImage(im image.Image, x, y int) {
|
func (dc *Context) DrawImage(im image.Image, x, y int) {
|
||||||
dc.DrawImageAnchored(im, x, y, 0, 0)
|
dc.DrawImageAnchored(im, x, y, 0, 0)
|
||||||
}
|
}
|
||||||
@ -576,12 +576,17 @@ func (dc *Context) DrawImageAnchored(im image.Image, x, y int, ax, ay float64) {
|
|||||||
s := im.Bounds().Size()
|
s := im.Bounds().Size()
|
||||||
x -= int(ax * float64(s.X))
|
x -= int(ax * float64(s.X))
|
||||||
y -= int(ay * float64(s.Y))
|
y -= int(ay * float64(s.Y))
|
||||||
p := image.Pt(x, y)
|
transformer := draw.BiLinear
|
||||||
r := image.Rectangle{p, p.Add(s)}
|
fx, fy := float64(x), float64(y)
|
||||||
|
m := dc.matrix.Translate(fx, fy)
|
||||||
|
s2d := f64.Aff3{m.XX, m.XY, m.X0, m.YX, m.YY, m.Y0}
|
||||||
if dc.mask == nil {
|
if dc.mask == nil {
|
||||||
draw.Draw(dc.im, r, im, image.ZP, draw.Over)
|
transformer.Transform(dc.im, s2d, im, im.Bounds(), draw.Over, nil)
|
||||||
} else {
|
} else {
|
||||||
draw.DrawMask(dc.im, r, im, image.ZP, dc.mask, p, draw.Over)
|
transformer.Transform(dc.im, s2d, im, im.Bounds(), draw.Over, &draw.Options{
|
||||||
|
DstMask: dc.mask,
|
||||||
|
DstMaskP: image.ZP,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,11 +613,34 @@ func (dc *Context) drawString(im *image.RGBA, s string, x, y float64) {
|
|||||||
Face: dc.fontFace,
|
Face: dc.fontFace,
|
||||||
Dot: fixp(x, y),
|
Dot: fixp(x, y),
|
||||||
}
|
}
|
||||||
d.DrawString(s)
|
// based on Drawer.DrawString() in golang.org/x/image/font/font.go
|
||||||
|
prevC := rune(-1)
|
||||||
|
for _, c := range s {
|
||||||
|
if prevC >= 0 {
|
||||||
|
d.Dot.X += d.Face.Kern(prevC, c)
|
||||||
|
}
|
||||||
|
dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
|
||||||
|
if !ok {
|
||||||
|
// TODO: is falling back on the U+FFFD glyph the responsibility of
|
||||||
|
// the Drawer or the Face?
|
||||||
|
// TODO: set prevC = '\ufffd'?
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sr := dr.Sub(dr.Min)
|
||||||
|
transformer := draw.BiLinear
|
||||||
|
fx, fy := float64(dr.Min.X), float64(dr.Min.Y)
|
||||||
|
m := dc.matrix.Translate(fx, fy)
|
||||||
|
s2d := f64.Aff3{m.XX, m.XY, m.X0, m.YX, m.YY, m.Y0}
|
||||||
|
transformer.Transform(d.Dst, s2d, d.Src, sr, draw.Over, &draw.Options{
|
||||||
|
SrcMask: mask,
|
||||||
|
SrcMaskP: maskp,
|
||||||
|
})
|
||||||
|
d.Dot.X += advance
|
||||||
|
prevC = c
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DrawString draws the specified text at the specified point.
|
// DrawString draws the specified text at the specified point.
|
||||||
// Currently, rotation and scaling transforms are not supported.
|
|
||||||
func (dc *Context) DrawString(s string, x, y float64) {
|
func (dc *Context) DrawString(s string, x, y float64) {
|
||||||
dc.DrawStringAnchored(s, x, y, 0, 0)
|
dc.DrawStringAnchored(s, x, y, 0, 0)
|
||||||
}
|
}
|
||||||
@ -622,7 +650,6 @@ func (dc *Context) DrawString(s string, x, y float64) {
|
|||||||
// text. Use ax=0.5, ay=0.5 to center the text at the specified point.
|
// text. Use ax=0.5, ay=0.5 to center the text at the specified point.
|
||||||
func (dc *Context) DrawStringAnchored(s string, x, y, ax, ay float64) {
|
func (dc *Context) DrawStringAnchored(s string, x, y, ax, ay float64) {
|
||||||
w, h := dc.MeasureString(s)
|
w, h := dc.MeasureString(s)
|
||||||
x, y = dc.TransformPoint(x, y)
|
|
||||||
x -= ax * w
|
x -= ax * w
|
||||||
y += ay * h
|
y += ay * h
|
||||||
if dc.mask == nil {
|
if dc.mask == nil {
|
||||||
|
34
examples/rotated-image.go
Normal file
34
examples/rotated-image.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/fogleman/gg"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const W = 400
|
||||||
|
const H = 500
|
||||||
|
im, err := gg.LoadPNG("examples/gopher.png")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
iw, ih := im.Bounds().Dx(), im.Bounds().Dy()
|
||||||
|
dc := gg.NewContext(W, H)
|
||||||
|
// draw outline
|
||||||
|
dc.SetHexColor("#ff0000")
|
||||||
|
dc.SetLineWidth(1)
|
||||||
|
dc.DrawRectangle(0, 0, float64(W), float64(H))
|
||||||
|
dc.Stroke()
|
||||||
|
// draw full image
|
||||||
|
dc.SetHexColor("#0000ff")
|
||||||
|
dc.SetLineWidth(2)
|
||||||
|
dc.DrawRectangle(100, 210, float64(iw), float64(ih))
|
||||||
|
dc.Stroke()
|
||||||
|
dc.DrawImage(im, 100, 210)
|
||||||
|
// draw image with current matrix applied
|
||||||
|
dc.SetHexColor("#0000ff")
|
||||||
|
dc.SetLineWidth(2)
|
||||||
|
dc.Rotate(gg.Radians(10))
|
||||||
|
dc.DrawRectangle(100, 0, float64(iw), float64(ih)/2+20.0)
|
||||||
|
dc.StrokePreserve()
|
||||||
|
dc.Clip()
|
||||||
|
dc.DrawImageAnchored(im, 100, 0, 0.0, 0.0)
|
||||||
|
dc.SavePNG("out.png")
|
||||||
|
}
|
30
examples/rotated-text.go
Normal file
30
examples/rotated-text.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fogleman/gg"
|
||||||
|
"github.com/golang/freetype/truetype"
|
||||||
|
"golang.org/x/image/font/gofont/goregular"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const S = 400
|
||||||
|
dc := gg.NewContext(S, S)
|
||||||
|
dc.SetRGB(1, 1, 1)
|
||||||
|
dc.Clear()
|
||||||
|
dc.SetRGB(0, 0, 0)
|
||||||
|
font, err := truetype.Parse(goregular.TTF)
|
||||||
|
if err != nil {
|
||||||
|
panic("")
|
||||||
|
}
|
||||||
|
face := truetype.NewFace(font, &truetype.Options{
|
||||||
|
Size: 40,
|
||||||
|
})
|
||||||
|
dc.SetFontFace(face)
|
||||||
|
text := "Hello, world!"
|
||||||
|
w, h := dc.MeasureString(text)
|
||||||
|
dc.Rotate(gg.Radians(10))
|
||||||
|
dc.DrawRectangle(100, 180, w, h)
|
||||||
|
dc.Stroke()
|
||||||
|
dc.DrawStringAnchored(text, 100, 180, 0.0, 0.0)
|
||||||
|
dc.SavePNG("out.png")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user