I've been trying to create a special random pattern for some time. For example random black dots, like this:
https://picload.org/thumbnail/riogwpll/pattern2.jpg
However, I need a much larger image with about 100,000 points / circles. In principle, no problem, however, the SVG with several MB then becomes too large to open it, for example, with Inkscape, because each circle is drawn individually. Any ideas how this could be realize better resulting in a smaller file. I have already tried something with pattern. Problem is that it should be a truly random, non-repeating pattern.
It's not necessary to do this with dots it could also look like this:
[enter image description here][1]
https://picload.org/thumbnail/riogwwdr/pattern1.jpg
For ideas / suggestions, I am grateful.
Is it something like this that you are after?
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="600" height="600">
<defs>
<filter id="dots" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%" color-interpolation-filters="sRGB">
<feTurbulence baseFrequency=".1" numOctaves="1" seed="42" />
<feColorMatrix type="saturate" values="0"/>
<feGaussianBlur result="blur" stdDeviation="2" />
<feComponentTransfer>
<feFuncA type="discrete" tableValues="0 1 1 1 1"/>
</feComponentTransfer>
</filter>
</defs>
<rect x="0" y="0" width="600" height="600" style="fill:#888; stroke:#bbd; stroke-width:2px; filter: url(#dots)" />
</svg>
How this works:
<feTurbulence baseFrequency=".1" numOctaves="1" seed="42" /> generates some random noise. Remove the seed attribute if you want a different pattern each time.
<feColorMatrix type="saturate" values="0"/> converts the noise to greyscale.
<feGaussianBlur result="blur" stdDeviation="2" /> blurs the noisey pattern so that the dots merge together a little. Experiment with this value to vary the "blobbiness".
<feComponentTransfer> thresholds the grey values to either black or white.
Related
I am trying to apply a Vignette effect on images with SVG filters. I am trying to implement this with the <fePointLight> primitive, but I find this a bit limited in that it is always has a circular shape. Is it possible to change the width such that the lighting effect takes on a wide elliptical shape? This is currently the filter I am using:
<filter id="vignette">
<feFlood id="flood-5" result="blackfield-6" x="0%" y="0%" width="100%" height="100%" flood-color="#000000" flood-opacity="1"/>
<feSpecularLighting id="specular-5" result="Spotlight-6" lighting-color="#FFFFFF" surfaceScale="1" specularConstant="1" specularExponent="100">
<fePointLight id="pointlight-5" x="720" y="450" z="1200"/>
</feSpecularLighting>
<feBlend id="svg-7" result="A-6" in="blackfield-6" in2="Spotlight-6" mode="lighten"/>
<feBlend id="blend-5" result="B-6" in="A-6" in2="SourceGraphic" mode="multiply"/>
</filter>
I am aware that it is possible to do this with a radial gradient effect on a separate shape, but I have a requirement that it must be done purely using SVG filters.
The values of the x=350 and y=240 attributes of the fePointLight filter are chosen so that the point is in the center of the image.
Different values for the z attribute of the fePointLight filter render the light source at different depths in relation to the drawing. The nearest position corresponds to the largest size.
Please watch in full screen
Hover over image
#img {
width:700px;
height:481px;
}
#img:hover {
filter:url(#spotlight);
}
<img id="img" src="https://i.stack.imgur.com/mBuDo.jpg" >
<svg width="700" height="481" viewBox="0 0 700 481" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id="spotlight">
<feSpecularLighting result="spotlight" specularConstant="3.5"
specularExponent="70" lighting-color="grey">
<fePointLight x="350" y="240" z="520"/>
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="spotlight" operator="in"/>
</filter>
</defs>
</svg>
Other image
#img {
width:700px;
height:481px;
}
#img:hover {
filter:url(#spotlight);
}
<img id="img" src="https://i.stack.imgur.com/GlhkD.jpg" >
<svg width="700" height="481" viewBox="0 0 700 481" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id="spotlight">
<feSpecularLighting result="spotlight" specularConstant="3.5"
specularExponent="70" lighting-color="grey">
<fePointLight x="350" y="240" z="520"/>
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="spotlight" operator="in"/>
</filter>
</defs>
If you want that sort of effect (elliptical light), you probably want to be using a spotlight rather than a point light.
If you offset the light position to one side and shine the cone down at a shallow-ish angle, you will get an elliptical spot.
<svg width="600" height="529">
<defs>
<filter id="spotlight">
<feSpecularLighting result="spotlight" specularConstant="1.5"
specularExponent="4" lighting-color="#FFF">
<feSpotLight x="-200" y="265" z="400" limitingConeAngle="10" pointsAtX="300" pointsAtY="265" />
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="spotlight" operator="out" k1="0" k2="1" k3="1" k4="0"/>
</filter>
</defs>
<rect x="0" y="0" width="600" height="529" style="fill: skyblue; filter:url(#spotlight);"/>
</svg>
Note that the lighting filter components can be unreliable to use. Each browser has differences in interpretation of the standard. Not to mention some bugs.
A point in case is the above example, which looks different in Firefox and Chrome.
But good luck with your project.
I have an SVG which includes a PNG image using <image>. This included image is a pixel art and I would like it to show pixelated.
But instead it is showing blurry.
Can I change the display so it is pixelated?
Minimal test case:
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image
width="100"
height="100"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAIAAAB7QOjdAAAAD0lEQVR4AWP48OotAwMDAA3tAsiMG69RAAAAAElFTkSuQmCC"
/>
</svg>
Inside is a PNG with dimensions two pixels wide and one pixel tall.
Here is how it displayed on macOS 12.1 (21C52) / Safari 15.2 (17612.3.6.1.6).
But I want it to look like this:
Styling the <image> element with image-rendering: pixelated achieves the desired result:
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image style="image-rendering: pixelated;" width="100" height="100" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAIAAAB7QOjdAAAAD0lEQVR4AWP48OotAwMDAA3tAsiMG69RAAAAAElFTkSuQmCC" />
</svg>
The image-rendering CSS property sets an image scaling algorithm. The property applies to an element itself, to any images set in its other properties, and to its descendants.
— MDN Web Docs: Image Rendering
Note, this doesn't appear to render correctly in Safari.
Well the right way would be to use image-rendering: pixelated - but that's not supported on Safari yet.
Until then - this filter will work on black and white pixel art - transforming all RG & B values between 0 and 127 -> 0 and all values from 128 to 255 -> 255. (If you have scaled up anti-aliasing that you want to squash, you should add another <feFuncA type="discrete" tableValues="0 1"/> to that list of feFunc's in the filter).
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" color-interpolation-filters="sRGB">
<defs>
<filter id="crispen">
<feComponentTransfer>
<feFuncR type="discrete" tableValues="0 1"/>
<feFuncG type="discrete" tableValues="0 1"/>
<feFuncB type="discrete" tableValues="0 1"/>
</feComponentTransfer>
</filter>
</defs>
<image
filter="url(#crispen)"
width="100"
height="100"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAIAAAB7QOjdAAAAD0lEQVR4AWP48OotAwMDAA3tAsiMG69RAAAAAElFTkSuQmCC"
/>
</svg>
You can also generalize this to duo-tone pixel art by specifying different arrays for tableValues. If your dark tones is rgb(40,60,70) and your light tone is rgb (250,200,180) then your feComponentTransfer would be:
<feComponentTransfer>
<feFuncR type="discrete" tableValues="0.156 .98"/>
<feFuncG type="discrete" tableValues="0.235 .784"/>
<feFuncB type="discrete" tableValues="0.274 .706"/>
</feComponentTransfer>
(e.g. - when you unitize the lower red value of 40 - you get 40/255 = .156)
Note that this only works when all the lower and upper RGB values are lower and higher than 127.5. For example, if your light tone is rgb(200,50,50) and your dark tone is (50,60,60) - then this will result in the wrong answer. In this case you have to create a longer (and more complex) tableValues array so that the source colors are converted to the right destination color.
I try to turn a precise shapes into a series of scatted dots that have a higher density in the middle of the source image.
Example: White Circle on Black Background → Messier 92 (sorry i hive not enough reputation to embed the image)
Consequently a shape other then a circle should still be recognizable. Here is the best I was able to do:
I would call such an effect a scatter filter. Please tell me if you have a better name.
<svg height='100' width='100'>
<filter id="cluster" filterUnits="userSpaceOnUse">
<feGaussianBlur in="SourceGraphic" result='blurred' stdDeviation="10" />
<feTurbulence type="turbulence" baseFrequency="9" numOctaves="4" result="turbulence" />
<feDisplacementMap in2="turbulence" in="blurred" scale="10" xChannelSelector="R" yChannelSelector="G" />
</filter>
<rect x='0' y='0' height='100' width='100' fill='black' />
<circle cx='50' cy='50' fill='white' r='30' filter='url(#cluster)' />
</svg>
It is basically a fancy blur. The results look better with increased scale in feDisplacementMap.
<svg height='100' width='100'>
<filter id="cluster" filterUnits="userSpaceOnUse">
<feGaussianBlur in="SourceGraphic" result='blurred' stdDeviation="10" />
<feTurbulence type="turbulence" baseFrequency="9" numOctaves="4" result="turbulence" />
<feDisplacementMap in2="turbulence" in="blurred" scale="50" xChannelSelector="R" yChannelSelector="G" />
</filter>
<rect x='0' y='0' height='100' width='100' fill='black' />
<circle cx='50' cy='50' fill='white' r='30' filter='url(#cluster)' />
</svg>
But that also displaces the image. Can I undo this? Or not do it in the first place? Maybe by using something other than feDisplacementMap?
The main problem with your filter is its very high baseFrequency - you need to dial that waaay down. And fractalNoise is better than turbulence as a feTurbulence type for a scatter filter. As long as your displacement map is centered at 0.5 of the channel, your image shouldn't be displaced in x/y on average. It's only a problem if you've got a bright or dark displacement map (which is not the case with feTurbulence). Finally - a higher displacement scale will give you the pointy look you're looking for - like so.
It can take a bunch of trial and error to get the exact look that you want. This is a link to a filter editor for shadows that might give you some ideas https://codepen.io/mullany/pen/sJopz
<svg height="220px" width="260px" viewBox="0 0 800 600">
<defs>
<filter id="scatter">
<feTurbulence baseFrequency=".2" type="fractalNoise" numOctaves="3"/>
<feDisplacementMap in="SourceGraphic" xChannelSelector="G" yChannelSelector="B" scale="300"/>
<feComposite operator="in" in2="finalMask"/>
</filter>
</defs>
<g filter="url(#scatter)">
<polyline points="10,10 10,300, 300,400" transform="translate(60 60)" fill="blue"/>
<polyline points="500,10 110,300, 300,400" transform="translate(260 60)" fill="red"/>
</g>
</svg>
Imagine we have a long list of instances (as an example, see just two such instances (INSTANCE1 and INSTANCE2) below) which all depend on some pre-defined #DEFINED_RECTANGLE_WHITE which does not contain stroke information in its definition.
As you can see, some of the instances will be scaled (see e.g. scale(1 2)). I am wondering what would be the best way of now stroking all of these instances (all should have same stroke-width, I do not want the strokes to be wider in any dimension on the scaled objects).
<use id="INSTANCE1"
xlink:href="#DEFINED_RECTANGLE_WHITE"
transform="rotate(90, 1, 1) translate(10,-400) scale(1 2)">
</use>
<use id="INSTANCE2"
xlink:href="#DEFINED_RECTANGLE_WHITE"
transform="translate(10,140)">
</use>
How to do this without SVG1.2 features?
Could you use a filter to create an outline effect? You would have to enclose your use elements in a group or another svg and apply the filter to that.
Also, the dilate operator can have undesired results, like the bevel effect in the last rotated rectangle.
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px" viewBox="0 0 100 100">
<defs>
<rect id="rectangle" width="10" height="10" fill="rgb(200,220,120)"/>
<filter id="outline">
<feMorphology operator="dilate" radius="4" result="result1"/>
<feFlood flood-color="rgb(51,51,51)" result="result2"/>
<feComposite in="result2" in2="result1" operator="in" result="result3"/>
<feComposite in="SourceGraphic" in2="result3"/>
</filter>
</defs>
<g filter="url(#outline)">
<use href="#rectangle" transform="translate(50,10) scale(4 1) rotate(90,1,1)"/>
<use href="#rectangle" transform="translate(40,30)"/>
<use href="#rectangle" transform="translate(20,50) scale(6 0.5)"/>
<use href="#rectangle" transform="translate(60,70) rotate(45,1,1)"/>
</g>
</svg>
edit : oh snap! #Kaiido posted exactly the same answer while I was writing mine. Sorry for stealing your thunder =(
Svg shapes other than text are affected by the shape-rendering attribute which can be set to the crispEdges value (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering). This value seems to turn anti-aliasing off.
But text is only affected by text-rendering. However, this does not provide the crispEdges value (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-rendering). Why? Is there another way to get non-anti-alias?
For really crisp edges, you can use a filter to posterize your text.
<svg width="400px" height="400px">
<defs>
<filter id="crispify">
<feComponentTransfer>
<feFuncA type="discrete" tableValues="0 1"/>
</feComponentTransfer>
</filter>
</defs>
<text filter="url(#crispify)" font-size="60" y="60" >Some crispy text</text>
</svg>