How to convert a SVG to a PNG with ImageMagick? - svg

I have a SVG file that has a defined size of 16x16. When I use ImageMagick's convert program to convert it into a PNG, then I get a 16x16 pixel PNG which is way too small:
convert test.svg test.png
I need to specify the pixel size of the output PNG. -size parameter seems to be ignored, -scale parameter scales the PNG after it has been converted to PNG. The best result up to now I got by using the -density parameter:
convert -density 1200 test.svg test.png
But I'm not satisfied, because I want to specify the output size in pixels without doing math to calculate the density value. So I want to do something like this:
convert -setTheOutputSizeOfThePng 1024x1024 test.svg test.png
So what is the magic parameter I have to use here?

I haven't been able to get good results from ImageMagick in this instance, but Inkscape does a nice job of scaling an SVG on Linux and Windows:
# Inkscape v1.0+
inkscape -w 1024 -h 1024 input.svg -o output.png
# Inkscape older than v1.0
inkscape -z -w 1024 -h 1024 input.svg -e output.png
Note that you can omit one of the width/height parameters to have the other parameter scaled automatically based on the input image dimensions.
Here's the result of scaling a 16x16 SVG to a 200x200 PNG using this command:

Try svgexport:
svgexport input.svg output.png 64x
svgexport input.svg output.png 1024:1024
svgexport is a simple cross-platform command line tool that I have made for exporting svg files to jpg and png, see here for more options. To install svgexport install npm, then run:
npm install svgexport -g
Edit: If you find an issue with the library, please submit it on GitHub, thanks!

This is not perfect but it does the job.
convert -density 1200 -resize 200x200 source.svg target.png
Basically it increases the DPI high enough (just use an educated/safe guess) that resizing is done with adequate quality. I was trying to find a proper solution to this but after a while decided this was good enough for my current need.
Note: Use 200x200! to force the given resolution

Inkscape doesn't seem to work when svg units are not px (e.g. cm). I got a blank image. Maybe, it could be fixed by twiddling the dpi, but it was too troublesome.
Svgexport is a node.js program and so not generally useful.
Imagemagick's convert works ok with:
convert -background none -size 1024x1024 infile.svg outfile.png
If you use -resize, the image is fuzzy and the file is much larger.
BEST
rsvg-convert -w 1024 -h 1024 infile.svg -o outfile.png
It is fastest, has the fewest dependencies, and the output is about 30% smaller than convert. Install librsvg2-bin to get it:
sudo apt install -y librsvg2-bin
There does not appear to be a man page but you can type:
rsvg-convert --help
to get some assistance. Simple is good.

If you are on MacOS X and having problems with Imagemagick's convert, you might try reinstalling it with RSVG lib.
Using HomeBrew:
brew remove imagemagick
brew install imagemagick --with-librsvg
Verify that it's delegating correctly:
$ convert -version
Version: ImageMagick 6.8.9-8 Q16 x86_64 2014-12-17 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2014 ImageMagick Studio LLC
Features: DPC Modules
Delegates: bzlib cairo fontconfig freetype jng jpeg lcms ltdl lzma png rsvg tiff xml zlib
It should display rsvg.

After following the steps in Jose Alban's answer, I was able to get ImageMagick to work just fine using the following command:
convert -density 1536 -background none -resize 100x100 input.svg output-100.png
The number 1536 comes from a ballpark estimate of density, see this answer for more information.

In order to rescale the image, the option -density should be used. As far as I know the standard density is 72 and maps the size 1:1. If you want the output png to be twice as big as the original svg, set the density to 72*2=144:
convert -density 144 source.svg target.png

In ImageMagick, one gets a better SVG rendering if one uses Inkscape or RSVG with ImageMagick than its own internal MSVG/XML rendered. RSVG is a delegate that needs to be installed with ImageMagick. If Inkscape is installed on the system, ImageMagick will use it automatically. I use Inkscape in ImageMagick below.
There is no "magic" parameter that will do what you want.
But, one can compute very simply the exact density needed to render the output.
Here is a small 50x50 button when rendered at the default density of 96:
convert button.svg button1.png
Suppose we want the output to be 500. The input is 50 at default density of 96 (older versions of Inkscape may be using 92). So you can compute the needed density in proportion to the ratios of the dimensions and the densities.
512/50 = X/96
X = 96*512/50 = 983
convert -density 983 button.svg button2.png
In ImageMagick 7, you can do the computation in-line as follows:
magick -density "%[fx:96*512/50]" button.svg button3.png
or
in_size=50
in_density=96
out_size=512
magick -density "%[fx:$in_density*$out_size/$in_size]" button.svg button3.png

