Editing the size of an SVG file - svg

<svg height="1000" width="977" xmlns="http://www.w3.org/2000/svg">
<path d="M0 841.743l185.535 -185.535l1.953 0q-66.402 -105.462 -66.402 -228.501 0 -177.723 124.992 -302.715t302.715 -124.992 302.715 124.992 124.992 302.715 -124.992 302.715 -302.715 124.992q-105.462 0 -197.253 -48.825l-193.347 193.347zm310.527 -415.012q0 98.627 70.308 167.958t167.958 69.332 167.958 -69.332 70.308 -167.958 -70.308 -167.958 -167.958 -69.332 -167.958 69.332 -70.308 167.958z"/>
</svg>
This svg will generate a search icon. It is written on the basis of 1000 hight and 977 width. If I change the width and the height it crops it and does not resize it. I would like to see a mathematical way or any tool online that can help me edit the code and resize it. I am using this on an HTML page and I know that I can just use css to resize it. However, I do not want to do that. I want to fix the svg file itself and resize it internally. Anyone has any idea on how to do that?

It's very simple.
Convert the width and height attributes to a viewBox. A viewBox will, for your purposes, take the form:
"0 0 <width> <height>"
so in this case it will become:
"0 0 977 1000"
Then set the width and height to appropriate values for the size icon you want. You will normally want them to keep the same ratio as the original values.
<svg width="97.7" height="100" viewBox="0 0 977 1000" xmlns="http://www.w3.org/2000/svg">
<path d="M0 841.743l185.535 -185.535l1.953 0q-66.402 -105.462 -66.402 -228.501 0 -177.723 124.992 -302.715t302.715 -124.992 302.715 124.992 124.992 302.715 -124.992 302.715 -302.715 124.992q-105.462 0 -197.253 -48.825l-193.347 193.347zm310.527 -415.012q0 98.627 70.308 167.958t167.958 69.332 167.958 -69.332 70.308 -167.958 -70.308 -167.958 -167.958 -69.332 -167.958 69.332 -70.308 167.958z"/>
</svg>

If you just want a free solution to reliably scale or make any other alterations to an SVG graphic, have you considered free and open-source Inkscape?
From its Debian package description:
Most of the common vector formats are supported, including PDF, Adobe
Illustrator and AutoCAD files, and it has unrivaled support for the
SVG web graphics standard.
Install
Available on Mac, Linux, Windows.
For Windows, you can try Inkscape Portable if you like portable apps.
On Linux, for example Debian-based distributions, you can:
$ sudo apt-get install inkscape
Inkscape
Using a text editor, save the SVG code you posted, to a file, name it for example graphic.svg.
Start Inkscape.
Ctrl+O to see the Open dialog
Browse and open graphic.svg.
Observe: In your case, your graphic resembles a black and white magnifying glass.
Click once on the graphic to select it.
Observe: Inkscape handlebars indicate you have selected the graphic.
Ctrl-shift-m to open Transform panel.
Scale tab.
It currently says:
Width: 976.500
Height: 999.936
Change unit drop-down to px.
Check mark Scale proportionally.
Let's say you want the width to be approximately 200 pixels wide:
Width: 200
Press tab to exit the Width entry.
Observe: due to Scale proportionally, the height: has automatically been re-calculated and updated to a new value 205.824
Apply.
Close the Transform panel.
Observe: it appears smaller than the canvas.
Ctrl-shift-d to open Document Properties.
Observe: it currently says:
Width: 977
Height: 1000.00
click Resize page to content
click Resize page to drawing or selection
Observe: it now says:
Width: 201.00
Height: 205.82
Close the Document Properties dialog.
Ctrl-shift-s to get Save As dialog.
name: graphic2.png
Bottom right drop-down menu,
Change Inkscape SVG (*.svg) to Plain SVG (*.svg).
Save
So now you have succesfully created a smaller version of your original graphic.
Reasons
Plain SVG (*.svg) is slightly smaller than the default Inkscape SVG (*.svg). 1.2K vs 2.1K
Further tweaks
If you look at the sizes:
graphic.svg 472b
graphic2.svg 1.2K
If minimizing file size is important to you, or for some reason you wish to eliminate all the additional meta tags that Inkscape provides, you can always use a text editor to assemble a final, smaller file, for example name it graphic3.svg.
For its opening SVG tag, borrow from your original code, but alter the width and height appropriately to the newer values. We saw earlier in Inkscape's Document Properties that the canvas was re-sized to:
Width: 201.00
Height: 205.82
So adapt this to the SVG attributes:
<svg height="206" width="201" xmlns="http://www.w3.org/2000/svg">
From graphic2.png, copy the <path ... > code.
End the file with a close SVG tag:
</svg>
Save, and now your new graphic3.png is about as small as your original graphic.svg

