Reputation: 220
I'm currently using draw2d lib to render some image. I noticed the core algorithm and method are the same for building SVG, or PNG images.
I do need to render this images as SVG (for web use) and PNG (for PDF use)
The only difference is at the entry type and output.
for PNG rendering I've
as input:
var gc *draw2dimg.GraphicContext
var img *image.RGBA
img = image.NewRGBA(image.Rect(0, 0, xSize, ySize))
gc = draw2dimg.NewGraphicContext(img)
as output:
draw2dimg.SaveToPngFile(FileName, img)
and for SVG I've:
as input:
var gc *draw2dsvg.GraphicContext
var img *draw2dsvg.Svg
img = draw2dsvg.NewSvg()
gc = draw2dsvg.NewGraphicContext(img)
as output:
draw2dsvg.SaveToSvgFile(FileName, img)
between input and output I've the same implementation.
Is there any way in Go to use different input type and get the same implementation without have to duplicate some code?
Upvotes: 0
Views: 155
Reputation: 6454
As I mentioned in the comment, try to refactor your code by moving the core algorithm part into a function or may be to a different package. To illustrate the idea, bellow is the refactored version of example in https://github.com/llgcode/draw2d README.
package main
import (
"image"
"image/color"
"github.com/llgcode/draw2d"
"github.com/llgcode/draw2d/draw2dimg"
"github.com/llgcode/draw2d/draw2dpdf"
"github.com/llgcode/draw2d/draw2dsvg"
)
func coreDraw(gc draw2d.GraphicContext) {
// Set some properties
gc.SetFillColor(color.RGBA{0x44, 0xff, 0x44, 0xff})
gc.SetStrokeColor(color.RGBA{0x44, 0x44, 0x44, 0xff})
gc.SetLineWidth(5)
// Draw a closed shape
gc.BeginPath() // Initialize a new path
gc.MoveTo(10, 10) // Move to a position to start the new path
gc.LineTo(100, 50)
gc.QuadCurveTo(100, 10, 10, 10)
gc.Close()
gc.FillStroke()
}
func main() {
format := "svg"
switch format {
case "png":
dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0))
gc := draw2dimg.NewGraphicContext(dest)
coreDraw(gc)
draw2dimg.SaveToPngFile("hello.png", dest)
case "pdf":
dest := draw2dpdf.NewPdf("L", "mm", "A4")
gc := draw2dpdf.NewGraphicContext(dest)
coreDraw(gc)
draw2dpdf.SaveToPdfFile("hello.pdf", dest)
case "svg":
img := draw2dsvg.NewSvg()
gc := draw2dsvg.NewGraphicContext(img)
coreDraw(gc)
draw2dsvg.SaveToSvgFile("hello.svg", img)
}
}
Upvotes: 1
Reputation: 11033
The typical way to achieve code sharing in Go would be through the use of interfaces. See if you can break down the steps of your image algorithm into interface methods. Then those methods can be driven in a generic way by a single piece of code that works across all image formats, as in the runAlgorithm
function below.
package main
import (
"image"
"github.com/llgcode/draw2d/draw2dimg"
"github.com/llgcode/draw2d/draw2dsvg"
)
// Common algorithm that is implemented for various image formats.
type ImageAlgorithm interface {
CreateImage(xSize, ySize int)
CreateGraphicsContext()
SaveImage(fileName string)
}
type RGBAAlgorithm struct {
gc *draw2dimg.GraphicContext
img *image.RGBA
}
func (alg *RGBAAlgorithm) CreateImage(xSize, ySize int) {
alg.img = image.NewRGBA(image.Rect(0, 0, xSize, ySize))
}
func (alg *RGBAAlgorithm) CreateGraphicsContext() {
alg.gc = draw2dimg.NewGraphicContext(alg.img)
}
func (alg *RGBAAlgorithm) SaveImage(fileName string) {
draw2dimg.SaveToPngFile(fileName, alg.img)
}
type SvgAlgorithm struct {
gc *draw2dsvg.GraphicContext
img *draw2dsvg.Svg
}
func (alg *SvgAlgorithm) CreateImage(xSize, ySize int) {
alg.img = draw2dsvg.NewSvg()
}
func (alg *SvgAlgorithm) CreateGraphicsContext() {
alg.gc = draw2dsvg.NewGraphicContext(alg.img)
}
func (alg *SvgAlgorithm) SaveImage(fileName string) {
draw2dsvg.SaveToSvgFile(fileName, alg.img)
}
func runAlgorithm(alg ImageAlgorithm) {
// input
alg.CreateImage(100, 100)
alg.CreateGraphicsContext()
// output
alg.SaveImage("out")
}
func main() {
runAlgorithm(&RGBAAlgorithm{})
runAlgorithm(&SvgAlgorithm{})
}
Upvotes: 0