SVG Stroke-Alignment

Hi all,

Problem: When I add an stroke as an outline to an svg image, even a small stroke say .5, it draws outside of the viewport. And thus the image looks cut off. I am currently setting up a UI where the end user can change the fill color and the stroke width and color of an image. So I need a strategy I can reliably employ.

it looks like the stroke is drawn on the outer edge of the image where 1/2 of the stroke is outside the path and 1/2 is inside. Is that correct?

How are others handling this stroke issue?

Strategies?

Thanks,
John…

Hello, it is correct and not an issue.

the frame of a rect or image has no logical width,

so a stroke width of 2 which runs over it would consume 1 on each sides.

Hi Miyako,

Maybe not a “technical” issue but it is an issue in that I am not sure how to handle it.

My images are of various non uniform shapes. I need them to be a uniform width and height preferably.

So…

How we you redraw the images so that the image maintained it’s correct size and allowed the stroke (say from .5 to 5)?

What approach can I take?

Thanks,
John…

: John FOSTER

I need them to be a uniform width and height preferably

how about you simply assign the same width and height?
you can use https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatiopreserveAspectRatio > to make the image “scale to fit”.

: John FOSTER

redraw the images so that the image maintained it’s correct size

that seems to contradict the former request.
if they come in all different shapes and sizes,
you can’t demand a uniform width and height,
and maintain their correct sizes at the same time.

reading back your original post,
it seems like you are drawing your shapes to the edge of the viewBox.

if you know by calculation the left, top, right, bottom most coordinates of your shape,
you could make the viewBox larger than the width/height of the svg.

this will effectively scale down the image.

Hi Miyako,

I was trying to say (weirdly) that the images are complex paths and not circles, squares, or rects. That they do have different size dimensions (some are 25x25, 25x27, 647x845, etc.) although I am toying with the idea of uniform dimensions.

OK, so I tried preserveAspectRatio=“xMidYMid” and hat doesn’t seem to work.

I am using PROCESS 4D TAGS with the code (not that it should matter).

Does this code fragment look correct?

John…

Hi Miyako,

I tried something similar and it partially worked. I might’ve been doing something wrong.

I’ll play with it again and see

Thanks,
John…

Hi Miyako,

No luck.

If I look at the images in Sketch I can see that what I need is to be able to set a property for the stroke to draw “inside”. If I could do that it would be perfect! But it looks like the rendering engine always uses a “center” offset and thus half drawn on the outer and half drawn on the inner.

But alas I don’t think the rendering engine supports this attribute.

I have played with the viewport and tried various offsets but the only time the viewport and the image are the same size is when there is no stroke. Otherwise either clipped or leaves extra margin.

If you want to play with it create an image, say the letter “M”, with a width of 256 and height of 300, as a path in an svg image. Then increase the size of the stroke (.5, 1, 5, 10…) and see if you can keep the entire image within the 256 by 300 viewport without being clipped or without shrinking leaving extra margin around the image.

There must be a way to do it?

Anyone,
John…

like?
<code 4D>
$rectRef:=SVG_New_rect ($svgRef;0-($strokeWidth_L/2);0-($strokeWidth_L/2);$rectWidth_L-($strokeWidth_L/2); rectWidth_L-($strokeWidth_L/2);-1;-1;$strokeColorName;$fillColorName;$strokeWidth_L)
</code 4D>

Ortwin,

The images are not rects. Otherwise I would know how to handle.

They are image made of various paths. For example, (knowing you are a Sketch man) if you create an image in Sketch of the letter “M” and fill it with a color, save it as an svg and then open in 4D, and then apply a stroke you will see what I mean.

I have almost 100 images that I need to modify using the images I created in Sketch, modified in a text editor to use tags, and then I dynamically change the fill color, etc.

I want to be able to apply a stroke and apply a color to the stroke. That works! BUT…

The new image will with a stroke width of 1 or more will cause the image to be clipped.

Here are three images:

1st image has no stroke - see how the image hugs the bounding box?

[]21224888;“Your comment here…”[/]

2nd image has no stroke - see how stroke straddles the bounding box?

[]21224899;“Your comment here…”[/]

3rd image has no stroke - see how stroke straddles the bounding box?

[]21224905;“Your comment here…”[/]

What I want is no straddling? The new image with stroke inside the viewport which happens to be the same size as the image.

Haven’t figured it out yet?

Thanks,
John…

if you draw an entity at coordinate 0 (x or y), that is the expected result. you can not complain.

you must either make the viewBox larger than the image or the image smaller than the viewBox.

Hi Miyako,

Not complaining? Trying to figure out how to get it working.