javascript:
function scaleSvgString(str, multiplicator){
var result_string="";
var current_number="";
for (var i = 0, len = str.length; i < len; i++) {
//means "is a number or a decimal separator"
if( (str[i].charCodeAt()>=48 && str[i].charCodeAt()<=57) || str[i].charCodeAt()==46){
current_number+=""+str[i];
}else{
if(current_number.length>0){
var scaled_number=Number(current_number)*multiplicator;
result_string+=""+scaled_number;
//reset number buffer
current_number="";
}
result_string+=""+str[i];
}
}
return result_string;
}
call it like
scaleSvgString("<svg> ... </svg>", 0.5);
i haven't actually tested it, i hope it works lol

You can do it dynamically with JavaScript.
The working code in the snippet below requires that you add an id to the svg path (or rect or g or whatever) that you want to just fill your desired area. You also have to change the desired width and height to whatever you want.
Pros:
You can re-use this routine for any shapes and any sizes you want.
All calculations are done for you.
You don't have to worry about aspect ratios, i.e. relative dimensions.
You don't have to do anything to the svg code (other than potentially adding an id to the target shape, as described above) for any image coming out of your favourite drawing program or downloaded from online.
You can re-use the same image with no internal modifications in different locations in your code, with each potentially being a different desired size.
You could potentially make a single svg file (e.g. allMyIconsInOnePlace.svg) containing multiple images you want used in different places, and then just use the code to target one particular shape for one particular use by changing the shpId in the code.
Cons:
Your stored svg code will be a little mis-leading, as the saved version won't contain the true information about its scaling which will only be determined at run-time.
This code will have to be included and run every time you want to use the image this way.
The only way to see the actual structure of the modified svg element would be at run-time, e.g., by using 'inspect element' in a browser debugger.
var shpId = "myShape";
var desiredWdth = 100;
var desiredHght = 60;
var shp = document.getElementById(shpId);
var svg = shp.ownerSVGElement;
var shpBBox = shp.getBBox();
var viewBoxStr =
shpBBox.x + " " +
shpBBox.y + " " +
shpBBox.width + " " +
shpBBox.height;
svg.setAttribute("viewBox", viewBoxStr);
svg.width .baseVal.value = desiredWdth;
svg.height.baseVal.value = desiredHght;
<svg height="1000" width="977" xmlns="http://www.w3.org/2000/svg">
<path id="myShape" d="M0 841.743l185.535 -185.535l1.953 0q-66.402 -105.462 -66.402 -228.501 0 -177.723 124.992 -302.715t302.715 -124.992 302.715 124.992 124.992 302.715 -124.992 302.715 -302.715 124.992q-105.462 0 -197.253 -48.825l-193.347 193.347zm310.527 -415.012q0 98.627 70.308 167.958t167.958 69.332 167.958 -69.332 70.308 -167.958 -70.308 -167.958 -167.958 -69.332 -167.958 69.332 -70.308 167.958z"/>
</svg>

Related