On macOS using brew, using librsvg directly works well
brew install librsvg
rsvg-convert test.svg -o test.png
Many options are available via rsvg-convert --help

For simple SVG to PNG conversion I found cairosvg (https://cairosvg.org/) performs better than ImageMagick. Steps for install and running on all SVG files in your directory.
pip3 install cairosvg
Open a python shell in the directory which contains your .svg files and run:
import os
import cairosvg
for file in os.listdir('.'):
name = file.split('.svg')[0]
cairosvg.svg2png(url=name+'.svg',write_to=name+'.png')
This will also ensure you don't overwrite your original .svg files, but will keep the same name. You can then move all your .png files to another directory with:
$ mv *.png [new directory]

why don't you give a try to inkscape command line, this is my bat file to convert all svg in this dir to png:
FOR %%x IN (*.svg) DO C:\Ink\App\Inkscape\inkscape.exe %%x -z --export-dpi=500 --export-area-drawing --export-png="%%~nx.png"

This is what worked for me and would be the easiest to run.
find . -type f -name "*.svg" -exec bash -c 'rsvg-convert -h 1000 $0 > $0.png' {} \;
rename 's/svg\.png/png/' *
This will loop all the files in your current folder and sub folder and look for .svg files and will convert it to png with transparent background.
Make sure you have installed the librsvg and rename util
brew install librsvg
brew install rename

Transparent background, exported at target height/size using ImageMagick 7:
magick -background none -size x1080 in.svg out.png
One-liner mass converter:
for i in *svg; do magick -background none -size x1080 "$i" "${i%svg}png"; done

I came to this post - but I just wanted to do the conversion by batch and quick without the usage of any parameters (due to several files with different sizes).
rsvg drawing.svg drawing.png
For me the requirements were probably a bit easier than for the original author. (Wanted to use SVGs in MS PowerPoint, but it doesn't allow)

Without librsvg, you may get a black png/jpeg image. We have to install librsvg to convert svg file with imagemagick.
Ubuntu
sudo apt-get install imagemagick librsvg
convert -density 1200 test.svg test.png
MacOS
brew install imagemagick librsvg
convert -density 1200 test.svg test.png

One thing that just bit me was setting the -density AFTER the input file name. That didn't work. Moving it to the first option in convert (before anything else) made it work (for me, YMMV, etc).

On Linux with Inkscape 1.0 to convert from svg to png need to use
inkscape -w 1024 -h 1024 input.svg --export-file output.png
not
inkscape -w 1024 -h 1024 input.svg --export-filename output.png

I've solved this issue through changing the width and height attributes of the <svg> tag to match my intended output size and then converting it using ImageMagick. Works like a charm.
Here's my Python code, a function that will return the JPG file's content:
import gzip, re, os
from ynlib.files import ReadFromFile, WriteToFile
from ynlib.system import Execute
from xml.dom.minidom import parse, parseString
def SVGToJPGInMemory(svgPath, newWidth, backgroundColor):
tempPath = os.path.join(self.rootFolder, 'data')
fileNameRoot = 'temp_' + str(image.getID())
if svgPath.lower().endswith('svgz'):
svg = gzip.open(svgPath, 'rb').read()
else:
svg = ReadFromFile(svgPath)
xmldoc = parseString(svg)
width = float(xmldoc.getElementsByTagName("svg")[0].attributes['width'].value.split('px')[0])
height = float(xmldoc.getElementsByTagName("svg")[0].attributes['height'].value.split('px')[0])
newHeight = int(newWidth / width * height)
xmldoc.getElementsByTagName("svg")[0].attributes['width'].value = '%spx' % newWidth
xmldoc.getElementsByTagName("svg")[0].attributes['height'].value = '%spx' % newHeight
WriteToFile(os.path.join(tempPath, fileNameRoot + '.svg'), xmldoc.toxml())
Execute('convert -background "%s" %s %s' % (backgroundColor, os.path.join(tempPath, fileNameRoot + '.svg'), os.path.join(tempPath, fileNameRoot + '.jpg')))
jpg = open(os.path.join(tempPath, fileNameRoot + '.jpg'), 'rb').read()
os.remove(os.path.join(tempPath, fileNameRoot + '.jpg'))
os.remove(os.path.join(tempPath, fileNameRoot + '.svg'))
return jpg

The top answer by #808sound did not work for me. I wanted to resize
and got
So instead I opened up Inkscape, then went to File, Export as PNG fileand a GUI box popped up that allowed me to set the exact dimensions I needed.
Version on Ubuntu 16.04 Linux:
Inkscape 0.91 (September 2016)
(This image is from Kenney.nl's asset packs by the way)

I was getting "low poly" curves using the general approach of increasing the density. So I decided to dig a little deeper and solve that problem as it seemed to be a side effect of this approach and I think it has to do with the original density or dpi.
We have seen 72 in this answer and 96 in this answer being suggested as the default density of an image, but which one? what if mine is different?
ImageMagick has a way to sort that out:
identify -verbose test.svg
this will put out a lot of metadata about the image file, including:
Image:
Filename: test.svg
Format: SVG (Scalable Vector Graphics)
Mime type: image/svg+xml
Class: ...
Geometry: ...
Resolution: 37.79x37.79
Print size: ...
Units: PixelsPerCentimeter
# and a whole lot MORE ...
for a more concise query you can try:
identify -format "%x x %y %U" test.svg
=> 37.789999999999999147 x 37.789999999999999147 PixelsPerCentimeter
as suggested by this forum post and modified with this documentation
Now we know the current density of the image but may need to convert it to the correct units for conversion or mogrifying (PixelsPerInch or dpi)
this is a simple calculations of PixelsPerCentimeter x 2.54
37.789999999999999147 x 2.54 = 95.9866 ~> 96
if you prefer a chart or online calculator for this you can try https://www.pixelto.net/cm-to-px-converter.
now that we have the right original density converted to dpi, the rest of the logic stated in the above answers falls into place and the svg file can be scaled to a better "resolution" by multiplying the original density.
the original density was far too pixelated as a png for me, so in my case 5x the original density or -density 480 was good enough for me. Remember that this resizes the image as well and you will need to adjust for that when using / implementing the image as compared to the original svg.
NOTE: I did try the Inkscape approaches as well and also had the pixelation problem, but had already seen an improvement with the density approach so I decided to dig into that deeper. The output of the Inkscape attempt however gave me the idea, which you can also use for determining the dpi, but that is a lot to install just to get something you can already get with ImageMagick
Area 0:0:20.75:17 exported to 21 x 17 pixels (96 dpi)

Related

how to export svg to png on the command line without antialiasing

I need to do some batch processing of svg files. SVG elements are all either black or white and I need bitmap images that are monochrome (black/white, no grayscale).
From within the inkscape gui I can just select this as an option.
However, I don't see any inkscape cli options related to antialiasing
Same for librsvg, (rsvg-convert) no command line options in the manual related to anti-aliasing.
Second thought was to just export to a png image and then use ImageMagick to threshhold the image. However, on my system
Mac OSX catalina (latest)
brew install imagemagick -> 7.0.10-23
when I run the following, i get an error:
>>> convert test.im.png -channel RGB -threshhold 50% test.im.t.png
convert: unrecognized option `-threshhold' # error/convert.c/ConvertImageCommand/3112.
looking for a little help on how to get from a black and white svg to a black and white png on the command line for batch processing given these problems.
On IM 7, use magick, not convert. So try
magick +antialias image.svg -channel RGB result.png
or
magick image.svg -channel RGB -threshold 50% result.png
If one of these works, then you can process a whole folder of files using magick mogrify. See https://imagemagick.org/Usage/basics/#mogrify

Why is ImageMagick treating SVG differently when piped in?

I have a file q.svg which is transparent (at least at the top left). Here's a command and its result:
$ convert -verbose -background "#ffffff00" q.svg -depth 8 RGBA:- | ruby -e '$stdin.binmode;p $stdin.read(4)'
'inkscape' '/tmp/magick-18391tJtIEDjjRpHh' --export-png='/tmp/magick-18391Wt5UBvmqqzoj' --export-dpi='96,96' --export-background='rgb(100%,100%,100%)' --export-background-opacity='0' > '/tmp/magick-18391_rpBcJRZuR3k' 2>&1
/tmp/magick-18391Wt5UBvmqqzoj PNG 640x384 640x384+0+0 8-bit sRGB 3413B 0.040u 0:00.029
/tmp/work/q.svg SVG 640x384 640x384+0+0 8-bit sRGB 3413B 0.000u 0:00.010
"\x00\x00\x00\x00"
The pixel is black fully transparent. I specified white as background color but as it's fully transparent, this is fine for me.
Now I run the command differently, by piping my input to convert:
$ cat q.svg | convert -verbose -background "#ffffff00" SVG:- -depth 8 RGBA:- | ruby -e '$stdin.binmode;p $stdin.read(4)'
'inkscape' '/tmp/magick-18396DKgnVvgUiunU' --export-png='/tmp/magick-18396vzaREmaEV3VO' --export-dpi='96,96' --export-background='rgb(100%,100%,100%)' --export-background-opacity='0' > '/tmp/magick-18396hHG-MP4569rJ' 2>&1
mvg:/tmp/magick-18396ZW9toKj2UPw8=>/tmp/magick-18396ZW9toKj2UPw8 MVG 640x384 640x384+0+0 16-bit sRGB 669B 0.280u 0:00.280
SVG:-=>- MVG 640x384 640x384+0+0 16-bit sRGB 669B 0.000u 0:00.010
"\xFF\xFF\xFF\x00"
The result is different now, and the process is different apparently - some MVG appears in the verbose log. Why is this different?! Some pixels (that were not transparent in the SVG) are actually incorrect this time in the full result.
If I specify the input as - instead of SVG:- I get back the behaviour from the first example apparently. So I can probably get the result I want by some trickery, but I'd prefer to understand what's going on. How is the "input engine" or whatever selected? Why is MVG involved, even after running inkscape? What input type should I use to get the SVG parsed correctly if I really want to specify it?
Version info:
$ convert -version
Version: ImageMagick 6.9.10-23 Q16 arm 20190101 https://imagemagick.org

jpg to eps conversion inverts colors

I'm trying to convert some CMYK images from jpg to eps using convert image.jpg -format esp3 image.eps. The resulting file appears to invert or mangle the color information.
Sample of the original .jpg:
Sample of the converted .eps:
I've tried some variations of the command. The output of convert -colorspace RGB image.jpg -format esp3 image.eps, for example, looks significantly better (as in the image is identifiable). Predictably, however, the colors are not correct.
What can I do to correct the outcome? I'm open to other (linux terminal) programs or scripting languages to get the job done.
Potentially useful information:
$ convert --version
Version: ImageMagick 6.9.7-4 Q16 x86_64 20170114 http://www.imagemagick.org
Copyright: © 1999-2017 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules OpenMP
Delegates (built-in): bzlib djvu fftw fontconfig freetype jbig jng jpeg lcms lqr ltdl lzma openexr pangocairo png tiff wmf x xml zlib
This works fine for me on IM 6.9.10.84 Q16 Mac OSX.
sRGB lena.jpg:
Convert it to CMYK:
convert lena.jpg -colorspace CMYK x1.jpg
CMYK lena (x1.jpg):
Convert to EPS:
convert x1.jpg EPS3:x1.eps
A display of x1.eps using Mac Preview looks fine - no color inversion.
Likewise, using profiles is even better:
convert lena.jpg -profile /Users/fred/images/profiles/sRGB.icc -profile /Users/fred/images/profiles/USWebCoatedSWOP.icc x2.jpg
CMYK lena with profiles (x2.jpg)
Convert to EPS:
convert x2.jpg EPS3:x2.eps
Result looks like the jpg from which it was created -- no color inversion.
Post your input jpg and I can take a look.
Perhaps it is your version of ImageMagick or of libjpeg or of lcms?
convert image.jpg -format esp3 image.eps
Note: you have misspelled -format eps3 (you used esp3). So perhaps the default EPS does not support what you are trying to do. Also note I prefaced my output with EPS:. Try that, though probably won't matter.

How do you extract a date from an image file and print it on to the image in linux

I have to write a script in linux with the identify command to extract a date from an image file and add it to the image itself this has to be done for every file in the specified directory. Anyone who could help me? Thanks a lot! I'm now on to this:
for file in $picturemap
do
identify -verbose $file > date.txt
date= date.txt grep | "date:create:"
done
its everything i know
You can use imagemagick package to draw on image files, convert them to other formats and lots of other stuff. There are huge amount of switches that can be useful, just reffer to the documentation.
Install imagemagick
sudo apt-get install imagemagick
Use convert command with draw switch.
Example:
convert test1.jpg -weight 700 -pointsize 200 -draw "gravity north fill black text 0,100 'text' " test2.jpg
this will take test1.jpg annotate text with black color in your image and write it to test.jpg.

Convert TrueType glyphs to PNG image?

Is there a command line tool to convert glyphs from a TTF file, to PNG (or some other bitmap image format)?
If there is no ready command line tool for that, how would you go about doing it from one of C++, Perl, Python or Ruby or something easily found on an Ubuntu box?
probably partly duplicate of How can I convert TTF glyphs to .png files on the Mac for free?
imagemagick can fulfill this kind of requests, should works fine on Mac/Linux/Windows. :-)
convert -background none -fill black -font font.ttf -pointsize 300 label:"Z" z.png
if a batch convert is needed, maybe you can consider use a little ruby script called ttf2png .
Python3
Since nobody has really address the part that specifies for C++, Python, Ruby, or Perl, here is the Python3 way. I've tried to be descriptive, but you can simplify to work how you need it to.
Requirements: PIL (Pillow)
PIL's ImageDraw and ImageFont module
# pip install Pillow
from PIL import Image, ImageFont, ImageDraw
# use a truetype font (.ttf)
# font file from fonts.google.com (https://fonts.google.com/specimen/Courier+Prime?query=courier)
font_path = "fonts/Courier Prime/"
font_name = "CourierPrime-Regular.ttf"
out_path = font_path
font_size = 16 # px
font_color = "#000000" # HEX Black
# Create Font using PIL
font = ImageFont.truetype(font_path+font_name, font_size)
# Copy Desired Characters from Google Fonts Page and Paste into variable
desired_characters = "ABCČĆDĐEFGHIJKLMNOPQRSŠTUVWXYZŽabcčćdđefghijklmnopqrsštuvwxyzž1234567890‘?’“!”(%)[#]{#}/&\<-+÷×=>®©$€£¥¢:;,.*"
# Loop through the characters needed and save to desired location
for character in desired_characters:
# Get text size of character
width, height = font.getsize(character)
# Create PNG Image with that size
img = Image.new("RGBA", (width, height))
draw = ImageDraw.Draw(img)
# Draw the character
draw.text((-2, 0), str(character), font=font, fill=font_color)
# Save the character as png
try:
img.save(out_path + str(ord(character)) + ".png")
except:
print(f"[-] Couldn't Save:\t{character}")
The PIL provides an API for this, but it's easy to use. Once you've got the PIL image, you can export it.
As suggested by #imcaspar, but I need it to convert icons in ttf font to png with specific sizes for ios integration
convert -background none -font my-icons-font.ttf -fill black -size "240x240" label:"0" +repage -depth 8 icon0#1x.png
where "0" is the character mapped for any of my icons. The extra options allowed me to have all character(icons) correctly generated as some where being cropped with regular command (+repage -depth did the job)
For my purposes I created a shell script. Works fine on macOS if ImageMagick is installed. Not sure about other platforms.
#!/bin/bash
FONT_NAME="$1"
FONT_SIZE="$2"
FILE_NAME=$(basename ${FONT_NAME} .ttf)"-${FONT_SIZE}.png"
read -r -d '' CHARSET << EOM
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789.:,;(*!?}^)#\${\%
&-+#'\"[]<>
EOM
convert -font ${FONT_NAME} -pointsize ${FONT_SIZE} label:"${CHARSET}" "${FILE_NAME}"
If you need additional characters exported, you might need to adjust charset variable used in script.
Call script with TTF font file and point size as arguments, as such:
> sh ttf2png.sh alagard.ttf 20
This script will then generate a file alagard-20.png
wget http://sid.ethz.ch/debian/ttf2png/ttf2png-0.3.tar.gz
tar xvzf ttf2png-0.3.tar.gz
cd ttf2png-0.3 && make
./ttf2png ttf2png -l 11 -s 18 -e -o test.png /path/to/your/font.ttf
eog test.png&

Resources