use pdf native transforms

This commit is contained in:
Stani 2015-06-29 01:29:04 +02:00
parent 458c46b28c
commit b3bea4f206
3 changed files with 65 additions and 70 deletions

View file

@ -10,6 +10,7 @@ import (
"image/color" "image/color"
"image/png" "image/png"
"log" "log"
"math"
"os" "os"
"strconv" "strconv"
@ -79,18 +80,15 @@ func NewGraphicContext(pdf *gofpdf.Fpdf) *GraphicContext {
// DrawImage draws an image as PNG // DrawImage draws an image as PNG
// TODO: add type (tp) as parameter to argument list? // TODO: add type (tp) as parameter to argument list?
func (gc *GraphicContext) DrawImage(image image.Image) { func (gc *GraphicContext) DrawImage(image image.Image) {
// TODO: fix rotation gc.Current.Tr
name := strconv.Itoa(int(imageCount)) name := strconv.Itoa(int(imageCount))
tp := "PNG" // "JPG", "JPEG", "PNG" and "GIF" tp := "PNG" // "JPG", "JPEG", "PNG" and "GIF"
b := &bytes.Buffer{} b := &bytes.Buffer{}
png.Encode(b, image) png.Encode(b, image)
gc.pdf.RegisterImageReader(name, tp, b) gc.pdf.RegisterImageReader(name, tp, b)
bounds := image.Bounds() bounds := image.Bounds()
//x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Dx()), float64(bounds.Dy()) x0, y0 := float64(bounds.Min.X), float64(bounds.Min.Y)
x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Max.X), float64(bounds.Max.Y) w, h := float64(bounds.Dx()), float64(bounds.Dy())
tr := gc.Current.Tr gc.pdf.Image(name, x0, y0, w, h, false, tp, 0, "")
tr.TransformRectangle(&x0, &y0, &x1, &y1)
gc.pdf.Image(name, x0, y0, x1-x0, y1-y0, false, tp, 0, "")
} }
// Clear draws a white rectangle over the whole page // Clear draws a white rectangle over the whole page
@ -123,13 +121,9 @@ func (gc *GraphicContext) GetStringBounds(s string) (left, top, right, bottom fl
// CreateStringPath creates a path from the string s at x, y, and returns the string width. // CreateStringPath creates a path from the string s at x, y, and returns the string width.
func (gc *GraphicContext) CreateStringPath(text string, x, y float64) (cursor float64) { func (gc *GraphicContext) CreateStringPath(text string, x, y float64) (cursor float64) {
// TODO: fix rotation of gc.Current.Tr
_, _, w, h := gc.GetStringBounds(text) _, _, w, h := gc.GetStringBounds(text)
x1, y1 := x+w, y+h
tr := gc.Current.Tr
tr.TransformRectangle(&x, &y, &x1, &y1)
gc.pdf.MoveTo(x, y) gc.pdf.MoveTo(x, y)
gc.pdf.Cell(x1-x, y1-y, text) gc.pdf.Cell(w, h, text)
return w return w
} }
@ -175,8 +169,8 @@ var logger = log.New(os.Stdout, "", log.Lshortfile)
// draw fills and/or strokes paths // draw fills and/or strokes paths
func (gc *GraphicContext) draw(style string, paths ...*draw2d.PathStorage) { func (gc *GraphicContext) draw(style string, paths ...*draw2d.PathStorage) {
paths = append(paths, gc.Current.Path) paths = append(paths, gc.Current.Path)
pathConverter := NewPathConverter(NewVertexMatrixTransform(gc.Current.Tr, gc.pdf)) pathConverter := NewPathConverter(gc.pdf)
// pathConverter := NewPathConverter(NewVertexMatrixTransform(gc.Current.Tr,NewPathLogger(logger, gc.pdf))) // pathConverter := NewPathConverter(NewPathLogger(logger, gc.pdf))
pathConverter.Convert(paths...) pathConverter.Convert(paths...)
if gc.Current.FillRule.UseNonZeroWinding() { if gc.Current.FillRule.UseNonZeroWinding() {
style += "*" style += "*"
@ -245,3 +239,59 @@ func (gc *GraphicContext) SetLineCap(Cap draw2d.Cap) {
gc.StackGraphicContext.SetLineCap(Cap) gc.StackGraphicContext.SetLineCap(Cap)
gc.pdf.SetLineCapStyle(caps[Cap]) gc.pdf.SetLineCapStyle(caps[Cap])
} }
// Transformations
// Scale generally scales the following text, drawings and images.
// sx and sy are the scaling factors for width and height.
// This must be placed between gc.Save() and gc.Restore(), otherwise
// the pdf is invalid.
func (gc *GraphicContext) Scale(sx, sy float64) {
gc.StackGraphicContext.Scale(sx, sy)
gc.pdf.TransformScale(sx*100, sy*100, 0, 0)
}
// Rotate rotates the following text, drawings and images.
// Angle is specified in radians and measured clockwise from the
// 3 o'clock position.
// This must be placed between gc.Save() and gc.Restore(), otherwise
// the pdf is invalid.
func (gc *GraphicContext) Rotate(angle float64) {
gc.StackGraphicContext.Rotate(angle)
gc.pdf.TransformRotate(-angle*180/math.Pi, 0, 0)
}
// Translate moves the following text, drawings and images
// horizontally and vertically by the amounts specified by tx and ty.
// This must be placed between gc.Save() and gc.Restore(), otherwise
// the pdf is invalid.
func (gc *GraphicContext) Translate(tx, ty float64) {
gc.StackGraphicContext.Translate(tx, ty)
gc.pdf.TransformTranslate(tx, ty)
}
// Save saves the current context stack
// (transformation, font, color,...).
func (gc *GraphicContext) Save() {
gc.StackGraphicContext.Save()
gc.pdf.TransformBegin()
}
// Restore restores the current context stack
// (transformation, color,...). Restoring the font is not supported.
func (gc *GraphicContext) Restore() {
gc.pdf.TransformEnd()
gc.StackGraphicContext.Restore()
c := gc.Current
gc.SetFontSize(c.FontSize)
// gc.SetFontData(c.FontData) unsupported, causes bug (do not enable)
gc.SetLineWidth(c.LineWidth)
gc.SetStrokeColor(c.StrokeColor)
gc.SetFillColor(c.FillColor)
gc.SetFillRule(c.FillRule)
// gc.SetLineDash(c.Dash, c.DashOffset) // TODO
gc.SetLineCap(c.Cap)
// gc.SetLineJoin(c.Join) // TODO
// c.Path unsupported
// c.Font unsupported
}

View file

@ -37,10 +37,12 @@ func main() {
// Draw image to fit in the frame // Draw image to fit in the frame
// TODO Seems to have a transform bug here on draw image // TODO Seems to have a transform bug here on draw image
scale := math.Min((dw-margin*2)/sw, (dh-margin*2)/sh) scale := math.Min((dw-margin*2)/sw, (dh-margin*2)/sh)
gc.Save()
gc.Translate(margin, margin) gc.Translate(margin, margin)
gc.Scale(scale, scale) gc.Scale(scale, scale)
gc.DrawImage(source) gc.DrawImage(source)
gc.Restore()
// Save to pdf // Save to pdf
pdf2d.SaveToPdfFile("frame-image.pdf", dest) pdf2d.SaveToPdfFile("frame-image.pdf", dest)

View file

@ -1,57 +0,0 @@
// Copyright 2015 The draw2d Authors. All rights reserved.
// created: 26/06/2015 by Stani Michiels
package pdf2d
import "github.com/stanim/draw2d"
// VertexMatrixTransform implements Vectorizer and applies the Matrix
// transformation tr. It is normally wrapped around gofpdf Fpdf
// or PathLogger.
type VertexMatrixTransform struct {
tr draw2d.MatrixTransform
Next Vectorizer
}
// NewVertexMatrixTransform constructs an new VertexMatrixTransform
func NewVertexMatrixTransform(tr draw2d.MatrixTransform,
vectorizer Vectorizer) *VertexMatrixTransform {
return &VertexMatrixTransform{tr, vectorizer}
}
// MoveTo creates a new subpath that start at the specified point
func (vmt *VertexMatrixTransform) MoveTo(x, y float64) {
vmt.tr.Transform(&x, &y)
vmt.Next.MoveTo(x, y)
}
// LineTo adds a line to the current subpath
func (vmt *VertexMatrixTransform) LineTo(x, y float64) {
vmt.tr.Transform(&x, &y)
vmt.Next.LineTo(x, y)
}
// CurveTo adds a quadratic bezier curve to the current subpath
func (vmt *VertexMatrixTransform) CurveTo(cx, cy, x, y float64) {
vmt.tr.Transform(&cx, &cy, &x, &y)
vmt.Next.CurveTo(cx, cy, x, y)
}
// CurveBezierCubicTo adds a cubic bezier curve to the current subpath
func (vmt *VertexMatrixTransform) CurveBezierCubicTo(cx1, cy1,
cx2, cy2, x, y float64) {
vmt.tr.Transform(&cx1, &cy1, &cx2, &cy2, &x, &y)
vmt.Next.CurveBezierCubicTo(cx1, cy1, cx2, cy2, x, y)
}
// ArcTo adds an arc to the current subpath
func (vmt *VertexMatrixTransform) ArcTo(x, y, rx, ry, degRotate, degStart, degEnd float64) {
vmt.tr.Transform(&x, &y)
vmt.Next.ArcTo(x, y, rx, ry, degRotate, degStart, degEnd)
}
// ClosePath closes the subpath
func (vmt *VertexMatrixTransform) ClosePath() {
vmt.Next.ClosePath()
}