Compare commits

..

No commits in common. "main" and "v1.3.0" have entirely different histories.
main ... v1.3.0

8 changed files with 7 additions and 125 deletions

View File

@ -14,8 +14,7 @@ Alternatively, you may use gopkg.in to grab a specific major-version:
## Documentation ## Documentation
- godoc: https://godoc.org/github.com/fogleman/gg https://godoc.org/github.com/fogleman/gg
- pkg.go.dev: https://pkg.go.dev/github.com/fogleman/gg?tab=doc
## Hello, Circle! ## Hello, Circle!
@ -128,7 +127,7 @@ SetFillRule(fillRule FillRule)
## Gradients & Patterns ## Gradients & Patterns
`gg` supports linear, radial and conic gradients and surface patterns. You can also implement your own patterns. `gg` supports linear and radial gradients and surface patterns. You can also implement your own patterns.
```go ```go
SetFillStyle(pattern Pattern) SetFillStyle(pattern Pattern)
@ -136,7 +135,6 @@ SetStrokeStyle(pattern Pattern)
NewSolidPattern(color color.Color) NewSolidPattern(color color.Color)
NewLinearGradient(x0, y0, x1, y1 float64) NewLinearGradient(x0, y0, x1, y1 float64)
NewRadialGradient(x0, y0, r0, x1, y1, r1 float64) NewRadialGradient(x0, y0, r0, x1, y1, r1 float64)
NewConicGradient(cx, cy, deg float64)
NewSurfacePattern(im image.Image, op RepeatOp) NewSurfacePattern(im image.Image, op RepeatOp)
``` ```

View File