I have tried to make the viewbox larger and smaller. But perhaps I am missing or misunderstanding something.

I have changed the x/y coordinate of the viewbox so that x/y is the width of the stroke. I have tried also adding to the viewport width and height. But the only time it fist within the viewport is when stroke width is 0.

Anyway, there’s no complaining ONLY hoping that someone might see the error in my thinking. And example form 4D would be perfect! I suppose I could use my partnership and submit a ticket. But seems like such a basic thing.

JOhn…

perhaps you can look at it this way:

what you call “stroke” is not the same as the concept of “stroke” in SVG.

anyway, the viewBox method will scale down the image, and offsetting the image by half the stroke width won’t work if the image touches the border on its opposite side.

I think the only way to “stroke inside the image” is to draw a second image on top of it.

it’s just how SVG works. sorry for that.

Hi Miyako,

Ref: “I think the only way to “stroke inside the image” is to draw a second image on top of it.”

Seems really complicated as I would have to read the path and offset the move lines to codes.

OK, maybe I’ll just not allow outlines just fills.

Thanks,
John…

have you used attribute “stroke-alignment” with value “inner”?
using http://livedoc.4d.com/4D-SVG-Component-16-R4/Attributes/SVG-SET-ATTRIBUTES.301-3454816.en.htmlSVG_SET_ATTRIBUTES> which uses
<code 4D>
DOM SET XML ATTRIBUTE($Txt_objectID;$Txt_attribut;$Txt_value)
</code 4D>
http://dddd.mettre.de/wp/from-sourcecode-to-documentation/#english?foruminternally>

If that doesn’t help, the 4D SVG renderer doesn’t support that feature, I suppose.

seems like “stroke-alignment” is not an SVG 1.1 specification

https://www.w3.org/TR/svg-strokes/#SpecifyingStrokeAlignment

see also

https://stackoverflow.com/questions/7241393/can-you-control-how-an-svgs-stroke-width-is-drawn

Hi,

it looks like the stroke is drawn on the outer edge of the image where 1/2 of the stroke is outside the path and 1/2 is inside. Is that correct?
Yes it is the correct behavior; if you do not want stroke to be clipped you need to leave enough space around the path like strokewith/2 + about 2 or 3 pixels to take account the antialiasing which may overflow the strict stroke width*0.5 (assuming there is no other transform applied to the path with may scale up the shape).
You can do it by defining a viewBox large enough to contain the shape including the stroke so there is enough space around the shape (like a viewbox with width and height set to shape expected width and height + stroke width+4px for instance; also decal shape with a translate transform of decal = (stroke width+4px)*0.5 for x and y so it leaves actually (stroke width+4px)*0.5 spacing around the shape inside the viewBox)

Also, stroke-alignment is not supported by 4D SVG renderer.

Regards,

Jacques.

Hi Ortwin,

Yes, that’s what I was trying to use initially I think the rendering engine just ignores the attribute.

I pent many hours researching the issue and came across the svg spec. But this attribute was in the spec and then they took it out and then I think I saw it in the spec again. There were implementation issues.

Sketch handles it quite nicely and allows one to set the “inner” attribute for a stroke. But if you save that image and open it in the SVG Viewer the image reverts to what I call straddling. Of course it really only matters when the image touches the bounding box. Otherwise it works great.

Anyway, appreciate,
John…

Hi Jacques,

Yes I agree that the rendering engine is handling it correctly.

I have tried something similar but the image always transform in uneven way. for example:

I have an image of width=525 and Height=598 with a stroke-width=0" - 4D dynamically changes it as follows:

<svg xmlns=“http://www.w3.org/2000/svg” height=“598 px” preserveAspectRatio=“xMinYMin” version=“1.1” viewBox=“0 0 525 598" viewport-fill=“white” viewport-fill-opacity=“1” width=“525 px”>

[]21234803;“Your comment here…”[/]

Changing stroke-width=15 -> viewBox=“0 0 540 613"

[]21234810;“Your comment here…”[/]

So changing it with offsets similar to your suggestion plus offsetting origin:

Changing stroke-width=15
W:= 525+15+3 = 544
H:= 598 +15+1 = 617
origin X = (15/2)-1
origin Y = (15/2)
-1

Changing stroke-width=15 -> viewBox=“-7 -7 542 613"

[]21234814;“Your comment here…”[/]

So this is pretty close.

Now I need to either start all my shapes at approx. the same width/height OR figure out how to convert these into some math formula where it even works on a 25x25 image (a stroke of 5 would overtake the image in 4D rendering).

Anyway, thanks for the idea. Maybe a negative origin is not a bad thing as I originally thought in my testing.

Appreciate,
John…