I am using opentype.js to extract glyphs from google font(Poppin). Currently It shows all the glyphs nicely. but i want only the character and numbers only. such as "A,B,C and 1,2,3 etc.
Is there any way to show only specific items from glyphs table?
thanks in advance
font.stringToGlyphs('ABC') or font.getPaths(chars, 0, 90, 100) would return only selected glyphs.
Use e.g font.stringToGlyphs() if you need to get glyph properties like sidebearings, unicode etc.
font.getPaths() will return path data (commands).
let preview = document.querySelector("#svgPreview");
let chars = "ABCD0123";
let output ='';
// opentype.js accepts woff, ttf and otf
let fontFile = "https://fonts.gstatic.com/s/poppins/v19/pxiByp8kv8JHgFVrLGT9Z1xlEw.woff";
opentype.load(fontFile, function (err, font) {
if (!err) {
//get glyphs as object
let glyphs = font.stringToGlyphs(chars);
console.log(glyphs)
//get glyphs pathdata for previewing
let paths = font.getPaths(chars, 0, 90, 100);
paths.forEach(function(path, i){
output +=path.toSVG(2)
});
preview.innerHTML = output;
let vb = preview.getBBox();
preview.setAttribute('viewBox',[0, 0, (vb.width+vb.x), 120].join(' ') )
console.log(paths);
} else {
console.log("Font could not be loaded: " + err);
}
});
<script src="https://cdn.jsdelivr.net/npm/opentype.js#latest/dist/opentype.min.js"></script>
<style>
svg{
border: 1px solid #ccc;
height:10em;
}
</style>
<svg id="svgPreview" viewBox="0 0 1000 100">
</svg>
I am trying to generate some SVG and allow users of my website to download these SVGs as PNGs.
After reading this I get all my external images included in the downloaded PNG.
Now I am trying to get the fonts on the PNG correct. This seems to answer that and so I added:
<defs>
<style type="text/css">
#font-face {
font-family: Parisienne;
src: url('data:application/font-woff;charset=utf-8;base64,.....')
}
</style>
</defs>
Where ..... is base64 encoded woff2 font. And then used it in text like so:
<text x="55" y="55" stroke="red" font-family="Parisienne">Blah</text>
The font gets displayed in the browser correctly (I haven't installed it on my OS), however it is still not included in the PNG.
Do I have to add some additional processing to the script I used from the first link?
Thanks.
--EDIT--
I have been asked for a complete example, here it is:
<svg id="generated-svg" class="generated-svg" width="300px" height="500px"
version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns-xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css">
#font-face {
font-family: Parisienne;
src: url('data:application/font-woff;charset=utf-8;base64,.....')
}
</style>
</defs>
<rect width="300" height="500" fill="#222"/>
<text x="55" y="55" stroke="red" font-family="Parisienne" font-size="20px">Test text</text>
</svg>
I haven't added the base64 encoded font as it's simply too big. But you can encode any font you like and replace the ....... I am using Parisienne.
Here is working jsfiddle with the actual font: https://jsfiddle.net/z8539err/
In my browser this is the output:
Whilst after using the download script above I would end up with:
I'm able to include the font in the png itself with the following code, give it a try
var svg = document.getElementById('generated-svg');
var svgData = new XMLSerializer().serializeToString( svg );
var canvas = document.createElement("canvas");
canvas.width = 300;
canvas.height = 500;
var ctx = canvas.getContext("2d");
//display image
var img = document.createElement( "img" );
img.setAttribute( "src", "data:image/svg+xml;base64," + btoa( svgData ) );
img.onload = function() {
ctx.drawImage( img, 0, 0 );
//image link
console.log( canvas.toDataURL( "image/png" ) );
//open image
window.location.href=canvas.toDataURL( "image/png" );
};
https://jsfiddle.net/user3839189/hutvL4ks/1/
A working proof of concept project on GitHub to address OP problem statement.
https://github.com/nirus/SVG-PNG-Convert
Built generic Javascript module that can be modified and used anywhere. Read the documentation. Give it a try!
I'm using use my own SVG icons and I'm trying to find the best way of using them.
I would like to keep the color but also adjust it if needed to match a theme or on when using hover.
I have tried using the following script which changes the following into an embedded SVG but as I load my scripts at the bottom of my HTML doc, I get a horrible jumping effect.
$(function(){
jQuery('img.svg').each(function(){
var $img = jQuery(this);
var imgID = $img.attr('id');
var imgClass = $img.attr('class');
var imgURL = $img.attr('src');
jQuery.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = jQuery(data).find('svg');
// Add replaced image's ID to the new SVG
if(typeof imgID !== 'undefined') {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if(typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http://validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// Check if the viewport is set, else we gonna set it if we can.
if(!$svg.attr('viewBox') && $svg.attr('height') && $svg.attr('width')) {
$svg.attr('viewBox', '0 0 ' + $svg.attr('height') + ' ' + $svg.attr('width'))
}
// Replace image with new SVG
$img.replaceWith($svg);
}, 'xml');
});
});
svg {width: 350px; height: 350px;}
svg path {fill: #000 !important;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img src="https://upload.wikimedia.org/wikipedia/commons/f/f8/Windows_logo_-_2012_%28red%29.svg" alt="Microsoft" width="350" />
I've then tried to embed the the SVG by copying the code from Illustrator but the only way I can edit the colours is if I delete them in the html doc as my css won't override them.
What is the best way while keeping them from jumping?
Inline SVGs would be best IMO.
Export your SVGs using Illustrator (if you have troubles, follow this excellent guide by Colin Lord).
Then remove the colors from your SVG code and set them only using CSS.
If you have trouble overriding your colors you can give your SVGs IDs for more specifity.
If you go down the embedded route (which is my preferred option) - you don't actually need the majority of the HTML that Illustrator usually throws out.
Here is an example of your SVG with the most minimal code, then you can just use CSS to change the colours how you wish :-)
svg {
width: 350px;
height: 350px;
}
svg path {
fill: #000;
transform-origin: 0 0;
transform: scale(3)
}
#svg3 path {
fill: turquoise;
}
#svg3:hover path {
fill: green;
}
<svg id="svg2">
<path d="m0,12.402,35.687-4.8602,0.0156,34.423-35.67,0.20313zm35.67,33.529,0.0277,34.453-35.67-4.9041-0.002-29.78zm4.3261-39.025,47.318-6.906,0,41.527-47.318,0.37565zm47.329,39.349-0.0111,41.34-47.318-6.6784-0.0663-34.739z" id="path4"/>
</svg>
<!-- Another exmaple below using CSS to change the colours -->
<svg id="svg3">
<path d="m0,12.402,35.687-4.8602,0.0156,34.423-35.67,0.20313zm35.67,33.529,0.0277,34.453-35.67-4.9041-0.002-29.78zm4.3261-39.025,47.318-6.906,0,41.527-47.318,0.37565zm47.329,39.349-0.0111,41.34-47.318-6.6784-0.0663-34.739z" id="path4"/>
</svg>
.player
{
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><line x1='1' y1='1' x2='9' y2='9' stroke='red'/><line x1='1' y1='9' x2='9' y2='1' stroke='red'/></svg>");
width: 100%;
height: 100%;
display: inline-block;
}
.one
{
fill: black;
}
.two
{
stroke: white;
}
Elements with the player class will have a background image that is an svg. If there are elements with both the player and the one or two class, is it possible to change the style of the svg if it's inlined like so? If not, how would I do a simple color change by having classes? Ideally, I wouldn't want to introduce any more markup in the html and prevent http accesses for such a small svg file.
As Douglas wrote, you can style only IMG elements with inline "src".
I use this technique:
Use common image with the path to your SVG:
<img src="my.svg" alt="">
Transform the "src" to inline style using JavaScript (jQuery):
$('img').each(function(){
var $img = jQuery(this);
var imgID = $img.attr('id');
var imgClass = $img.attr('class');
var imgURL = $img.attr('src');
jQuery.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = jQuery(data).find('svg');
// Add replaced image's ID to the new SVG
if(typeof imgID !== 'undefined') {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if(typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http://validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// Replace image with new SVG
$img.replaceWith($svg);
}, 'xml');
});
Style your SVG using CSS:
path {
fill: #f00;
}
Done.
In order to modify your SVG with CSS, you have to use inline SVG, you can't modify it with a class if you use it as a background-image to an element.
If you want to make your authoring look cleaned up you can use a server side script to push the SVG's markup to your page (such as PHP's file_get_contents()).
Since there's no way around this, just compress your SVG as much as possible (I like this tool, there's some other good ones on the source I attached) and then write your svg as cleanly as possible, it shouldn't be that bloated looking if it's a small file.
Source: https://css-tricks.com/using-svg/
Sorry I couldn't be the bearer of better news.
Is it possible to use an inline SVG definition in CSS?
I mean something like:
.my-class {
background-image: <svg>...</svg>;
}
Yes, it is possible. Try this:
body { background-image:
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='%23F00'/><stop offset='90%' stop-color='%23fcc'/> </linearGradient><rect fill='url(%23gradient)' x='0' y='0' width='100%' height='100%'/></svg>");
}
http://jsfiddle.net/6WAtQ/
(Note that the SVG content needs to be url-escaped for this to work, e.g. # gets replaced with %23.)
This works in IE 9 (which supports SVG). Data-URLs work in older versions of IE too (with limitations), but they don’t natively support SVG.
If any of you have been going crazy trying to use inline SVG as a background, the escaping suggestions above do not quite work. For one, it does not work in IE, and depending on the content of your SVG the technique will cause trouble in other browsers, like FF.
If you base64 encode the svg (not the entire url, just the svg tag and its contents! ) it works in all browsers. Here is the same jsfiddle example in base64: http://jsfiddle.net/vPA9z/3/
The CSS now looks like this:
body { background-image:
url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PGxpbmVhckdyYWRpZW50IGlkPSdncmFkaWVudCc+PHN0b3Agb2Zmc2V0PScxMCUnIHN0b3AtY29sb3I9JyNGMDAnLz48c3RvcCBvZmZzZXQ9JzkwJScgc3RvcC1jb2xvcj0nI2ZjYycvPiA8L2xpbmVhckdyYWRpZW50PjxyZWN0IGZpbGw9J3VybCgjZ3JhZGllbnQpJyB4PScwJyB5PScwJyB3aWR0aD0nMTAwJScgaGVpZ2h0PScxMDAlJy8+PC9zdmc+");
Remember to remove any URL escaping before converting to base64. In other words, the above example showed color='#fcc' converted to color='%23fcc', you should go back to #.
The reason why base64 works better is that it eliminates all the issues with single and double quotes and url escaping
If you are using JS, you can use window.btoa() to produce your base64 svg; and if it doesn't work (it might complain about invalid characters in the string), you can simply use https://www.base64encode.org/.
Example to set a div background:
var mySVG = "<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='#F00'/><stop offset='90%' stop-color='#fcc'/> </linearGradient><rect fill='url(#gradient)' x='0' y='0' width='100%' height='100%'/></svg>";
var mySVG64 = window.btoa(mySVG);
document.getElementById('myDiv').style.backgroundImage = "url('data:image/svg+xml;base64," + mySVG64 + "')";
html, body, #myDiv {
width: 100%;
height: 100%;
margin: 0;
}
<div id="myDiv"></div>
With JS you can generate SVGs on the fly, even changing its parameters.
One of the better articles on using SVG is here : http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/
My solution was https://yoksel.github.io/url-encoder/
You just simply insert your svg and getting back background-image code
For people who are still struggling, I managed to get this working on all modern browsers IE11 and up.
base64 was no option for me because I wanted to use SASS to generate SVG icons based on any given color. For example: #include svg_icon(heart, #FF0000); This way I can create a certain icon in any color, and only have to embed the SVG shape once in the CSS. (with base64 you'd have to embed the SVG in every single color you want to use)
There are three things you need be aware of:
URL ENCODE YOUR SVG
As others have suggested, you need to URL encode your entire SVG string for it to work in IE11. In my case, I left out the color values in fields such as fill="#00FF00" and stroke="#FF0000" and replaced them with a SASS variable fill="#{$color-rgb}" so these can be replaced with the color I want. You can use any online converter to URL encode the rest of the string. You'll end up with an SVG string like this:
%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20494.572%20494.572%27%20width%3D%27512%27%20height%3D%27512%27%3E%0A%20%20%3Cpath%20d%3D%27M257.063%200C127.136%200%2021.808%20105.33%2021.808%20235.266c0%2041.012%2010.535%2079.541%2028.973%20113.104L3.825%20464.586c345%2012.797%2041.813%2012.797%2015.467%200%2029.872-4.721%2041.813-12.797v158.184z%27%20fill%3D%27#{$color-rgb}%27%2F%3E%3C%2Fsvg%3E
OMIT THE UTF8 CHARSET IN THE DATA URL When creating your data URL, you need to leave out the charset for it to work in IE11.
NOT background-image: url( data:image/svg+xml;utf-8,%3Csvg%2....)
BUT background-image: url( data:image/svg+xml,%3Csvg%2....)
USE RGB() INSTEAD OF HEX colors Firefox does not like # in the SVG code. So you need to replace your color hex values with RGB ones.
NOT fill="#FF0000"
BUT fill="rgb(255,0,0)"
In my case I use SASS to convert a given hex to a valid rgb value. As pointed out in the comments, it's best to URL encode your RGB string as well (so comma becomes %2C)
#mixin svg_icon($id, $color) {
$color-rgb: "rgb(" + red($color) + "%2C" + green($color) + "%2C" + blue($color) + ")";
#if $id == heart {
background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20494.572%20494.572%27%20width%3D%27512%27%20height%3D%27512%27%3E%0A%20%20%3Cpath%20d%3D%27M257.063%200C127.136%200%2021.808%20105.33%2021.808%20235.266c0%204%27%20fill%3D%27#{$color-rgb}%27%2F%3E%3C%2Fsvg%3E');
}
}
I realize this might not be the best solution for very complex SVG's (inline SVG never is in that case), but for flat icons with only a couple of colors this really works great.
I was able to leave out an entire sprite bitmap and replace it with inline SVG in my CSS, which turned out to only be around 25kb after compression. So it's a great way to limit the amount of requests your site has to do, without bloating your CSS file.
On Mac/Linux, you can easily convert a SVG file to a base64 encoded value for CSS background attribute with this simple bash command:
echo "background: transparent url('data:image/svg+xml;base64,"$(openssl base64 < path/to/file.svg)"') no-repeat center center;"
Tested on Mac OS X.
This way you also avoid the URL escaping mess.
Remember that base64 encoding an SVG file increase its size, see css-tricks.com blog post.
I've forked a CodePen demo that had the same problem with embedding inline SVG into CSS. A solution that works with SCSS is to build a simple url-encoding function.
A string replacement function can be created from the built-in str-slice, str-index functions (see css-tricks, thanks to Hugo Giraudel).
Then, just replace %,<,>,",', with the %xxcodes:
#function svg-inline($string){
$result: str-replace($string, "<svg", "<svg xmlns='http://www.w3.org/2000/svg'");
$result: str-replace($result, '%', '%25');
$result: str-replace($result, '"', '%22');
$result: str-replace($result, "'", '%27');
$result: str-replace($result, ' ', '%20');
$result: str-replace($result, '<', '%3C');
$result: str-replace($result, '>', '%3E');
#return "data:image/svg+xml;utf8," + $result;
}
$mySVG: svg-inline("<svg>...</svg>");
html {
height: 100vh;
background: url($mySVG) 50% no-repeat;
}
There is also a image-inline helper function available in Compass, but since it is not supported in CodePen, this solution might probably be useful.
Demo on CodePen: http://codepen.io/terabaud/details/PZdaJo/
I found one solution for SVG. But it is work only for Webkit, I just want share my workaround with you. In my example is shown how to use SVG element from DOM as background through a filter (background-image: url('#glyph') is not working).
Features needed for this SVG icon render:
Applying SVG filter effects to HTML elements using CSS (IE and
Edge not supports)
feImage fragment load supporting (firefox not
supports)
.test {
/* background-image: url('#glyph');
background-size:100% 100%;*/
filter: url(#image);
height:100px;
width:100px;
}
.test:before {
display:block;
content:'';
color:transparent;
}
.test2{
width:100px;
height:100px;
}
.test2:before {
display:block;
content:'';
color:transparent;
filter: url(#image);
height:100px;
width:100px;
}
<svg style="height:0;width:0;" version="1.1" viewbox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="glyph">
<path id="heart" d="M100 34.976c0 8.434-3.635 16.019-9.423 21.274h0.048l-31.25 31.25c-3.125 3.125-6.25 6.25-9.375 6.25s-6.25-3.125-9.375-6.25l-31.202-31.25c-5.788-5.255-9.423-12.84-9.423-21.274 0-15.865 12.861-28.726 28.726-28.726 8.434 0 16.019 3.635 21.274 9.423 5.255-5.788 12.84-9.423 21.274-9.423 15.865 0 28.726 12.861 28.726 28.726z" fill="crimson"/>
</g>
<svg id="resized-glyph" x="0%" y="0%" width="24" height="24" viewBox="0 0 100 100" class="icon shape-codepen">
<use xlink:href="#glyph"></use>
</svg>
<filter id="image">
<feImage xlink:href="#resized-glyph" x="0%" y="0%" width="100%" height="100%" result="res"/>
<feComposite operator="over" in="res" in2="SourceGraphic"/>
</filter>
</defs>
</svg>
<div class="test">
</div>
<div class="test2">
</div>
One more solution, is use url encode
var container = document.querySelector(".container");
var svg = document.querySelector("svg");
var svgText = (new XMLSerializer()).serializeToString(svg);
container.style.backgroundImage = `url(data:image/svg+xml;utf8,${encodeURIComponent(svgText)})`;
.container{
height:50px;
width:250px;
display:block;
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
}
<svg height="100" width="500" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" />
</svg>
<div class="container"></div>
Inline SVG coming from 3rd party sources (like Google charts) may not contain XML namespace attribute (xmlns="http://www.w3.org/2000/svg") in SVG element (or maybe it's removed once SVG is rendered - neither browser inspector nor jQuery commands from browser console show the namespace in SVG element).
When you need to re-purpose these svg snippets for your other needs (background-image in CSS or img element in HTML) watch out for the missing namespace. Without the namespace browsers may refuse to display SVG (regardless of the encoding utf8 or base64).
If you're using postcss you can try the postcss-inline-svg plugin https://www.npmjs.com/package/postcss-inline-svg
.up {
background: svg-load('img/arrow-up.svg', fill: #000, stroke: #fff);
}
.down {
background: svg-load('img/arrow-down.svg', fill=#000, stroke=#fff);
}
Done programatically based on the approach taken by the already mentioned https://github.com/yoksel/url-encoder/ :
// Svg (string)
const hexagon = `
<svg
width="100"
height="20"
viewBox="0 0 100 20"
xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient
id="redyel"
gradientUnits="objectBoundingBox"
x1="0"
y1="0"
x2="1"
y2="1"
>
<stop offset="0%" stop-color="#ff0000" />
<stop offset="100%" stop-color="#ffff00" />
</linearGradient>
</defs>
<polygon
points="0,10 5,0 95,0 100,10 95,20 5,20"
fill="#eee"
stroke="url(#redyel)"
/>
</svg>
`
// svgToBackgroundImage
const symbols = /[%#()<>?[\\\]^`{|}]/g;
const newLine = /\r?\n/;
const notEmptyString = (str) => str.length;
const trim = (str) => str.trim();
const toOneLine = (str) =>
str.split(newLine).filter(notEmptyString).map(trim).join(" ");
function addNameSpace(svgString) {
if (svgString.indexOf(`http://www.w3.org/2000/svg`) < 0) {
svgString = svgString.replace(
/<svg/g,
`<svg xmlns="http://www.w3.org/2000/svg"`
);
}
return svgString;
}
function encodeSVG(svgString) {
svgString = svgString.replace(/>\s{1,}</g, `><`);
svgString = svgString.replace(/\s{2,}/g, ` `);
// Using encodeURIComponent() as replacement function
// allows to keep result code readable
return svgString.replace(symbols, encodeURIComponent);
}
const svgToBackgroundImage = (svgString) =>
`url('data:image/svg+xml,${encodeSVG(addNameSpace(toOneLine(svgString)))}')`;
// DOM
const element = document.querySelector("#hexagon");
element.style.backgroundImage = svgToBackgroundImage(hexagon);
#hexagon {
width: 100px;
height: 20px;
}
<div id="hexagon"/>
You can also just do this:
<svg viewBox="0 0 32 32">
<path d="M11.333 13.173c0-2.51 2.185-4.506 4.794-4.506 2.67 0 4.539 2.053 4.539 4.506 0 2.111-0.928 3.879-3.836 4.392v0.628c0 0.628-0.496 1.141-1.163 1.141s-1.163-0.513-1.163-1.141v-1.654c0-0.628 0.751-1.141 1.419-1.141 1.335 0 2.571-1.027 2.571-2.224 0-1.255-1.092-2.224-2.367-2.224-1.335 0-2.367 1.027-2.367 2.224 0 0.628-0.546 1.141-1.214 1.141s-1.214-0.513-1.214-1.141zM15.333 23.333c-0.347 0-0.679-0.143-0.936-0.404s-0.398-0.597-0.398-0.949 0.141-0.689 0.398-0.949c0.481-0.488 1.39-0.488 1.871 0 0.257 0.26 0.398 0.597 0.398 0.949s-0.141 0.689-0.398 0.949c-0.256 0.26-0.588 0.404-0.935 0.404zM16 26.951c-6.040 0-10.951-4.911-10.951-10.951s4.911-10.951 10.951-10.951c6.040 0 10.951 4.911 10.951 10.951s-4.911 10.951-10.951 10.951zM16 3.333c-6.984 0-12.667 5.683-12.667 12.667s5.683 12.667 12.667 12.667c6.984 0 12.667-5.683 12.667-12.667s-5.683-12.667-12.667-12.667z"></path>
</svg>