From b3bea4f206e01a8106d7dfbf9bb4b11f5c66d26d Mon Sep 17 00:00:00 2001 From: Stani Date: Mon, 29 Jun 2015 01:29:04 +0200 Subject: [PATCH] use pdf native transforms --- pdf2d/graphiccontext.go | 76 ++++++++++++++++++++---- pdf2d/samples/frame-image/frame-image.go | 2 + pdf2d/transform.go | 57 ------------------ 3 files changed, 65 insertions(+), 70 deletions(-) delete mode 100644 pdf2d/transform.go diff --git a/pdf2d/graphiccontext.go b/pdf2d/graphiccontext.go index 8a6777a..d4848b4 100644 --- a/pdf2d/graphiccontext.go +++ b/pdf2d/graphiccontext.go @@ -10,6 +10,7 @@ import ( "image/color" "image/png" "log" + "math" "os" "strconv" @@ -79,18 +80,15 @@ func NewGraphicContext(pdf *gofpdf.Fpdf) *GraphicContext { // DrawImage draws an image as PNG // TODO: add type (tp) as parameter to argument list? func (gc *GraphicContext) DrawImage(image image.Image) { - // TODO: fix rotation gc.Current.Tr name := strconv.Itoa(int(imageCount)) tp := "PNG" // "JPG", "JPEG", "PNG" and "GIF" b := &bytes.Buffer{} png.Encode(b, image) gc.pdf.RegisterImageReader(name, tp, b) bounds := image.Bounds() - //x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Dx()), float64(bounds.Dy()) - x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Max.X), float64(bounds.Max.Y) - tr := gc.Current.Tr - tr.TransformRectangle(&x0, &y0, &x1, &y1) - gc.pdf.Image(name, x0, y0, x1-x0, y1-y0, false, tp, 0, "") + x0, y0 := float64(bounds.Min.X), float64(bounds.Min.Y) + w, h := float64(bounds.Dx()), float64(bounds.Dy()) + gc.pdf.Image(name, x0, y0, w, h, false, tp, 0, "") } // 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. func (gc *GraphicContext) CreateStringPath(text string, x, y float64) (cursor float64) { - // TODO: fix rotation of gc.Current.Tr _, _, 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.Cell(x1-x, y1-y, text) + gc.pdf.Cell(w, h, text) return w } @@ -175,8 +169,8 @@ var logger = log.New(os.Stdout, "", log.Lshortfile) // draw fills and/or strokes paths func (gc *GraphicContext) draw(style string, paths ...*draw2d.PathStorage) { paths = append(paths, gc.Current.Path) - pathConverter := NewPathConverter(NewVertexMatrixTransform(gc.Current.Tr, gc.pdf)) - // pathConverter := NewPathConverter(NewVertexMatrixTransform(gc.Current.Tr,NewPathLogger(logger, gc.pdf))) + pathConverter := NewPathConverter(gc.pdf) + // pathConverter := NewPathConverter(NewPathLogger(logger, gc.pdf)) pathConverter.Convert(paths...) if gc.Current.FillRule.UseNonZeroWinding() { style += "*" @@ -245,3 +239,59 @@ func (gc *GraphicContext) SetLineCap(Cap draw2d.Cap) { gc.StackGraphicContext.SetLineCap(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 +} diff --git a/pdf2d/samples/frame-image/frame-image.go b/pdf2d/samples/frame-image/frame-image.go index 9234e04..728a88a 100644 --- a/pdf2d/samples/frame-image/frame-image.go +++ b/pdf2d/samples/frame-image/frame-image.go @@ -37,10 +37,12 @@ func main() { // Draw image to fit in the frame // TODO Seems to have a transform bug here on draw image scale := math.Min((dw-margin*2)/sw, (dh-margin*2)/sh) + gc.Save() gc.Translate(margin, margin) gc.Scale(scale, scale) gc.DrawImage(source) + gc.Restore() // Save to pdf pdf2d.SaveToPdfFile("frame-image.pdf", dest) diff --git a/pdf2d/transform.go b/pdf2d/transform.go deleted file mode 100644 index 6461aa6..0000000 --- a/pdf2d/transform.go +++ /dev/null @@ -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() -}