@ -5,7 +5,6 @@ import (
"errors" "errors"
"image" "image"
"image/color" "image/color"
"image/jpeg"
"image/png" "image/png"
"io" "io"
"math" "math"
@ -141,23 +140,11 @@ func (dc *Context) SavePNG(path string) error {
return SavePNG(path, dc.im) return SavePNG(path, dc.im)
} }
// SaveJPG encodes the image as a JPG and writes it to disk.
func (dc *Context) SaveJPG(path string, quality int) error {
return SaveJPG(path, dc.im, quality)
}
// EncodePNG encodes the image as a PNG and writes it to the provided io.Writer. // EncodePNG encodes the image as a PNG and writes it to the provided io.Writer.
func (dc *Context) EncodePNG(w io.Writer) error { func (dc *Context) EncodePNG(w io.Writer) error {
return png.Encode(w, dc.im) return png.Encode(w, dc.im)
} }
// EncodeJPG encodes the image as a JPG and writes it to the provided io.Writer
// in JPEG 4:2:0 baseline format with the given options.
// Default parameters are used if a nil *jpeg.Options is passed.
func (dc *Context) EncodeJPG(w io.Writer, o *jpeg.Options) error {
return jpeg.Encode(w, dc.im, o)
}
// SetDash sets the current dash pattern to use. Call with zero arguments to // SetDash sets the current dash pattern to use. Call with zero arguments to
// disable dashes. The values specify the lengths of each dash, with // disable dashes. The values specify the lengths of each dash, with
// alternating on and off lengths. // alternating on and off lengths.
@ -418,7 +405,6 @@ func (dc *Context) stroke(painter raster.Painter) {
r := dc.rasterizer r := dc.rasterizer
r.UseNonZeroWinding = true r.UseNonZeroWinding = true
r.Clear() r.Clear()
r.Dx, r.Dy = dc.im.Bounds().Min.X, dc.im.Bounds().Min.Y
r.AddStroke(path, fix(dc.lineWidth), dc.capper(), dc.joiner()) r.AddStroke(path, fix(dc.lineWidth), dc.capper(), dc.joiner())
r.Rasterize(painter) r.Rasterize(painter)
} }
@ -433,7 +419,6 @@ func (dc *Context) fill(painter raster.Painter) {
r := dc.rasterizer r := dc.rasterizer
r.UseNonZeroWinding = dc.fillRule == FillRuleWinding r.UseNonZeroWinding = dc.fillRule == FillRuleWinding
r.Clear() r.Clear()
r.Dx, r.Dy = dc.im.Bounds().Min.X, dc.im.Bounds().Min.Y
r.AddPath(path) r.AddPath(path)
r.Rasterize(painter) r.Rasterize(painter)
} }
@ -756,7 +741,7 @@ func (dc *Context) DrawStringAnchored(s string, x, y, ax, ay float64) {
x -= ax * w x -= ax * w
y += ay * h y += ay * h
if dc.mask == nil { if dc.mask == nil {
dc.drawString(dc.im, s, x+float64(dc.im.Bounds().Min.X), y+float64(dc.im.Bounds().Min.Y)) dc.drawString(dc.im, s, x, y)
} else { } else {
im := image.NewRGBA(image.Rect(0, 0, dc.width, dc.height)) im := image.NewRGBA(image.Rect(0, 0, dc.width, dc.height))
dc.drawString(im, s, x, y) dc.drawString(im, s, x, y)
@ -859,13 +844,13 @@ func (dc *Context) ScaleAbout(sx, sy, x, y float64) {
dc.Translate(-x, -y) dc.Translate(-x, -y)
} }
// Rotate updates the current matrix with a anticlockwise rotation. // Rotate updates the current matrix with a clockwise rotation.
// Rotation occurs about the origin. Angle is specified in radians. // Rotation occurs about the origin. Angle is specified in radians.
func (dc *Context) Rotate(angle float64) { func (dc *Context) Rotate(angle float64) {
dc.matrix = dc.matrix.Rotate(angle) dc.matrix = dc.matrix.Rotate(angle)
} }
// RotateAbout updates the current matrix with a anticlockwise rotation. // RotateAbout updates the current matrix with a clockwise rotation.
// Rotation occurs about the specified point. Angle is specified in radians. // Rotation occurs about the specified point. Angle is specified in radians.
func (dc *Context) RotateAbout(angle, x, y float64) { func (dc *Context) RotateAbout(angle, x, y float64) {
dc.Translate(x, y) dc.Translate(x, y)

View File

@ -191,7 +191,7 @@ func TestPushPop(t *testing.T) {
dc.Pop() dc.Pop()
} }
saveImage(dc, "TestPushPop") saveImage(dc, "TestPushPop")
checkHash(t, dc, "31e908ee1c2ea180da98fd5681a89d05") checkHash(t, dc, "e0d6724eb72033577811a55f7a642f6a")
} }
func TestDrawStringWrapped(t *testing.T) { func TestDrawStringWrapped(t *testing.T) {

View File

@ -1,38 +0,0 @@
// +build ignore
package main
import (
"image/color"
"github.com/fogleman/gg"
)
func main() {
dc := gg.NewContext(400, 400)
grad1 := gg.NewConicGradient(200, 200, 0)
grad1.AddColorStop(0.0, color.Black)
grad1.AddColorStop(0.5, color.RGBA{255, 215, 0, 255})
grad1.AddColorStop(1.0, color.RGBA{255, 0, 0, 255})
grad2 := gg.NewConicGradient(200, 200, 90)
grad2.AddColorStop(0.00, color.RGBA{255, 0, 0, 255})
grad2.AddColorStop(0.16, color.RGBA{255, 255, 0, 255})
grad2.AddColorStop(0.33, color.RGBA{0, 255, 0, 255})
grad2.AddColorStop(0.50, color.RGBA{0, 255, 255, 255})
grad2.AddColorStop(0.66, color.RGBA{0, 0, 255, 255})
grad2.AddColorStop(0.83, color.RGBA{255, 0, 255, 255})
grad2.AddColorStop(1.00, color.RGBA{255, 0, 0, 255})
dc.SetStrokeStyle(grad1)
dc.SetLineWidth(20)
dc.DrawCircle(200, 200, 180)
dc.Stroke()
dc.SetFillStyle(grad2)
dc.DrawCircle(200, 200, 150)
dc.Fill()
dc.SavePNG("gradient-conic.png")
}

9
go.mod
View File

@ -1,9 +0,0 @@
module git.milar.in/milarin/gg
go 1.18
require (
github.com/fogleman/gg v1.3.0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
)

8
go.sum
View File

@ -1,8 +0,0 @@
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 h1:LRtI4W37N+KFebI/qV0OFiLUv4GLOWeEW5hn/KEJvxE=
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -164,52 +164,6 @@ func NewRadialGradient(x0, y0, r0, x1, y1, r1 float64) Gradient {
return g return g
} }
// Conic Gradient
type conicGradient struct {
cx, cy float64
rotation float64
stops stops
}
func (g *conicGradient) ColorAt(x, y int) color.Color {
if len(g.stops) == 0 {
return color.Transparent
}
a := math.Atan2(float64(y)-g.cy, float64(x)-g.cx)
t := norm(a, -math.Pi, math.Pi) - g.rotation
if t < 0 {
t += 1
}
return getColor(t, g.stops)
}
func (g *conicGradient) AddColorStop(offset float64, color color.Color) {
g.stops = append(g.stops, stop{pos: offset, color: color})
sort.Sort(g.stops)
}
func NewConicGradient(cx, cy, deg float64) Gradient {
g := &conicGradient{
cx: cx,
cy: cy,
rotation: normalizeAngle(deg) / 360,
}
return g
}
func normalizeAngle(t float64) float64 {
t = math.Mod(t, 360)
if t < 0 {
t += 360
}
return t
}
// Map value which is in range [a..b] to range [0..1]
func norm(value, a, b float64) float64 {
return (value - a) * (1.0 / (b - a))
}
func getColor(pos float64, stops stops) color.Color { func getColor(pos float64, stops stops) color.Color {
if pos <= 0.0 || len(stops) == 1 { if pos <= 0.0 || len(stops) == 1 {
return stops[0].color return stops[0].color

View File

@ -109,7 +109,7 @@ func fixp(x, y float64) fixed.Point26_6 {
} }
func fix(x float64) fixed.Int26_6 { func fix(x float64) fixed.Int26_6 {
return fixed.Int26_6(math.Round(x * 64)) return fixed.Int26_6(x * 64)
} }
func unfix(x fixed.Int26_6) float64 { func unfix(x fixed.Int26_6) float64 {