Flipping the Y axis doesn't work with "draw2dpdf.GraphicContext"
I've written an helper function to flip the image around the Y axis as in below:
// Flips the image around the Y axis.
func invertY(gc draw2d.GraphicContext, height int) {
gc.Translate(0, float64(height))
gc.Scale(1, -1)
}
It works just fine with the "draw2dimg.GraphicContext", but silently fails if the current graphic context is in "draw2dpdf.GraphicContext". The "gofpdf" package seems to provide image transformation functions such as:
func (f *Fpdf) Transform(tm TransformMatrix)
func (f *Fpdf) TransformBegin()
func (f *Fpdf) TransformEnd()
func (f *Fpdf) TransformMirrorHorizontal(x float64)
func (f *Fpdf) TransformMirrorLine(angle, x, y float64)
func (f *Fpdf) TransformMirrorPoint(x, y float64)
func (f *Fpdf) TransformMirrorVertical(y float64)
func (f *Fpdf) TransformRotate(angle, x, y float64)
func (f *Fpdf) TransformScale(scaleWd, scaleHt, x, y float64)
func (f *Fpdf) TransformScaleX(scaleWd, x, y float64)
func (f *Fpdf) TransformScaleXY(s, x, y float64)
func (f *Fpdf) TransformScaleY(scaleHt, x, y float64)
func (f *Fpdf) TransformSkew(angleX, angleY, x, y float64)
func (f *Fpdf) TransformSkewX(angleX, x, y float64)
func (f *Fpdf) TransformSkewY(angleY, x, y float64)
func (f *Fpdf) TransformTranslate(tx, ty float64)
func (f *Fpdf) TransformTranslateX(tx float64)
func (f *Fpdf) TransformTranslateY(ty float64)
So, is it possible to add some basic functionality to "draw2dpdf.GraphicContext", so that we can make use of these image transformation capabilities ? Thanks.
Hi @korayeyinc , Can you provide a code that reproduces the problem please? @stanim what do you think about this bug?
draw2dpdf already uses TransformTranslate and TransformScale in implementation of gc.Translate and gc.Scale. regards
Hi @llgcode ,
Sure, the code below builds successfully using go version "go1.9.2" on a "linux/amd64" box -- i'm sorry about the formatting though, the code tag seems to unindent the code:
package main
import (
"image"
"image/color"
"github.com/llgcode/draw2d"
"github.com/llgcode/draw2d/draw2dimg"
"github.com/llgcode/draw2d/draw2dpdf"
)
var black = color.RGBA{0, 0, 0, 255}
// Flips the image around the Y axis.
func invertY(gc draw2d.GraphicContext, height int) {
gc.Translate(0, float64(height))
gc.Scale(1, -1)
}
func check(err error) {
if err != nil {
panic(err)
}
}
// Generates PDF output.
func genPDF() {
height := 600
dst := draw2dpdf.NewPdf("L", "mm", "A4")
gc := draw2dpdf.NewGraphicContext(dst)
gc.SetStrokeColor(black)
gc.SetLineWidth(2)
gc.MoveTo(10, 10)
gc.LineTo(100, 100)
gc.QuadCurveTo(100, 10, 10, 10)
gc.Close()
invertY(gc, height)
gc.Stroke()
filename := "sample.pdf"
err := draw2dpdf.SaveToPdfFile(filename, dst)
check(err)
}
// Generates PNG output.
func genPNG() {
width, height := 800, 600
dst := image.NewRGBA(image.Rect(0, 0, width, height))
gc := draw2dimg.NewGraphicContext(dst)
gc.SetStrokeColor(black)
gc.SetLineWidth(2)
gc.MoveTo(10, 10)
gc.LineTo(100, 100)
gc.QuadCurveTo(100, 10, 10, 10)
gc.Close()
invertY(gc, height)
gc.Stroke()
filename := "sample.png"
err := draw2dimg.SaveToPngFile(filename, dst)
check(err)
}
func main() {
genPNG()
genPDF()
}
By the way, it generates PNG output successfully but throws the error "panic: transformation context is not active" during PDF generation. Thanks.
Thansk @korayeyinc , I think the problem is drawimg apply the transformation also on the path that is not already stroke or fill unlike drawpdf. Apply the transformation before creating the path (before gc.MoveTo), transformation have to be set before creating a path.
Just for tips: You can use the code blocks for code. I used the playground for guickly formatting.
package main
import (
"image"
"image/color"
"github.com/llgcode/draw2d"
"github.com/llgcode/draw2d/draw2dimg"
"github.com/llgcode/draw2d/draw2dpdf"
)
var black = color.RGBA{0, 0, 0, 255}
// Flips the image around the Y axis.
func invertY(gc draw2d.GraphicContext, height int) {
gc.Translate(0, float64(height))
gc.Scale(1, -1)
}
func check(err error) {
if err != nil {
panic(err)
}
}
// Generates PDF output.
func genPDF() {
height := 600
dst := draw2dpdf.NewPdf("L", "mm", "A4")
gc := draw2dpdf.NewGraphicContext(dst)
gc.SetStrokeColor(black)
gc.SetLineWidth(2)
gc.MoveTo(10, 10)
gc.LineTo(100, 100)
gc.QuadCurveTo(100, 10, 10, 10)
gc.Close()
invertY(gc, height)
gc.Stroke()
filename := "sample.pdf"
err := draw2dpdf.SaveToPdfFile(filename, dst)
check(err)
}
// Generates PNG output.
func genPNG() {
width, height := 800, 600
dst := image.NewRGBA(image.Rect(0, 0, width, height))
gc := draw2dimg.NewGraphicContext(dst)
gc.SetStrokeColor(black)
gc.SetLineWidth(2)
gc.MoveTo(10, 10)
gc.LineTo(100, 100)
gc.QuadCurveTo(100, 10, 10, 10)
gc.Close()
invertY(gc, height)
gc.Stroke()
filename := "sample.png"
err := draw2dimg.SaveToPngFile(filename, dst)
check(err)
}
func main() {
genPNG()
genPDF()
}
regards
Thanks for the tips. This is taken from the gofpdf package documentation:
go doc gofpdf.TransformBegin
func (f *Fpdf) TransformBegin()
TransformBegin sets up a transformation context for subsequent text,
drawings and images. The typical usage is to immediately follow a call to
this method with a call to one or more of the transformation methods such as
TransformScale(), TransformSkew(), etc. This is followed by text, drawing or
image output and finally a call to TransformEnd(). All transformation
contexts must be properly ended prior to outputting the document.
So, i applied the TransformBegin() and TransformEnd() functions as told in the the documentation and it works:
// Generates PDF output.
func genPDF() {
height := 600
dst := draw2dpdf.NewPdf("L", "mm", "A4")
gc := draw2dpdf.NewGraphicContext(dst)
dst.TransformBegin()
invertY(gc, height)
gc.SetStrokeColor(black)
gc.SetLineWidth(2)
gc.MoveTo(10, 10)
gc.LineTo(100, 100)
gc.QuadCurveTo(100, 10, 10, 10)
gc.Close()
dst.TransformEnd()
gc.Stroke()
filename := "sample.pdf"
err := draw2dpdf.SaveToPdfFile(filename, dst)
check(err)
}
I believe it would be more straightforward if both TransformBegin() and TransformEnd() functions were accessible via gc -- *draw2dpdf.GraphicContext. Also, i should note that it's necessary to apply dst.TransformEnd() function just before gc.Stroke(). Thanks for pointing me in the right direction.