Unable to resize this svg file

My following svg file nicely displays the image (shown below) with 512x512 size. I want to convert it to a 32x32 size. But when I change the width and height attributes to 32x32 in the first line of the below file, the image does not even display. If I change it to, say, 100x100, only a portion of the image is displayed. Question: How can I generate a 32x32 size svg image from the following svg file. Or, if this is not possible, is there any other way of generating the image (shown below) as an svg file with size of 32x32?
MySvgFile.svg:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="512" height="512"><path d="M507.712 311.74c-7.903 0-13.493-0.757-16.772-2.27s-6.599-4.456-9.962-8.827l-62.298-89.284 39.85-57.757c3.363-4.54 7.945-8.66 13.746-12.358s15.343-5.549 28.627-5.549v-8.828h-68.855v8.828c5.549 0 9.878 1.387 12.989 4.161s4.666 5.843 4.666 9.206c0 1.177-0.084 2.312-0.252 3.405s-0.841 2.228-2.018 3.405l-33.293 48.93-37.832-55.74-1.135-1.387c0 0-0.378-0.967-1.135-2.9 0-2.354 1.598-4.456 4.792-6.305s7.567-2.774 13.115-2.774v-8.828h-80.205v8.828h4.54c7.735 0 13.536 0.673 17.403 2.018s6.894 3.699 9.080 7.062l53.47 79.952-46.66 69.108c-2.186 3.363-6.18 7.188-11.981 11.476s-15.932 6.432-30.392 6.432v8.827h16.413c-3.319 17.739-7.947 31.114-13.892 40.103-6.894 10.425-22.531 15.637-46.913 15.637h-37.833c-6.726 0-10.635-0.757-11.728-2.27s-1.639-4.456-1.639-8.827v-75.917h24.465c13.284 0 21.774 2.522 25.474 7.567s5.549 13.704 5.549 25.978h6.81v-75.665h-6.81c0 12.274-1.555 20.892-4.666 25.852s-11.896 7.44-26.357 7.44h-24.465v-69.108c0-4.372 0.547-7.315 1.639-8.827s5.002-2.27 11.728-2.27h35.563c22.195 0 36.445 4.287 42.75 12.863s10.635 22.868 12.989 42.877h6.558l-8.827-64.567h-129.294l-4.381-62.298h-175.795l-4.54 64.567h6.558c2.354-23.372 6.222-38.505 11.602-45.399s18.664-10.341 39.85-10.341h15.386c3.363 0 5.338 1.009 5.927 3.026s0.883 4.708 0.883 8.071v149.313c0 4.372-1.219 7.692-3.657 9.962s-10.888 3.405-25.348 3.405h-13.367v8.827h106.94v-8.827h-9.080c-14.46 0-22.868-1.135-25.221-3.405s-3.531-5.591-3.531-9.962v-149.313c0-3.363 0.168-5.759 0.504-7.188s1.597-2.732 3.784-3.91h15.638c21.186 0 34.469 3.447 39.85 10.341 5.202 6.666 8.907 21.058 11.123 43.129h-21.968v8.827h6.558c11.266 0 17.823 0.841 19.673 2.522s2.774 5.297 2.774 10.845v149.313c0 5.549-0.925 9.164-2.774 10.846s-8.407 2.522-19.673 2.522h-6.558v8.827h164.697l9.763-64.567h48.247v-8.827c-6.726 0-11.392-1.682-13.998-5.045s-3.909-6.137-3.909-8.323c0-1.177 0.084-2.312 0.252-3.405s0.841-2.228 2.017-3.405l40.103-60.028 44.39 69.107c0 1.009 0.378 1.598 1.135 1.765l1.135 0.252c0 2.354-1.555 4.456-4.666 6.305s-7.44 2.774-12.989 2.774v8.827h79.952v-8.827h-4.288z"></path></svg>
Image display of the above svg file:
Here is a codepen on how to do it, to add to my comment, viewBox does it all here. :)
https://codepen.io/kissu-the-styleful/pen/yLaQwOq
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
EDIT: Great website to understand viewBox a bit more !
https://wattenberger.com/guide/scaling-svg

