SVG patterns rasterised when printing to PDF - svg

I'm trying to create a SVG file what when printed to PDF maintains all of its parts in vector. This file uses a pattern as a fill to a path, or in the example bellow as the fill to the rect element:
<svg
width="200"
height="200"
viewBox="0 0 200 200"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
className="productWrapper"
>
<defs>
<pattern id="pattern" x="0" y="0" width="1" height="1">
<path
fill="#fcc"
d="[vector path here]"
/>
</pattern>
</defs>
<rect fill="url(#pattern)" stroke="black" width="200" height="200" />
</svg>
The issue I'm facing is that when printed to PDF the rect element or any path at the top level of the SVG file stays vector, but all vector content inside the pattern is rasterized.
A very minimal example of this can be found here:
https://6j8953j8rn.codesandbox.io/
Any way to get the SVG to render in vector when printing to PDF?

One tool that kept vector info after converting from SVG (including <pattern>) to PDF (I used it as CLI) is https://github.com/typst/svg2pdf
Some online converters also could do it while the most of other tools I tried make content inside <pattern> raster.

Related

Is it possible to center a SVG pattern image fill without using JavaScript?

I have the following SVG:
<?xml version="1.0" encoding="UTF-8"?>
<svg width="480" height="1080" version="1.1" viewBox="0 0 480 1080" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="wpi" width="100%" height="100%" patternUnits="userSpaceOnUse">
<image width="100%" height="100%" preserveAspectRatio="none" xlink:href="h_img.jpg" x="0" y="0"/>
</pattern>
</defs>
<rect class="wallpaper" width="100%" height="250" fill="url(#wpi)"/>
</svg>
The h_img jpg might vary on time, loading different images, so I can't be aware of its size in advance, yet I know that, most of the time, its height value is greater than its width but I need to apply it to a rect element that has a smaller height compared to its own width and this is for sure (despite I'm using a relative 100% value for that one). I need the pattern to fill that rect with the image maintaining its aspect ratio and the height being crop (or hide overflow) centered. I know I can use JavaScript to calculate the image relative width, resize the height accordingly to maintain the aspect ratio and calculate the offset needed to provide the centering (and I did) but... Do you know maybe is there a way to do what I need simply using the right parameters on the SVG element and no JavaScript?
I tried with:
<pattern id="wpi" width="100%" height="100%" patternContentUnits="objectBoundingBox">
<image width="1" height="1" preserveAspectRatio="xMidYMid" xlink:href="h_img.jpg" x="0" y="0"/>
</pattern>
But that doesn't get me the desired effect I need...
Thanks for your help
SOLVED EDIT:
Thanks to #ccprog for his suggestion took me on the right direction, I managed to find a way to solve like this:
<?xml version="1.0" encoding="UTF-8"?>
<svg width="480" height="1080" viewBox="0 0 480 1080" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<pattern id="wpi" width="1" height="1">
<image width="100%" height="250" preserveAspectRatio="xMidYMid slice" xlink:href="h_img.jpg"/>
</pattern>
</defs>
<rect class="wallpaper" width="100%" height="250" fill="url(#wpi)"/>
</svg>
Notice: you need to set for the <image> just the same height and width values used for the pattern image container area (= that means the size of the element on which the pattern is going to be applied, in this case it's a <rect>).
As final words I'll say there are at least a couple of reasons for I wanted the image to stay applied within a pattern:
one is that, in this way, I can be able to use javascript code to shift the centering of the image by y and x attributes values while letting the rectangle stay in its position;
and another reason is I could change the rectangle fill to a solid color easily if I need doing it.
If you want to display an image once in a rectangular area, you do not need a pattern. Patterns are for repeating content more than once.
The attribute you were searching for is preserveAspectRatio="xMidYMid slice". See the spec.
<svg width="480" height="1080" viewBox="0 0 480 1080"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image class="wallpaper" width="100%" height="250"
preserveAspectRatio="xMidYMid slice" xlink:href="h_img.jpg"/>
</svg>

Transforming <svg> element in SVG behaves differently in Chrome, Firefox

I have a fairly simple SVG which I've converted into a SSCCE. Here's the SVG (and a fiddle you can see for yourself):
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<rect id="leader" width="100%" height="100%" stroke="red" fill="none" />
<svg id="left" x="5%" y="5%" width="40%" height="85%">
<rect width="100%" height="100%" fill="blue"/>
</svg>
<svg id="left" x="55%" y="5%" width="40%" height="85%" transform="scale(.5)">
<rect width="100%" height="100%" fill="red"/>
</svg>
</svg>
I'm expecting a large, empty red rectangle containing two smaller rectangles: one blue one which takes up quite a bit of space and another one (red) which is half the size of the blue one. There is a translation which occurs as well, but that's not terribly important for this question.
In Firefox, I get the expected image, which is this:
However, when I view the same image in Chrome (or Safari), it seems to be ignoring my transformation, and the two rectangles are both the same size:
Is there something wrong with my SVG, is this a bug in either of these browsers, or is this an unsupported part of SVG in Chrome/Safari? There is an old bug from early 2017 which is reported to be fixed, so I'm thinking that I'm missing something about the way SVG transforms are supposed to work.
The transform attribute for an <svg> element has only been introduced for SVG 2. For now it is not supported in all browsers. (Setting a version attribute on the root element has no effect.)
You can achieve the same effect if you wrap the <svg> element with a <g> and define the transformation there. The percentage values for the positioning will still be relative to the nearest parent element establishing a viewport, which is the outer <svg>.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="leader" width="100%" height="100%" stroke="red" fill="none" />
<svg id="left" x="5%" y="5%" width="40%" height="85%">
<rect width="100%" height="100%" fill="blue"/>
</svg>
<g transform="scale(.5)">
<svg id="left" x="55%" y="5%" width="40%" height="85%">
<rect width="100%" height="100%" fill="red"/>
</svg>
</g>
</svg>
The bug you referenced, btw, does not apply. It's not easy to see at first glance, but the attached test case shows this refers to setting a transformation on a <g> element via script.

Convert SVG textPath to transform matrix

I have in an e-book a title page formatted with SVG, using textPath to place text along a curve:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 160 256" width="160" height="256">
<g style="text-align:center;text-anchor:middle;stroke:none;stroke-width:0;">
<path style="fill:none;"
d="m 0,72 c 32,-16 52,-20 80,-20 28,0 48,4 80,20"
id="path-upper" />
<text style="font-size:9px;"><textPath xlink:href="#path-upper" startOffset="50%"><tspan>Text to be Placed Along a Curve</tspan></textPath></text>
</g>
</svg>
The trouble is that many e-book platforms (most importantly the Kindle) do not support textPath. What I’d like to do is “compile out” the results of textPath into rotated text.
Running
$ inkscape -A curve.pdf --export-ignore-filters curve.svg
$ inkscape -l curve2.svg curve.pdf
does kinda work, yielding (for example)
<text transform="matrix(0.94068351,0.33928532,0.33928532,-0.94068351,17.864857,145.9156)"><tspan y="0" x="0">T</tspan></text>
<text transform="matrix(0.94997891,0.31231406,0.31231406,-0.94997891,20.665461,146.93493)"><tspan y="0" x="0">e</tspan></text>
<text transform="matrix(0.96048875,0.27831882,0.27831882,-0.96048875,24.497618,148.19598)"><tspan y="0" x="0">x</tspan></text>
<text transform="matrix(0.96875188,0.24803186,0.24803186,-0.96875188,28.337099,149.29823)"><tspan y="0" x="0">t</tspan></text>
but it also rewrites the rest of my SVG file—most annoyingly, adding a global transform (transform="matrix(1.3333333,0,0,-1.3333333,0,256)") which makes everything harder to read and understand.
Is there another tool or bit of code I can use to programmatically generate these rotation matrices from the path?
(Otherwise, what I need is a tool that combines the transform matrices within the SVG file after Inkscape has mangled things, but that’s a different question.)

Is it possible to check the code of a vector design?

I understand that all vector drawings (even others) are made of codes. I was wondering if its possible to check the code of the same. For instance, if I have a rectangle in .svg or .eps format, how do I check the code that makes this rectangle ?
Try opening it in a text editor?
For instance, this image should look like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 100 100">
<title>SVG Logo</title>
<a xlink:href="http://www.w3.org/Graphics/SVG/" target="_parent"
xlink:title="W3C SVG Working Group home page">
<rect
id="background"
fill="#FF9900"
width="100"
height="100"
rx="4"
ry="4"/>
...

How to reuse <image> tags in SVG <defs>?

I have a situation where to save on memory and loading, I am trying to reuse a single <image> tag in an SVG, instead of referencing the same xlink:href in several <image> tags.
My research has shown that <use> is the tag to reference a defined object.
However, when I try to reference an image, particularly inside a pattern (which is what I am trying to do), I get nothing, where using an image tag works fine.
What am I doing wrong? Is this even possible? I tried searching, but could not find any examples of the <use> tag with an image, just rects, paths, groups, etc.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 1024 600" >
<style type="text/css">
.fillme{fill:url(#tsmall)}
</style>
<defs>
<image id="texture" xlink:href="texture.tiny.png" />
<pattern id="tsmall" patternUnits="userSpaceOnUse" width="486" height="402">
<use xlink:href="#texture" x="0" y="0" width="486" height="402" />
</pattern>
<pattern id="tlarge" patternUnits="userSpaceOnUse" width="972" height="804">
<use xlink:href="#texture" x="0" y="0" width="972" height="804" />
</pattern>
</defs>
<rect x="0" y="0" width="1024" height="600" class="fillme"/>
</svg>
SVG image elements must have width and height attributes, yours doesn't.
An image is a graphics element and if you point a <use> at a graphics element the <use> width and height are ignored per the SVG specification (since it's not a symbol or an svg element it falls into the Otherwise case in the specification)

Resources