tdewolff / canvas

Cairo in Go: vector to raster, SVG, PDF, EPS, WASM, OpenGL, Gio, etc.
MIT License
1.49k stars 102 forks source link

[question] Drawing parsed SVG file #293

Closed mangofeet closed 5 months ago

mangofeet commented 5 months ago

I am trying to load an SVG file and add it in, but I cannot seem to get it to work

Using canvas.ParseSVGPath does work, but it only works on the path instructions, not the full SVG file. This is fine when the SVG is a single path, but an SVG with multiple paths makes this more complicated

I can parse the file using canvas.ParseSVG, but then I get a *canvas.Canvas back, and I can't seem to get it to draw to my current drawing context (I tried .RenderTo and .RenderViewTo, but these don't seem to do anything, or I just don't know how to use them)

trashCost := mustLoadGameSVG("TRASH_COST bw") // calls `canvas.ParseSVG`, returns a *canvas.Canvas
trashCost.RenderViewTo(ctx, canvas.Identity) // does not seem to do anything, though I'm not sure how I would give it coordinates to render

This works, but it uses the ParseSVGPath method, which only works for single raw paths, not full SVG files

rt.WritePath(mustLoadGameAsset("TRASH_ABILITY").Scale(face.Size*0.0002, face.Size*0.0002).Transform(canvas.Identity.ReflectY().Translate(0, face.Size*-1)), textColor, canvas.FontMiddle)
tdewolff commented 5 months ago

You're on the right track! Perhaps try and draw the *canvas.Canvas it returns and see if it has any content at all. The SVG parsing is an ad-hoc solution and works only for simple SVGs. Check the canvas.Size() of the returned canvas object to see what its size it with respect to the target canvas you want to RenderTo. You probably need to use the RenderViewTo if dimensions are different, and use a scaling to accomplish that, eg. canvas.Identity.Scale(factor,factor).

mangofeet commented 5 months ago

Ya, looks like the size was 0x0 after parsing... I should be able to make due with the raw path parsing for now. Thanks for the reply

tdewolff commented 5 months ago

Could you try calling canvas.Fit(0.0) after parsing the SVG? This will resize the canvas to contain all content. Perhaps the canvas size is never set by the SVG parser, what does your <svg> tag look like?

mangofeet commented 5 months ago

same result

here is the SVG file in question

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 101859 101859" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;">
  <path d="M32761.5,38913.2l0,-5279.5l41114.4,0l0,5476.92l-5930.38,39928.8l-29069.1,0l-6114.92,-40126.2" style="fill:none;fill-rule:nonzero;stroke:#000;stroke-width:2500px;"/>
  <path d="M32761.5,33633.7c-855.554,-0 -1011.98,-189.584 -1044.45,-1044.44l0,-4420.5c0,-755.208 176.042,-1163.02 1163.02,-1163.02l4163.02,0l1911.29,-3033.33c485.762,-760.242 1272.92,-1154.17 2175.17,-1154.17l24092.9,0c1143.92,37.675 1595.31,227.258 2169.79,1067.01l2088.02,3077.43l3990.28,-0c1038.71,-0 1277.25,448.783 1277.25,1277.25l0,4251.75c0,704.167 -444.27,1125.7 -1148.09,1148.09l-40838.2,-6.079l0.02,-0Z" style="fill:none;fill-rule:nonzero;stroke:#000;stroke-width:2500px;stroke-linecap:square;"/>
  <path d="M34799.4,54931.7l-6786.08,-0" style="fill:none;fill-rule:nonzero;stroke:#000;stroke-width:2500px;stroke-linecap:square;"/>
  <path d="M34088,50199.6l-15832.2,0" style="fill:none;fill-rule:nonzero;stroke:#000;stroke-width:2500px;stroke-linecap:square;"/>
  <path d="M32761.5,41767.1l-11364.9,0" style="fill:none;fill-rule:nonzero;stroke:#000;stroke-width:2500px;stroke-linecap:square;"/>
</svg>
tdewolff commented 5 months ago

This is now fixed, please let me know how it goes. Be aware that when width or height are specified in percentage (as in your case), it uses the values from the viewBox attribute, which is 101859x101859 in your case. Be aware that if you write out a PNG file with 1 dot-per-mm it will take a lot of time just to compress the raster data as PNG. Use something like renderers.Write("out.png", c, canvas.DPMM(0.1)).

mangofeet commented 5 months ago

It works! Thanks for the quick update