Convert SVG Image to Path - to use with skrollr

I recently came across Skrollr, an interesting library to achieve a parallax effect. I am using it to control some opacities and would be ideal to make a 'path' ( provided as an SVG image - including coloring and stroke width etc - from the designers ).
I am hoping to animate a SVG image (path) as the user scrolls down as though the line is drawn. This is a nice example from skrollr which uses a similar effect as expected. The used example has a 'path', but what I have is an svg image - which I notice to have many paths. Skrollr seems to be needing an inline SVG path as it seems.
How can I get a similar effect as in the example specified. To get it, I will have to convert the given svg file in to some thing similar to ( from example ):-
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="900px" height="1200px">
<path
style="fill:none;stroke:#333333;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6000;stroke-dashoffset:0"
data-0="stroke-dashoffset:6000;" data-end="stroke-dashoffset:0;"
d="m 199.16266,227.29566 c 0,0 -35.71429,-184.285714 37.14286,-210.000004 72.85714,-25.7142792 95.40137,3.16127 134.28572,42.85715 C 462.01038,153.47988 433.14019,231.62843 612.01981,188.72422 740.78435,157.8401 648.46996,-124.25341 423.44838,73.009946 397.57737,95.689556 342.01981,227.29566 322.01981,268.72423 c -20,41.42857 -15.71429,142.85714 64.28571,222.85714 80,80 143.73919,-10.78923 207.14286,17.14286 89.11717,39.26002 175.71428,70 214.28571,198.57143 38.57143,128.57142 -224.28571,45.71428 -311.42857,50 -87.14286,4.28571 -174.7636,-13.7114 -273.33504,69.14573 -98.57143,82.85724 -123.427376,147.71354 -133.893126,125.93684 -13.988987,-29.1077 -55.031934,-20.6196 -72.436974,2.587 -35.52138,47.36187 48.898892,49.25187 59.501803,81.06057 11.228801,33.6863 -55.491303,91.6685 -70.7122836,61.2265 -14.3563298,-28.7127 55.6559746,-11.2104 68.9875946,-11.2104 59.313946,0 106.207266,-47.3062 135.388156,-93.99577 9.07249,-14.516 16.34065,-34.5597 6.03641,-50.0161 -24.31744,-36.4761 -61.10674,32.1704 -64.67586,50.0161 -1.78804,8.94027 -18.73345,93.13327 -18.9716,93.13327 -15.39093,0 28.03002,-116.70147 77.61105,-83.6473 22.80402,15.2025 -31.82409,33.8676 -43.11725,31.0443 -2.54514,-0.6362 -14.1213,-7.4374 -16.38456,-5.174 -1.98676,1.9867 9.07416,13.8365 10.34816,16.3845 2.87494,5.7499 10.51739,15.8661 17.24688,18.1092 69.57702,23.1924 68.47583,-63.69675 106.93079,-50.8783 25.47788,8.4926 17.93869,61.2265 13.79751,61.2265 -4.54633,0 1.86112,-32.5889 2.58704,-36.2185 1.63481,-8.1741 -8.336,-25.008 0,-25.008 23.1702,0 56.38131,-4.3117 84.50982,-4.3117 6.92267,0 20.69627,8.6474 20.69627,1.7246 0,-22.13767 -106.83933,7.883 -73.29932,52.6031 15.39517,20.5269 45.97363,7.0247 56.91476,-11.2104 4.27342,-7.1224 5.92963,-41.2859 6.03643,-41.3927 3.30032,-3.3003 25.38957,-5.1906 31.04441,-7.7611 8.17799,-3.71727 116.56888,-61.61957 80.19809,-70.71237 -62.06519,-15.5162 -84.81857,132.80117 -47.42898,132.80117 39.83429,0 168.06934,-127.94377 127.62705,-141.42457 -48.77358,-16.2579 -78.2302,99.41297 -51.74069,125.90247 20.35735,20.3573 58.34681,-22.9907 73.29932,-37.9432 37.20757,-37.20767 16.38455,62.9731 16.38455,52.603 0,-50.488 -2.86125,-72.28997 41.39257,-61.2265 18.42188,4.6055 41.59056,-2.80515 61.22649,0 33.65343,4.8077 18.48038,96.0268 157.85652,147.0903"
/>
</svg>
Resources:
Image: https://gist.github.com/ziyan-junaideen/3f3ffc99d6812ff78717
Example: https://github.com/Prinzhorn/skrollr/blob/master/examples/path.html

