I need to convert svg to png at the command-line. I tried using imagemagick but it seems to have a bug when used with rotate transforms, e.g. this sample s3.svg:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg">
<g id="layer1">
<circle cx="200" cy="200" r="200" stroke="black"
stroke-width="0.5" fill="none"/>
<g transform="rotate(48 200 200)">
<path id="path00" style="fill:#dca08c;stroke:#000000;stroke-width:1"
d="M 200,0 L 400,200 L 200,400 L 0,200 z"/>
</g>
</g>
</svg>
I was able to use inkscape at the command-line:
c:\app\inkscape\portable\App\Inkscape\inkscape.com -f s3.svg -e s3.png --export-background=white --export-area=0:652:400:1052
but SVG coordinates (0,0) are defined at the upper left whereas in inkscape's export the export area is (0,0) defined at the lower left.
How can I use inkscape to export without the magic number 1052 that defines the page height?
One way that might help is to draw an area you want as a container, give it an id, and export that with the -i id option. Give the wrapper blank background/border if it shouldn't be visible.
Edit (adding example):
I used this xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg">
<g id="layer1">
<rect width="400" height="600" id="wrapper" fill="none"></rect>
<circle cx="200" cy="200" r="200" stroke="black"
stroke-width="0.5" fill="none"/>
<g transform="rotate(48 200 200)">
<path id="path00" style="fill:#dca08c;stroke:#000000;stroke-width:1"
d="M 200,0 L 400,200 L 200,400 L 0,200 z"/>
</g>
</g>
</svg>
And with this command (I'm on a mac, so translate specific OS as needed) I could control the size/position of the output png:
/Applications/Inkscape.app/Contents/Resources/bin/inkscape -f test.svg -e out.png -i wrapper
I'm not an svg expert so I'm not sure if there are some specific things inkscape does, but I've always found it very web compliant. In the past I've used its svg files directly in web pages.
It seems what you are trying to export is the whole drawing.
inkscape has the option to export the drawing with --export-area-drawing instead of specifying the area to export.
c:\app\inkscape\portable\App\Inkscape\inkscape.com -f s3.svg -e s3.png --export-background=white --export-area-drawing
If the problem is not knowing the page height then the following syntax might help?
c:\app\inkscape\portable\App\Inkscape\inkscape.com s3.svg -z --query-height
This should return the pixel height of the document, you can use the returned number in your export call.
Inkscape has canvas size option, I had the same problem exporting for the web - your image drops out of the viewport.
Change canvas/artboard size to meet the size of element you are exporting
Related
I'm new to the svg library (HTML5 svg tag and related) and trying to learn. I'm working on a little diagram editor in VueJS using svg. I know how to create a rectangle and even a path from one rectangle/circle/etc to another, but I'm not unclear how to approach creating a path that starts and ends at the same rectangle (i.e., a loop) - something like this
I don't care that much where the start and end points intersect the rectangle, though I'd prefer they were relatively close to one another or at least on the same edge of the rectangle.
Thanks for any nudges in the right direction.
Just create a <path> that consists of a bezier curve whose control points form a rectangle.
<svg viewBox="0 0 100 100">
<rect x="50" y="10" width="50" height="40" fill="#4472c4"/>
<path d="M 50,20 C 10,20 10,40, 50,40" fill="none" stroke="red"/>
<!-- Show grey lines to indicate the bezier control points -->
<line x1="50" y1="20" x2="10" y2="20" fill="none" stroke="lightgrey" stroke-width="0.5"/>
<line x1="50" y1="40" x2="10" y2="40" fill="none" stroke="lightgrey" stroke-width="0.5"/>
</svg>
I created an SVG image as defined by the code below. The issue I am having is that the SVG image is being rendered incorrectly. The z-order of the elements in my SVG are incorrectly being rendered.
Issue: There are 3x rectangles (color = white), which are above another rectangle (color=red). These 3x rectangles are positioned to have the same y-axis as the red rectangle behind it and have the same height. Despite this positioning/height, there is a "red" border that seems to be visible on the edge of the white rectangle due to the red rectangle in the back. It seems that z-order or stacking order of the elements in the rendered image is not being respected.
Below is a screenshot of the SVG image open in the Inkscape showing the issue. Even after converting the SVG image to PNG, the z-order issue still existing.
After troubleshooting with the position, I noticed the issue randomly disappears depending on the value of the y-axis position, or SVG image size (pixels/width/height). For example, if you change edit the SVG from y="2.5807" to y="2.5", the issue goes however. However, this is a NOT a feasible solution for my issue, but the exact positing and SVG image size properties is are fixed can shouldn't be changed.
Updates
I tried #Robert Longson suggestion of using shape-rendering="crispEdges" on the root SVG. It did NOT solve the issue for my use case. Using his suggestion, it does solve the issue on how the image is rendered in a browser, however the issue is still visible in Inkscape or when SVG is converted to PNG. For my use case, I care about how the SVG is rendered after being converted to PNG.
I just found out shape-rendering="crispEdges does work when SVG is converted to PNG, but its dependent on how the conversion process works. If I use rsvg-convert command in Bash, which is provided by librsvg2-bin, to convert the SVG to PNG, the issue is fixed. However, if I use convert command in Bash, which is provided by ImageMagick, the issue still exist. If open the SVG file in Inkscape and then Export as PNG, then the issue still exist.
<svg baseProfile="full" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink" width="912px" height="1140px" preserveAspectRatio="none" viewBox="0,0,8.0,5.0">
<rect x="0" y="0" width="8.0" height="5.0" fill="white" />
<rect x="0" y="2.5807" width="8.0" height="1.0" fill="red" />
<g transform="translate(2.9275,0)">
<rect x="0" y="2.5807" width="0.5" height="1.0" fill="white" />
<rect x="1.0" y="2.5807" width="1.0" height="1.0" fill="white" />
<rect x="2.5" y="2.5807" width="1.5" height="1.0" fill="white" />
</g>
</svg>
that's antialiasing you can turn it off with shape-rendering="crispEdges"
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="912px" height="1140px" preserveAspectRatio="none" viewBox="0,0,8.0,5.0" shape-rendering="crispEdges">
<rect x="0" y="0" width="8.0" height="5.0" fill="white" />
<rect x="0" y="2.5807" width="8.0" height="1.0" fill="red" />
<g transform="translate(2.9275,0)">
<rect x="0" y="2.5807" width="0.5" height="1.0" fill="white" />
<rect x="1.0" y="2.5807" width="1.0" height="1.0" fill="white" />
<rect x="2.5" y="2.5807" width="1.5" height="1.0" fill="white" />
</g>
</svg>
The client asked to scale the drawing down so I added width/height and viewBox to the SVG element. The problem is that some elements are scaled differently than others. The structure of the svg is like this:
<svg width="100%" height="100%" viewBox="0 50 700 200">
<defs>...</defs>
<g id="group-ab">
Here are the boxes (drawn with polyline) that are scaled correctly, both in their own group (group-a, group-b)
</g>
<g id="group-a-id">
<text>A</text>
<circle id="group-a-id-bg-circle"></circle>
</g>
<g id="group-B-id">
<text>B</text>
<circle id="group-b-id-bg-circle"></circle>
</g>
<path id="group-a-pattern" d="..."></path>
<path id="group-b-pattern" d="..."></path>
</svg>
The path is the pattern for the pieces. It seems that everything that isn't under the group "group-ab" isn't scaled correctly, see the image below. Normally (when not using viewBox) the pattern fills up the boxes and the A/B are centered with the boxes (same translates are done to them).
Why is this happening? One would think that it doesn't matter if elements are within groups or not if svg is scaled.
I have a trouble opening an SVG file under my machine Linux:
Gave this svg file:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="1000px" height="707px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path id="MyPath" d="M 599,455 A 244,244 0 0,1 723,578" />
</defs>
<use xlink:href="#MyPath" fill="none" stroke="red" />
<text font-family="Verdana" font-size="42.5" fill="blue" >
<textPath xlink:href="#MyPath">
We go up, then we go down, then up again
</textPath>
</text>
</svg>
If I open it with firefox I can see it, but If I open it with gimp for example, I can see nothing.
What part of that file is creating this issue?
You are saying you see no error, so I don't know if this is right:
If you built GIMP yourself, our are not using the system's GIMP for some
reason, there is a chance the devel-files for the SVG libs
were not present when GIMP was built. If taht is the case, it won't be able to
read the SVG file itself.
You didn't say anything about error, so your might be another issue
(for example, the "Verdana" font might not be available for
GIMP, and it being replaced by a font with no visible glyphs)
In any case, the workaround would be to open the SVG file
in Inkscape, and export it as a raster PNG file for you
to work with it in GIMP>
I'm working on a PHP script that generates a jpg wallpaper from an SVG-file according to the screen resolution of the visitor. The wallpaper consists of a circular gradient (rectangle) background and a path on top of it. How would you go about centering the path horizontally and vertically to the rectangle? Remember that the rectangle's size and proportions are not a constant. Should I separate the background and path to different svg files or is there an easy way to center paths? Maybe a framework?
This is easilly achieved by using nested <svg> elements and the preserveAspectRatio attribute. Put your background in the outer svg and your path in the inner one.
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%">
<rect id="background" width="100%" height="100%" fill="grey"/>
<svg preserveAspectRatio="xMidYMid meet" viewBox="0 0 30 40" width="100%" height="100%">
<g>
<circle cx="15" cy="20" r="10" fill="yellow"/>
<circle cx="12" cy="17" r="1.5" fill="black"/>
<circle cx="18" cy="17" r="1.5" fill="black"/>
<path d="M 10 23 A 8 13 0 0 0 20 23" stroke="black" stroke-width="2" fill="none"/>
</g>
</svg>
</svg>
Run this snippet and try resizing the window.
To get this to work, all you need to ensure is that the viewBox attribute on the inner <svg> element is correctly set.
If you know the coordinates of the paths, you could take the total of the x/y coordinates and divide by the number of coordinates, this will give you the average position for the coordinate set. Then, offset each coordinate by the coordinates for half the width/height of the square, plus any offset, minus the difference between the center of the coordinate set and half the width/height of the square.
This should result in your coordinates being centered within the square, I think (it is rather early here, and I've just started my first coffee, so I could be wrong). This is of course assuming you know all the variables in play (the width/height of the square, any offset applied and the coordinates of the path).