I am using vips PHP library. I want to add svg path on my image. I implemented below code for that but it's not giving me expected output. The problem is how can I set svg path according to the actual image height & width. I tried using resize and thumbnail but it doesn't give me expected output. Also I want to fill the grey color on my actual image blocks like in expected output image.
The expected output image generated using imagick
$background = Vips\Image::newFromFile($arg[1], ['access' => 'sequential']);
$svg = Vips\Image::svgload_buffer('<svg>
<path
d="M0 200 v-200 h200
a100,100 90 0,1 0,200
a100,100 90 0,1 -200,0
z" stroke="#fff" fill="transparent"/>
</svg>');
// $svg = $svg->resize(2.5);
$svg = $svg->thumbnail_image(700, ['height' => 700, 'size' => 'both']);
$image = $background->composite($svg, 'dest-in');
$image->writeToFile([$arg2], ['background' => [128, 128, 128], 'Q' => 100]);
Below is the image on which I added my svg path
My vips output image
Expected output image
Try:
#!/usr/bin/php
<?php
require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;
$background = Vips\Image::newFromFile($argv[1], ['access' => 'sequential']);
$width = $background->width;
$height = $background->height;
$svg = Vips\Image::svgload_buffer(<<<EOF
<svg
viewBox="0 0 300 300"
width="$width"
height="$height">
<path
d="M0 200 v-200 h200
a100,100 90 0,1 0,200
a100,100 90 0,1 -200,0
z" stroke="#fff" fill="white"/>
</svg>
EOF);
$image = $background->colourspace('b-w')->composite($svg, 'dest-in');
$image->writeToFile($argv[2], ['background' => [128, 128, 128], 'Q' => 100]);
Associated github issue: https://github.com/libvips/php-vips/issues/109
Related
I was wondering why this D3 code just does not work:
...
console.log(data["SAT"]);
/************* Generic line definition ************/
var line = d3.line()
.x(d => xScale(d.x))
.y(d => yScale1(d.y));
/******************* SAT line *****************/
var SATPath = svg.append("g")
.attr("class", "SAT-curve")
.selectAll("path")
.data(data["SAT"])
.enter().append('path')
.attr("fill", "none")
.attr("stroke-width", 1.5)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("d", d => line(d))
.attr("stroke", colors.purple);
The console.log() line just shows data in apparently correct way:
[0 … 99]
0: {x: 0.0011, y: 178.75}
1: {x: 0.0011, y: 180.75}
...
94: {x: 0.0014, y: 366.75}
95: {x: 0.0014, y: 368.75}
96: {x: 0.0014, y: 370.75}
97: {x: 0.0014, y: 372.75}
98: {x: 0.0014, y: 374.75}
99: {x: 0.0015, y: 376.75}
[100 … 199]
[200 … 299]
[300 … 307]
length: 308
[[Prototype]]: Array(0)
... And all margin.*, xScale and yScale1 axes are correctly defined (or I think so) because they are correctly rendered.
The problem is that it generates all 308 paths with all attributes, EXCEPT the d one, and then the path results in 0x0 size:
<g class="SAT-curve">
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
....
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
</g>
No JS console errors.
Any ideas?
Thanks in advance.
The data() method binds one array element to one DOM element. That said, you don't want 308 paths, you want just one path with 308 data points. Therefore, wrap everything in an outer array, witch has just one element:
.data([data["SAT"]])
I have an SVG in my website which displays fine on Chrome but isn't visible on Safari and Mobile Safari.
Weirdly, if I copy and paste the SVG into a Codepen page then it works fine, so I'm not able to recreate the issue publicly.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="22" aria-hidden="true" focusable="false" role="img"><path fill="currentColor" d="M4.686 427.314L104 328l-32.922-31.029C55.958 281.851 66.666 256 88.048 256h112C213.303 256 224 266.745 224 280v112c0 21.382-25.803 32.09-40.922 16.971L152 376l-99.314 99.314c-6.248 6.248-16.379 6.248-22.627 0L4.686 449.941c-6.248-6.248-6.248-16.379 0-22.627zM443.314 84.686L344 184l32.922 31.029c15.12 15.12 4.412 40.971-16.97 40.971h-112C234.697 256 224 245.255 224 232V120c0-21.382 25.803-32.09 40.922-16.971L296 136l99.314-99.314c6.248-6.248 16.379-6.248 22.627 0l25.373 25.373c6.248 6.248 6.248 16.379 0 22.627z"></path></svg>
Setting height 100% as an attribute fixes the issue in Safari and doesn't make it the wrong size or aspect ratio.
What is going on here? Why does this work and is a safe fix? And also why is the issue not reproducible?
UPDATE: Ive now been able to recreate. Safari hides the SVG when it has a parent div with display: flex:
https://codepen.io/adsfdsfhdsafkhdsafjkdhafskjds/pen/yLPgaJx
<div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="22" aria-hidden="true" focusable="false" role="img"><path fill="currentColor" d="M4.686 427.314L104 328l-32.922-31.029C55.958 281.851 66.666 256 88.048 256h112C213.303 256 224 266.745 224 280v112c0 21.382-25.803 32.09-40.922 16.971L152 376l-99.314 99.314c-6.248 6.248-16.379 6.248-22.627 0L4.686 449.941c-6.248-6.248-6.248-16.379 0-22.627zM443.314 84.686L344 184l32.922 31.029c15.12 15.12 4.412 40.971-16.97 40.971h-112C234.697 256 224 245.255 224 232V120c0-21.382 25.803-32.09 40.922-16.971L296 136l99.314-99.314c6.248-6.248 16.379-6.248 22.627 0l25.373 25.373c6.248 6.248 6.248 16.379 0 22.627z"></path></svg>
</div>
If I set the container div to display: block or set a height on the SVG then it comes back.
As comments #Evanss
Also height auto doens't make the SVG appear, but height 100% does.
width="22" height="100%"
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="22" height="100%" aria-hidden="true" focusable="false" role="img" style="border:1px solid red">
<path fill="currentColor" d="M4.686 427.314L104 328l-32.922-31.029C55.958 281.851 66.666 256 88.048 256h112C213.303 256 224 266.745 224 280v112c0 21.382-25.803 32.09-40.922 16.971L152 376l-99.314 99.314c-6.248 6.248-16.379 6.248-22.627 0L4.686 449.941c-6.248-6.248-6.248-16.379 0-22.627zM443.314 84.686L344 184l32.922 31.029c15.12 15.12 4.412 40.971-16.97 40.971h-112C234.697 256 224 245.255 224 232V120c0-21.382 25.803-32.09 40.922-16.971L296 136l99.314-99.314c6.248-6.248 16.379-6.248 22.627 0l25.373 25.373c6.248 6.248 6.248 16.379 0 22.627z">
</path>
</svg>
The snippet above doesn't render the image correctly, but if you save the svg as a separate file and open it in a browser, you'll see exactly the same image.
In the image below, the red rectangle is the border of the svg canvas with width="22" and height="100%"
As you can see, with this SVG configuration, paddings are too large. What is unacceptable and will interfere with layout
Using JavaScript isnt idea as it may cause the page to flicker
Using the JavaScript method getBBox() in the snippet console allows you to find out the physical dimensions of the svg shape
In this case, JS is not involved in the SVG rendering process and is only a reference tool.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 32 448 512" width="22" height="100%" aria-hidden="true" focusable="false" role="img" style="border:1px solid red">
<path id="path" fill="currentColor" d="M4.686 427.314L104 328l-32.922-31.029C55.958 281.851 66.666 256 88.048 256h112C213.303 256 224 266.745 224 280v112c0 21.382-25.803 32.09-40.922 16.971L152 376l-99.314 99.314c-6.248 6.248-16.379 6.248-22.627 0L4.686 449.941c-6.248-6.248-6.248-16.379 0-22.627zM443.314 84.686L344 184l32.922 31.029c15.12 15.12 4.412 40.971-16.97 40.971h-112C234.697 256 224 245.255 224 232V120c0-21.382 25.803-32.09 40.922-16.971L296 136l99.314-99.314c6.248-6.248 16.379-6.248 22.627 0l25.373 25.373c6.248 6.248 6.248 16.379 0 22.627z">
</path>
</svg>
<script>
console.log(path.getBBox())
</script>
In the console, we can see the physical dimensions (dimensions that are given by the path of the svg shape)
"x": 0,
"y": 31.999996185302734,
"width": 448,
"height": 448
To move the image to the top left corner (this is the svgs origin) we set the value viewBox="0 32 448 448"` And to reduce the margin margins we set fixed values width="22" height="22"
Recommendations for creating and using icons
Setting both dimensions would be very time consuming as I have a lot
of icons with the same issue.
If you are using some unique icons created by a designer, then you cannot avoid the manual positioning and scaling process for each icon described above.
There is no universal solution for this case. It all depends on how the icon was drawn.
If the icon is simple, standard, then it is better to use icons drawn by professionals. There are many such resources on the web.
In this case, manual, additional processing is not required.
You can use google-fonts character font
Icons by name can be selected here
The name of your icon - Close `Fullscreen
Below is an example with minimal layout
span {
margin-left: 0.5em;
margin-top:0.5em;
transition: transform 1s ease-in-out;
}
span:hover {
transform: scale(2);
color:red;
}
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<span class="material-icons"> close_fullscreen </span>
You have the height of the SVG twice. In view styles hight="100%" and style="height: auto;"
safari doesn't know which style to prefer, how to scale the SVG, so it doesn't display the image.
Leave one style: width="22" height="auto"
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="22" height="auto" aria-hidden="true" focusable="false" role="img" style="border:1px solid red">
<path fill="currentColor" d="M4.686 427.314L104 328l-32.922-31.029C55.958 281.851 66.666 256 88.048 256h112C213.303 256 224 266.745 224 280v112c0 21.382-25.803 32.09-40.922 16.971L152 376l-99.314 99.314c-6.248 6.248-16.379 6.248-22.627 0L4.686 449.941c-6.248-6.248-6.248-16.379 0-22.627zM443.314 84.686L344 184l32.922 31.029c15.12 15.12 4.412 40.971-16.97 40.971h-112C234.697 256 224 245.255 224 232V120c0-21.382 25.803-32.09 40.922-16.971L296 136l99.314-99.314c6.248-6.248 16.379-6.248 22.627 0l25.373 25.373c6.248 6.248 6.248 16.379 0 22.627z">
</path>
</svg>
Update
Try setting the values of `viewBox="0 32 448 448" according to the dimensions shown by the JS method getBBox()
And also specify fixed width and height viewport width="22" height="22"
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 32 448 448" width="22" height="22" aria-hidden="true" focusable="false" role="img" style="border:1px solid red">
<path id="path" fill="currentColor" d="M4.686 427.314L104 328l-32.922-31.029C55.958 281.851 66.666 256 88.048 256h112C213.303 256 224 266.745 224 280v112c0 21.382-25.803 32.09-40.922 16.971L152 376l-99.314 99.314c-6.248 6.248-16.379 6.248-22.627 0L4.686 449.941c-6.248-6.248-6.248-16.379 0-22.627zM443.314 84.686L344 184l32.922 31.029c15.12 15.12 4.412 40.971-16.97 40.971h-112C234.697 256 224 245.255 224 232V120c0-21.382 25.803-32.09 40.922-16.971L296 136l99.314-99.314c6.248-6.248 16.379-6.248 22.627 0l25.373 25.373c6.248 6.248 6.248 16.379 0 22.627z">
</path>
</svg>
<script>
console.log(path.getBBox())
</script>
In my case, adding the svg attributes width="40" and height="auto" did the trick for Safari to show the svgs correctly:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 503.8 503.8" width="40" height="auto">
<style>.st0{fill:currentcolor}</style>
<path d="M251.9 45.4c67.3 0 75.3.2 101.8 1.5 24.6 1.1 37.9 5.2 46.8 8.6a79.6 79.6 0 0 1 29 18.9 78.2 78.2 0 0 1 18.8 28.9c3.5 8.9 7.6 22.3 8.7 46.8 1.2 26.6 1.5 34.6 1.5 101.8s-.3 75.3-1.5 101.8c-1.1 24.6-5.2 37.9-8.7 46.8a83.4 83.4 0 0 1-47.8 47.8c-8.9 3.5-22.2 7.6-46.8 8.7-26.5 1.2-34.5 1.5-101.8 1.5s-75.2-.3-101.8-1.5c-24.5-1.1-37.9-5.2-46.8-8.7a78.2 78.2 0 0 1-28.9-18.8 79.6 79.6 0 0 1-18.9-29c-3.4-8.9-7.5-22.2-8.6-46.8-1.3-26.5-1.5-34.5-1.5-101.8s.2-75.2 1.5-101.8c1.1-24.5 5.2-37.9 8.6-46.8a78.4 78.4 0 0 1 18.9-28.9 78.4 78.4 0 0 1 28.9-18.9c8.9-3.4 22.3-7.5 46.8-8.6 26.6-1.3 34.6-1.5 101.8-1.5m0-45.4c-68.4 0-77 .3-103.8 1.5S102.9 7 86.9 13.2a124.9 124.9 0 0 0-44.6 29.1 123.6 123.6 0 0 0-29.1 44.6c-6.2 16-10.5 34.3-11.7 61.2S0 183.5 0 251.9s.3 77 1.5 103.9 5.5 45.1 11.7 61.1a125.3 125.3 0 0 0 29.1 44.7 123.4 123.4 0 0 0 44.6 29c16 6.2 34.3 10.5 61.2 11.7s35.4 1.5 103.8 1.5 77-.2 103.9-1.5 45.1-5.5 61.1-11.7a128.6 128.6 0 0 0 73.7-73.7c6.2-16 10.5-34.3 11.7-61.1s1.5-35.5 1.5-103.9-.2-77-1.5-103.8-5.5-45.2-11.7-61.2a123.4 123.4 0 0 0-29-44.6 123.1 123.1 0 0 0-44.7-29.1c-16-6.2-34.3-10.5-61.1-11.7S320.3 0 251.9 0Z"></path>
<path d="M251.9 122.6a129.4 129.4 0 1 0 129.4 129.3 129.3 129.3 0 0 0-129.4-129.3Zm0 213.3a84 84 0 1 1 84-84 84 84 0 0 1-84 84Z"></path>
<circle cx="386.4" cy="117.4" r="30.2"></circle>
</svg>
I am attempting to produce an SVG image from the package RDKit. A minimum reproducable example:
from rdkit import Chem
from rdkit.Chem import Draw
img = Draw.MolsToGridImage([Chem.MolFromSmiles(x) for x in ['C', 'CO', 'CN']], useSVG = True)
print(img)
The output is below, but doesn't render any image in any browser or image viewer I have tried. Is this a valid SVG file, or is the package producing an invalid format? Or is there some other error I cannot see?
<?xml version='1.0' encoding='iso-8859-1'?>
<svg version='1.1' baseProfile='full'
xmlns='http://www.w3.org/2000/svg'
xmlns:rdkit='http://www.rdkit.org/xml'
xmlns:xlink='http://www.w3.org/1999/xlink'
xml:space='preserve'
width='600px' height='200px' >
<!-- END OF HEADER -->
<rect style='opacity:1.0;fill:#FFFFFF;stroke:none' width='600' height='200' x='0' y='0'> </rect>
<text x='0' y='200' style='font-size:0px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#000000' ><tspan>CH</tspan><tspan style='baseline-shift:sub;font-size:0px;'>4</tspan><tspan></tspan></text>
<path class='bond-0' d='M 200,200 200,200' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<path class='bond-0' d='M 200,200 200,200' style='fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<text x='200' y='200' style='font-size:0px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#FF0000' ><tspan>OH</tspan></text>
<path d='M 200,200 200,200 200,200 200,200 200,200' style='fill:none;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<path class='bond-0' d='M 400,200 400,200' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<path class='bond-0' d='M 400,200 400,200' style='fill:none;fill-rule:evenodd;stroke:#0000FF;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<text x='400' y='200' style='font-size:0px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#0000FF' ><tspan>NH</tspan><tspan style='baseline-shift:sub;font-size:0px;'>2</tspan><tspan></tspan></text>
<path d='M 400,200 400,200 400,200 400,200 400,200' style='fill:none;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
</svg>
RDKit is for an unknown reason producing SVG code which doesn't show anything. However, changing the list of molecules does result in SVG code which produces a visible image.
This works:
from rdkit import Chem
from rdkit.Chem import Draw
img = Draw.MolsToGridImage([Chem.MolFromSmiles(x) for x in ['C', 'CO', 'CN', 'CCC']], useSVG = True)
print(img)
A bug has been opened here: https://github.com/rdkit/rdkit/issues/2641
I can create a Polygon by:
#!/usr/bin/env python
from shapely.geometry import Polygon
area = Polygon(((52, 13), (57, 14), (58, 12)))
with open('test.svg', 'w') as f:
f.write(area.svg())
which returns
<path fill-rule="evenodd" fill="#66cc99" stroke="#555555" stroke-width="2.0" opacity="0.6" d="M 52.0,13.0 L 57.0,14.0 L 58.0,12.0 L 52.0,13.0 z" />
This is not a valid SVG file. How can I get a valid SVG?
I tried
#!/usr/bin/env python
from shapely.geometry import Polygon
area = Polygon(((52, 13), (57, 14), (58, 12)))
with open('test.svg', 'w') as f:
f.write('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">')
f.write(area.svg())
f.write('</svg>')
When I view this, the viewport is way to big for the polygon. Manually editing it with Inkscape and resizing it gives:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="test.svg"
width="7.9687681"
height="4.4396091">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1364"
id="namedview6"
showgrid="false"
inkscape:zoom="2.36"
inkscape:cx="-1.8038839"
inkscape:cy="-34.869627"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg2"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<path
d="m 0.19611614,2.3092357 4.99999996,1 1,-2 -5.99999996,1 z"
id="path4"
inkscape:connector-curvature="0"
style="opacity:0.6;fill:#66cc99;fill-rule:evenodd;stroke:#555555;stroke-width:2" />
</svg>
Is there a way to get this automatically?
try:
with open('test.svg', 'w') as f:
f.write(area._repr_svg_())
the BaseGeometry._repr_svg_ function is used for IPython/Jupyter integration, in order to render Shapely objects inline in Jupyter notebooks. Hence the "internal" naming, which is defined here:
http://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html
Effectively, it results in a valid SVG output.
You would need to specify the size and viewBox of the resulting image. For example:
#!/usr/bin/env python
from shapely.geometry import Polygon
import textwrap
area = Polygon(((52, 13), (57, 14), (58, 12)))
with open('test.svg', 'w') as f:
#specify margin in coordinate units
margin = 5
bbox = list(area.bounds)
bbox[0] -= margin
bbox[1] -= margin
bbox[2] += margin
bbox[3] += margin
width = bbox[2] - bbox[0]
height = bbox[3] - bbox[1]
#transform each coordinate unit into "scale" pixels
scale = 10
props = {
'version': '1.1',
'baseProfile': 'full',
'width': '{width:.0f}px'.format(width = width*scale),
'height': '{height:.0f}px'.format(height = height*scale),
'viewBox': '%.1f,%.1f,%.1f,%.1f' % (bbox[0], bbox[1], width, height),
'xmlns': 'http://www.w3.org/2000/svg',
'xmlns:ev': 'http://www.w3.org/2001/xml-events',
'xmlns:xlink': 'http://www.w3.org/1999/xlink'
}
f.write(textwrap.dedent(r'''
<?xml version="1.0" encoding="utf-8" ?>
<svg {attrs:s}>
{data:s}
</svg>
''').format(
attrs = ' '.join(['{key:s}="{val:s}"'.format(key = key, val = props[key]) for key in props]),
data = area.svg()
).strip())
I've got SVG image (code below):
<svg height="500" width="500">
<!-- Inner line -->
<path d="M100,50 L 100,100 A 45,45 0 1,0 150,150 L 200 150" style="stroke:#000; stroke-width:6; fill:none;" />
<!-- Outer line -->
<path d="M 90,50 L 90,92.5 A 54.5,54.5 0 0,0 90,197.5 L 90, 240.5" style="stroke:#000; stroke-width:1; fill:none;" />
<circle cx="105" cy="145" r="35" stroke="black" stroke-width="1" fill="green" />
I cannot see any pattern while drawing curved lines that are separated by the same margin (I've made the image above just by "guessing"). The number of lines is dynamic so I need a formula to count every M L A parameter. E.g. I can take inner line as static (showing just the d attribute),
d="M100,50 L 100,100 A 45,45 0 1,0 150,150 L 200 150"
but then first outer should be calculated somehow, to get d:
d="M 90,50 L 90,92.5 A 54.5,54.5 0 0,0 90,197.5 L 90, 240.5"
SVG arcs are drawn with A rx ry rotation large-arc-flag sweep-flag x y
The key parameters here are rx and ry: the radii of the arc and x and y which are the final point in the arc.
For example, if you have a circle centred on (cx, cy) with radius r, you can create and arc around it, d units from the edge of the circle with:
<path d="M cx cy+r+d A r+d r+d 0 0 0 cx+r+d cy" />
This arc will be in the lower, right quadrant because of where it starts (cx, cy+r+d) and ends (cx+r+d, cy).
So call the radius of the inner arc r and the radius of the outer arc r + d. Now we need to know where to start and stop the arc. The x-coordinate of the start and stop points is d units to the left of the cx. We can find the y-coordinate by using Pythagoras's theorem to calculate the height of the triangle with a hypotenuse of r+d and a base of d:
h = sqrt((r + d)^2 - d^2).
The code for the arc will therefore be:
d="M cx-d, 50 L cx-d, cy-h A r+d r+d 0 0 0 cx-d, cy+h L cx-d, 240"
For example, with (cx, cy) = (100, 150), r = 50, and d = 10
<path d="M100,50 L 100,100 A 50,50 0 1,0 150,150 L 200 150" style="stroke:#000; stroke-width:6; fill:none;" />
<path d="M 90,50 L 90,90.8 A 60,60 0 0,0 90,209.1 L 90, 240.5" style="stroke:#000; stroke-width:1; fill:none;" />
<circle cx="100" cy="150" r="40" stroke="black" stroke-width="1" fill="green" />
Does that make sense?