getting text width in SVG prior to rendering

I want to put a rectangle around a text in SVG.
The height of the text is known to me (the font-size attribute of the text element). But the width is dependent on the actual content. Using getBBox() or getComputedTextLength() should work. But this only works after rendering.
Is there a way to specify that in an other way? For example defining the x and width attributes relative to other values? I didn't find anything like that in the SVG Spec.
Figuring where text ends presumably requires roughly the same underlying code path as the rendering itself implements - going through the width of each character based on the font and style, etc... As I am not aware the SVG standards define a method for directly getting this information without doing the actual full rendering, till such methods emerge or are reported here by others, the approach should be to render invisibly before doing the actual rendering.
You can do that in a hidden layer (z-index, opacity and stuff) or outside the visible viewport, whichever works best in experimentation. You just need to get the browser do the rendering to find out, so you render invisibly for that sake, then use getComputedTextLength()
I know this is old, but a few ideas:
If you can choose a mono-spaced font, you know your width by a simple constant multiplication with glyph count
If you are bound to proportional fonts, you can find an average glyph size, do the math as with mono-space, and leave enough padding. Alternatively you can fill the padding with text element textLength attribute. If the constant is chosen carefully, the results are not very displeasing.
EDIT: As matanster found it to be hacky
Predetermine glyph widths with getComputedTextLength() and build a lookup table. Downside is that it does not account for kerning, but if your cache size is not a problem, you can append glyph-pair widths to this lookup.
Going beyond that is to find some way to do server side rendering: Is there a way to perform server side rendering of SVG graphics using React?
It is possible using canvas with measureText():
// Get text width before rendering
const getTextWidth = (text, font) => {
const element = document.createElement('canvas');
const context = element.getContext('2d');
context.font = font;
return context.measureText(text).width;
}
// Demo
const font = '16px serif';
const text = 'My svg text';
const textWidth = getTextWidth(text, font);
document.body.innerHTML = `
<svg>
<text x="0" y="20" font="${font}">${text}</text>
<rect x="0" y="30" width="${textWidth}" height="4" fill="red" />
</svg>
`;
Adapted from https://stackoverflow.com/a/31305410/1657101

Raphael and preserveAspectRatio

