ImageMagick SVG with Windows symbol font (private use unicode character) - svg

I'm using MagickNet (ImageMagick for .NET) to read the SVG code below, which contains a valid character from the "Symbol" true type font on Windows. The character is UF0B7 (uniF0B7 in the cmap table of the symbol.ttf font). This is a filled circle. The image I get using ImageMagick contains a rectangle with F0B7 written inside.
Here is my SVG file containing this special character. It is inside the text XML element (you might see it as a small square on your browser):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="main1" width="960" height="720">
<g transform="matrix(1.3333334 0 0 1.3333334 0 0)">
<path stroke="none" fill="#FFFFFF" fill-rule="evenodd" d="M0 0L720 0L720 540L0 540z" transform="matrix(1 0 0 1 0 0)" />
<text style="fill:#000000;font-family:Symbol;" font-size="32" transform="matrix(1 0 0 1 43.08661 129.5433)" fill-opacity="1" x="0.028347015" y="29.952" letter-spacing="-0.01"></text>
</g>
</svg>
Here is my C# code:
byte[] imageData = File.ReadAllBytes(#"F:\test.svg");
using MagickImage image = new MagickImage(imageData);
image.Write(#"F:\test.jpg");
Is there a way to make ImageMagick use the system's Symbol font with such private use characters (according to the unicode standard) ? This character and others of the same kind are often used by Powerpoint software for bullets. I need, in my own software, to convert pptx slides to svgs using available libraries, and then rework them, isolate paragraphs in separate SVGs, to produce slide animation. In order to convert the final SVGs to images, I could also use other libraries like SVG.Net, but this one has other problems too. Up to now, MagickNet is the most precise one, except for this problem.

Related

Why are there missing spaces in SVG text in some browsers?

I'm drawing a graphic in CorelDRAW (2021) and then exporting it to SVG.
In CorelDRAW, one of the artistic text objects contains text in different font weights. For example:
Garfield sat on the mat
Problem: Some browsers, such as Chrome and Edge, display that text in the SVG as:
Garfieldsat on the mat
That is, with the bold "Garfield" abutting the normal "sat", with no space.
In other browsers, such as Firefox, the same SVG displays as expected, with a space.
Example SVG (exported from CorelDRAW: not a truly minimal example, but I've stripped some of the excess markup):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW 2021.5 -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="3.44562in" height="0.247335in" version="1.1" viewBox="0 0 18928.2 1358.7">
<defs>
<style type="text/css">
<![CDATA[
.fil0 {fill:#373435}
.fnt1 {font-weight:normal;font-size:1831.1px;font-family:'Arial'}
.fnt0 {font-weight:bold;font-size:1831.1px;font-family:'Arial'}
]]>
</style>
</defs>
<text x="-87.9" y="1334.9" class="fil0 fnt0">Garfield</text>
<text x="6831.7" y="1334.9" class="fil0 fnt1"> sat on the mat</text>
</svg>
Chrome and Edge, and possibly other browsers, ignore leading spaces inside the SVG <text> element.
Here's a snippet of the SVG:
<text ... class="fil4 fnt0">Garfield</text>
<text ... class="fil4 fnt1"> sat on the mat</text>
(where "..." indicates elided attributes)
Note:
CorelDRAW has split the original single text object into two SVG <text> elements. Understandable, because of the different font weights (.fnt0 is bold, .fnt1 is normal).
The content of the second <text> element begins with a space.
Workaround: In CorelDRAW, don't mix font weights in a single text object.
More generally, whatever application you use to create SVG: if you notice a missing space when the SVG is rendered (say, in a browser), check whether the content of the corresponding SVG <text> element begins with a leading space. If so, rework your artwork in the original application to avoid that SVG output.
Usually for html2pdf, in common with many apps, heavy weight texts tend to "stretch" into a following void, or in this case the leading space is not defined. One way to enforce whitespace is try in standard html see the enforced spacing in https://stackoverflow.com/a/74297349/10802527
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW 2021.5 -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="3.44562in" height="0.247335in" version="1.1" viewBox="0 0 18928.2 1358.7">
<defs>
<style type="text/css">
<![CDATA[
.fil0 {fill:#373435}
.fnt1 {font-weight:normal;font-size:1831.1px;font-family:'Arial'}
.fnt0 {font-weight:bold;font-size:1831.1px;font-family:'Arial'}
]]>
</style>
</defs>
<text x="-87.9" y="1334.9" class="fil0 fnt0">Garfield</text>
<text x="6831.7" y="1334.9" class="fil0 fnt1"> sat on the mat</text>
</svg>

Is it possible to convert a base64 SVG into a standard one that uses paths / <g> tags?

I have an SVG that looks like this:
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="3367px" height="1250px" viewBox="0 0 3367 1250" enable-background="new 0 0 3367 1250" xml:space="preserve"> <image id="image0" width="3367" height="1250" x="0" y="0"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAADScAAATiCAQAAABYVH+tAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZ
cwAALiMAAC4jAXilP3YAAAAHdElNRQfkBRkBOx8UiOyrAABwDUlEQVR42uzda5obq5Io0PT5el6m
RlZ4ZEqPzP3Du/b2o+wSEhnBYy19t0/f07gACaXIDAKOAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAADgKp+yGwDAxepf/m+fj/Lv/34eXx/6GwAAAADA4oSTANZQfggMvV5a05d//7ea3WkAAAAA
IIJwEsCc6j//eW3o6D5vAab6zB8BAAAAAEYlnAQwi+/5Rz9uTzem78Glmt0MAAAAAKAX4SSAkc0S
QvqTL8dxnMeZ3QwAAAAA4BnCSQDj+R5EGmEbu36+HDKWAAAAAGBSwkkA46jHzJlI9zmPr/KVAAAA
AGAuwkkA2VbMRfqYsBIAAAAATEM4CSBPXT4X6WM2wYNs9eF/KSQ8v7L9rxCMaYfraw2sa4f3k93V
h/+l7wcAAAytHvX45vXTq3qkCSmeuxoxO79GXl5jvmr2xSGA9xP6eeb3/JbdeABm8r/sBgBspBz1
uB3fjtfttrb72OtxOwSVIN7np/51zW4+AMD2nrm7lKkMQAPhJIAI5ajHt+N2vJqs/5WgEsR69gGC
0DgAQK765L83nwPgbsJJANf6L5DEvQSVIMrzV6aS3QUAgK09O5+TnwTA3YSTAK4ikPQcQSW4Xnn6
L7jCAQDkKYP8DQC2IJwE0J9AUj9vQSWgv9rhb1jPCgCQp8c9p/tWAO4knATQk0DSNV6Pb8fNQ2vo
rM+VyvUOACBHr4U9NbsjAMxBOAmgl3rcBJIuVOQpQVe1098p2R0BANhU6fR33MUCcJf/y24AwALK
Is it possible to conver that into a standard SVG that uses <path> and <g> tags that we are all familiar with ?
What is that standard SVG called?
Base64 encoding is a way of converting a stream of binary data into printable characters (letters, numbers, and punctuation) for when you can't include arbitrary binary data.
SVG is already printable, so encoding it with Base64 wouldn't make any sense; there is no "base64 SVG" here.
What you're seeing is something else embedded inside the SVG. A clue to what is embedded comes in this line:
data:image/png;base64
That's a data: URI, but the important thing to notice is that as well as "base64", it specifies a file type: "image/png". So the thing that's embedded is a PNG file - a bitmap image format common on the web.
This explains two things:
It needs to be base64 encoded, because it's a binary format embedded into a text format.
It needs to be embedded, because it's a bitmap image (specifying the colour of each pixel) not a vector image (specifying what shapes to draw).
So, in short: no.

Is there a blend mode to replace black and keep other colors (i.e. white)?

I want to create a dynamically colored map marker in flutter_svg
<?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 style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;" height="100%" version="1.1" viewBox="0 0 24 24" width="100%" xmlns="http://www.w3.org/2000/svg" xml:space="preserve">
<g transform="matrix(1,0,0,1,4,0)">
<path style="fill:rgb(0,0,0);" d="M8.25,0C3.689,0 0,3.756 0,8.4C0,14.7 8.25,24 8.25,24C8.25,24 16.5,14.7 16.5,8.4C16.5,3.756 12.811,0 8.25,0Z"/>
<path style="fill:rgb(255,255,255);" d="M8.25,11.4C6.624,11.4 5.304,10.056 5.304,8.4C5.304,6.744 6.624,5.4 8.25,5.4C9.876,5.4 11.196,6.744 11.196,8.4C11.196,10.056 9.876,11.4 8.25,11.4Z"/>
</g>
</svg>
which looks like this:
I am experimenting with Blend Modes.
If I use this:
SvgPicture.asset(
"assets/images/to_marker.svg",
package: "trufi_core",
color: const Color(0xff27ae60),
colorBlendMode: BlendMode.difference,
)
the white color becomes transparent:
Is there even a blend mode which just replaces black by the color, and leaves white intact or do I have to use some color replacing?
Is there another way to replace a color in flutter_svg, maybe with CSS?
By brute forcing (trying all the modes) I found out, that BlendMode.screen works for this case

Converting vector fill patterns to explicit objects

I'm creating some masks for photolithography that have arrays of 50 µm features across a 4"x4" span.
An SVG file that represents my mask objects implicitly as a fill pattern is trivial:
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="4in" xmlns="http://www.w3.org/2000/svg" version="1.1" height="4.25in">
<defs>
<pattern height="0.100000mm" width="0.100000mm" patternUnits="userSpaceOnUse" y="0" x="0" id="tile">
<rect y="0" width="0.100000mm" fill="black" x="0" height="0.100000mm" />
<rect y="0.025000mm" width="0.050000mm" height="0.050000mm" x="0.025000mm" fill="white" />
</pattern>
</defs>
<rect y="0" width="4in" height="4in" x="0" fill="url(#tile)" />
<text font-size="6pt" y="4.1in" x="0.1cm" font-family="Consolas">50 µm squares, 50 µm pitch; tds 3/6/13</text>
</svg>
Our printing provider says they can take EPS files. Doing a round trip from SVG to EPS in Illustrator works fine, but the generated EPS file still has an implicit representation of the mask features, and the print shop says they can't see anything. I think that I need to have an explicit representation of each of the features instead of using a fill pattern.
What's the best way (with Postscript?) to convert a vector fill pattern into explicitly rendered vector objects? I could generate the SVG by hand but gosh, that would be a honking huge text file.
You should be able to get this converted from a pattern to actual vector data within Illustrator by selecting Object > Expand (make sure Fill is selected). Note that this will generate many paths and your resulting file should indeed be honking huge.

SVG and DPI, absolute units and user units: Inkscape vs. Firefox vs. ImageMagick

I try to auto-generate an SVG file intended to be printed on a certain size (A4). I wish to use a path in it, which only allows 'user units', not 'absolute units'.
It seems to me that it is impossible to 'publish' an SVG file that has absolute units (e.g. document size) and a path anywhere, because I cannot get it to work properly across viewers.
Is there a way to get some consistency in rendering, like specifying a 'default DPI'?
Or put differently: Can I get my example below to render the same in all viewers without abandoning absolute units at all?
Related: Is there a way to force any of the applications below to render the image in the same way as one of the others? (E.g. I tried the -density option of 'convert', but I couldn't get the output to match Inkscape's or Firefox' output.)
Example:
I've created one SVG file, with three black squares (rect) with a red diagonal (path):
Left: square and diagonal in user units
Middle: square and diagonal in inch (seemed to me the most logical choice, but is not allowed)
Right: square in mm, diagonal in user units
Which renders differently in different viewers:
Inkscape: 90 DPI, all squares same size, red diagonal matches
Firefox: 96 DPI?, latter squares to large (or diagonal to short)
Convert: 72 DPI, latter squares to small (or diagonal to long)
Code:
<?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"
version="1.1"
width="200mm"
height="100mm"
>
<g transform="translate(50,50)">
<rect
width="100."
height="100."
x="10"
y="10" />
<path style="stroke: #ff0000" d="M 10 10 L 110 110" />
</g>
<g transform="translate(200,50)">
<rect
width="1.111in"
height="1.111in"
x="0.1111in"
y="0.1111in" />
<path style="stroke: #ff0000" d="M 0.1111in 0.1111in L 1.111in 1.111in" />
</g>
<g transform="translate(350,50)">
<rect
width="1.111in"
height="1.111in"
x="0.1111in"
y="0.1111in" />
<path style="stroke: #ff0000" d="M 10 10 L 110 110" />
</g>
</svg>
Inkscape (my default 'viewer'):
Firefox (note that the red line does not reach the lower right corner. I made a screenshot and cropped sort of arbitrarily):
ImageMagick (convert, no options besides filenames given):
All dimensions in a path tag are in user units.
You cannot specify absolute units within a path tag, which is why the path in the middle square does not render.
The simplest way I have found is to set the units using viewbox:
Set the width & height in inches.
Then set the viewbox to be the same.
This sets the user unit to be one inch.
All sizes are then specified in inches (note: I used lower case l in path tag to specify a relative move)
This displays correctly in Inkscape and Firefox.
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="8in"
height="4in"
viewBox="0 0 8 4">
<g transform="translate(4,0.5)">
<rect
width="1.111"
height="1.111"
x="0.1111"
y="0.1111" />
<path d="M 0.1111,0.1111 l 1.111 1.111" style="stroke: #ff0000;stroke-width:0.01" />
</g>
</svg>
I have had a similar issue using Apache Batik to embed an SVG file in a PDF file using iText. iText uses 72 DPI, the standard for PDF, while Batik uses 96.
To get the image to appear correctly, that is, to scale, in the PDF file, you need to divide the width=x cm height=y cm in the SVG header by 1.33 (96/72).

Resources