With RaphaelJS, this command inserts an image:-
var myImg = paper.image('image.svg', 100, 100, 150,150);
and the SVG output is:-
<image x="100" y="100" width="150" height="150" preserveAspectRatio="none" href="image.svg"/>
Question: How do I directly access preserveAspectRatio attribute and change it to xMidYMid meet - if you examine myImg.attr(), it doesnt show this attribute.
The roundabout way is navigate the SVG DOM tree, and execute svgImg.setAttributeNS(null,"preserveAspectRatio" , "xMidYMid meet" );
Note: Only some images require none while the rest needs the xMidYMid meet tag. Hence I can't set this attribute on parent <svg>
Note2: Chrome doesn't support preserveAspectRatio with SVG images. Use FF or IE to test.
At the source code level, preserveAspectRatio is hardcoded to none
Answer The quickest way to change this:-;
myImg[0].preserveAspectRatio.baseVal.align = 6 (1 = off, 6 = xMidYMid)
myImg[0].preserveAspectRatio.baseVal.meetOrSlice = 1 (1 = meet, 2 = slice)
Update:- jQuery style:-
jQuery(myImg.node).prop('preserveAspectRatio').baseVal.align = 6 ;
jQuery(myImg.node).prop('preserveAspectRatio').baseVal.meetOrSlice = 1 ;
Raphael's docs for Element.node "Gives you a reference to the DOM object, so you can assign event handlers or just mess around. Note: Don’t mess with it."
You can call these parameters on the Raphael canvas as a whole.
First create SVG:
var paper = Raphael('content',xSize,ySize);
Place image in it:
paper.image('image.svg', 100, 100, 150,150);
Then change attributes of svg:
paper.canvas.setAttribute('preserveAspectRatio', 'xMidYMid meet');

SVG Text bounding box is different from browser to browser when using #font-face?

I am trying to place an SVG Text-element according to the width and height of the text by getting the bounding box using the getBBox() method.
If the text is using a websafe font, this works reasonably well across different browsers, but if the text is styled using #font-face and a custom webfont, then the width of the text is returned incorrectly in Firefox (Mac) and Safari (iOS).
It works perfectly in both Safari (Mac) and Chrome (Mac).
If the gray box has the same width as the text, then it works in that browser.
Does anybody have an idea on how to get the correct width of the text bounding box in all browsers?
The browser is calculating the bounding box before it has finished loading/applying #font-face, assuming you don't need IE, you can wrap your BBox calculation function inside a document.fonts.ready promise...
document.fonts.ready.then(() => const bbox = textEl.getBBox());
Here is an example at work that exhibits the problem and the fix:
const xmlns = "http://www.w3.org/2000/svg";
const correct = document.getElementById("correct");
const incorrect = document.getElementById("incorrect");
visualizeBBox(incorrect);
document.fonts.ready.then(()=> visualizeBBox(correct));
function visualizeBBox(el){
const bbox = el.getBBox();
const rect = document.createElementNS(xmlns, "rect");
for (prop in bbox) rect.setAttribute(prop, bbox[prop]);
document.querySelector("svg").appendChild(rect);
}
svg text {
font-family: 'Diplomata SC', serif;
}
svg rect {
stroke: red;
fill: none;
}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Diplomata+SC&display=swap" rel="stylesheet">
<svg xmlns="https://www.w3.org/2000/svg" width="600" height="400">
<text x="0" y="40" font-size="24" id="correct">Correct dimensions</text>
<text y="100" font-size="24" id="incorrect">Incorrect dimensions</text>
<svg>
Today I ran into similar issue. Duopixel is right that getBBox() might return momental metric which may be unexpected because external font hasn't been loaded yet and some standard font is used instead.
The problem in WebKit (tested in Chrome 24.0.1312.52 and 26.0.1389.0 canary) is that the browser defers external font loading until it is first effectively used anywhere on the page. So even if you wait for onreadystatechange to become "complete" you are not guaranteed to have font metrics ready when calling getBBox() - you may still be the first one rendering a text styled with external font, inserting it into the document and immediately calling getBBox() on it (my case).
My workaround instead of calling mySVGInitCode() directly I do:
$("body").append(
$("<div/>")
.attr("class", "force-external-font-loading")
.attr("style", "font-family: \"xkcd\";visibility:hidden;position:absolute")
.text("x")
);
setTimeout(function(){ mySVGInitCode() }, 100); // 100ms is just arbitrary waiting time which should be sufficient for fetching the external font on a fast network, anyone has a better solution?
As you can see I dynamically insert absolutely positioned styled piece of text to force external font loading (visibility:hidden is important here instead of display:none). Then I wait some time before I execute my SVG code which could potentially render something and then immediately ask for metrics.

Resources