Outils pour utilisateurs

Outils du site


issue113:inkscape

Ceci est une ancienne révision du document !


A major feature of SVG filters is that they're dynamic. The calculations to produce the output aren't simply done once and then stored in the image – as is often the case with filters in bitmap editors. Rather, they're performed time and time again as you zoom, pan, rotate objects or otherwise modify your drawing. This gives you the flexibility to make changes to your filter parameters at any time, but all this recalculation takes its toll on Inkscape's rendering speed. So now that you're (hopefully) starting to create more and more complex filters, I'm going to begin this instalment by looking at a few ways to mitigate this slowdown.

When faced with a program that's slowing down due to too many calculations, there are two approaches that can be used to minimise the problem: reduce the number of calculations, or find some way to speed them up. Remembering that filters are applied on a per-pixel basis, just at the point of rendering the object, one way to reduce the number of calculations is to zoom out. An object viewed at a low zoom, which takes up 10×10 pixels on screen, occupies an area of 100 pixels. Even for the simplest of theoretical filters that means 100 calculations – but in practice it will be many more as, at the very least, there will likely need to be separate calculations for the red, green, blue and alpha channels. Zoom in so that the object fills 20×20 pixels – what we would colloquially consider to be “twice as big” – and the area grows by four times, to 400 pixels and therefore 400 calculations per channel. Zoom right in so that your small object almost fills your HD monitor and there's a lot of calculations to perform!

As well as avoiding large zooms, you can reduce the number of pixels to recalculate by simply resizing your Inkscape window. Does it really need to be full-sized to stretch to the whole width of your widescreen monitor? Try reducing the canvas size to something with a squarer aspect-ratio in the middle of your screen, with dialogs dragged out to floating windows at the sides.

Sometimes you don't really need to see the filtered version of an object if you just want to zoom in to tweak its shape. For those occasions, there's the View > Display Mode > No Filters option. There's also an option for viewing the Outline of objects only, which can be useful for finding elements you've lost through one of the myriad ways of making things invisible, but which doesn't really offer anything more in terms of dealing with slow filters. I mention it simply because there's also a Toggle option which cycles through all three modes – if you only do one thing today, learn the keyboard shortcut for it (CTRL-5 by default, where “5” is the key on the numeric keypad). The great thing about this is that you don't have to change modes before zooming – if you zoom in and the redraw is too slow, just press CTRL-5 to switch modes, abandoning the current redraw.

How about when you've finished tweaking a filtered object, at least for the time being? If you don't need to refer to it when working on other parts of the drawing, it's worth putting it into its own layer or sub-layer. Turn the layer visibility off, and there's nothing for Inkscape to re-calculate. If you do still want to see it, you can make a bitmap copy of the filtered object before you move the original to another layer. Select your object and use Edit > Make a Bitmap Copy (or press ALT-B): Inkscape will render a bitmap of your object, complete with filters applied, meaning that (once the original is hidden) it doesn't need to re-calculate the filters as you work on your document. When you've finished your drawing you can delete the bitmap version and re-display the hidden layer with your original content. The resolution of the bitmap copy is set in the Inkscape preferences – lower values will be created faster, but won't be as accurate when you zoom in closely. Usually this is fine, though, as the bitmap is generally there as a position or color reference, rather than needing to be a high-resolution representation of your object.

These methods reduce the amount of calculations that need to be performed, but there are also ways to speed up filter performance even when you need to have the original filtered objects visible. Within the Inkscape Preferences (File > Inkscape Preferences… on 0.48, Edit > Preferences on 0.91) there is a panel for adjusting the rendering of filters, labelled as “Filters” on 0.48 and “Rendering” on 0.91.

Within this panel you can set the number of threads that Inkscape uses for rendering Gaussian Blur filters (0.48), or filters in general (0.91). If you have a multi-core or hyper-threading processor in your machine, increasing this value to suit can speed up rendering. The usual recommendation is to set it to the number of cores minus 1. That, in theory, allows a single core to be used for the main Inkscape process, whilst using your remaining cores to render the filters. In practice there's a whole operating system between Inkscape and your cores, so although it's a useful guideline there's no guarantee that your OS will distribute the threads so neatly.

On 0.91 you can also set aside some memory in which to cache the results of your filter calculations. This should have an effect on things like panning – where an already calculated filter result is moved in and out of view – but it will likely have less effect if you zoom in and out, as the filters will need to be recalculated for each zoom level anyway. Nevertheless, if you have plenty of spare RAM it might be worth assigning a bit more to this option to help speed things up where possible.

Finally there are a couple of sets of radio buttons governing the trade-off between display quality and speed. Filters can be approximated by rendering at a lower resolution, giving a faster redraw but with less accuracy. The buttons here let you adjust that balance for filters in general, but also for Gaussian Blur in particular (since that tends to be the most commonly used filter primitive). Note that these radio buttons only affect the display of your image on screen – exporting to a PNG file always uses the highest possible quality.

Moving on from performance, and back to filters themselves, a small correction of the previous article: it seems that the Image primitive in 0.91 does let you use an SVG element from your drawing as its input, after all. The problem is that the element is included relative to the top left of the page – so if you try to include something that's located away from that corner, there's a good chance you'll only see empty space pulled into your filter (that's what led me to think it wasn't working at all). There are two possible solutions to this: draw your included SVG element at the top left of the page (you can put it onto a hidden layer if you don't want it to be visible there in the final image), or increase the size of the filter region until your included element is visible, then use an Offset primitive to move it to the right place. Neither of these are great options, in my opinion, but, of the two, I tend to prefer placing the included element (or a clone of it) at the top left corner, on a hidden layer, as the latter results in a larger filter area to calculate – and hence slows down rendering.

Another problem with this feature in 0.91 occurs if you try to use the same object both as a target of the filter chain, and as an input to the Image primitive. This is fairly easy to do by mistake, as the clumsiness of Inkscape's filter UI makes it likely that you'll lose track of what is selected and why, but the result is an instant crash of Inkscape, with no warning and no backup file saved. If you plan to use SVG objects as inputs to the Image primitive in 0.91 it's probably best to save your file just before you add the link.

A good use for the Image primitive is in conjunction with the Displacement Map filter. This replaces each individual output pixel with one taken from elsewhere in your image, so can be used to create various whorls, waves and distortions. It takes two inputs: the first is the image you want to distort, whilst the second is another image that acts as a “map” to tell the filter where to find each output pixel. The process is really quite simple when considered on a pixel-by-pixel basis, but soon becomes rather complex when you try to create a displacement map to perform a specific distortion.

To begin to understand this primitive, let's start with a most basic of chains:

As you can see, the first input to the displacement map is our Source Graphic, whilst the second comes from an Image primitive. In practice the Image is just a 50% gray rectangle pulled in as an SVG element (and positioned at the top left of the page so that it works in 0.91). There are also two stars in the image: the filter is applied to the red one, whereas the green one is simply there as a reference so that you can see the effect more clearly. The effect parameters are set to a Scale of 10, with the Red and Green channels being used as the source of the X and Y displacements respectively – those settings will become clear shortly.

The result of the filter is… absolutely nothing! To understand why, let's consider a single pixel in our output image. That pixel comes from somewhere in the source image, with the exact nature of “somewhere” being defined by the displacement map (the second input image). Each pixel in the displacement map is made up of a combination of four values (Red, Green, Blue and Alpha), and the settings in the filter dialog let you choose which of those values should be used for the X offset, and which for the Y offset. From there, Inkscape goes through the following steps to find out what color the output pixel should be:

1) Find the color of the equivalent pixel in the displacement map. 2) Extract the X and Y offsets from the color components that have been set in the filter. 3) Divide the offsets by 255 to normalize them into a range of 0 to 1. 4) Subtract 0.5 from the offsets to shift them into a range of -0.5 to 0.5 5) Multiply the offsets by the Scale value set in the filter. 6) Add the offset values to the X and Y coordinates of the pixel to get a new pair of coordinates. 7) The output pixel should be set to the color of the pixel from the input image that is located at the new coordinates, or an interpolated color based on the surrounding pixels if the coordinates don't point to a single pixel.

Bear in mind that our map consists only of 50% gray, with RGB values of 127, 127, 127. If you follow the steps above you'll find that gives an offset of about -0.02 pixels for both X and Y – close enough to zero to effectively mean that the output pixel is taken from the same position as the input pixel. Extend that over every pixel in the filter, and it's clear why our output looks exactly the same as the input.

Changing the rectangle to a black fill (0, 0, 0) alters the calculation somewhat. Now the offset becomes -5, -5 so our output pixel is the color of the pixel located a little up and to the left in the original image. That gives the appearance of the whole image having moved down and to the right.

Changing the rectangle to white (255, 255, 255) has the opposite effect – the image appears to move up and to the left. Because we've specified Red and Green for the X and Y displacement, filling it with pure red (255, 0, 0) produces different displacement values for the two coordinates, effectively moving the image down and to the left; pure green (0, 255, 0) moves it up and to the right. In all cases, the value of the Blue component (or, indeed, the Alpha component) doesn't make any difference. Pure cyan (0, 255, 255) has exactly the same effect as pure green, since we've configured the filter to consider just the Red and Green components.

Used with a flat color like this, Displacement Map is just a very poor replacement for the Offset primitive. Where it comes into its own is when your displacement map contains various colors in order to use different offsets for each pixel. We know that a black fill pulls its pixels from up/left, and a white fill from down/right – what happens when we use an image with both black and white in it? Let's give it a try with a group, containing a black spiral on a white background – and we'll apply it to something a bit more complex than a red star. By adding a little Gaussian Blur between the Image primitive and the Displacement Map you can soften the edges to give a nice ripple effect – with its intensity adjusted by changing the Scale parameter. Or how about a red-to-green gradient to give a fish-eye type of effect?

It's a bit of a cheat, because using just red and green only “stretches” your image in two directions. Overlaying a circle with perpendicular gradient that runs from white to transparent to black gives a more accurate result, but does start to hint at the biggest problem with the Displacement Map primitive: creating a suitable map image for the effect you want to achieve isn't always easy or obvious. But there is one way of creating a map that's quite simple, and extremely useful: the Turbulence primitive.

If you need a refresher on this primitive, take a look at Part 51 of this series. In short, it's a fast way to create areas filled with pseudo-random colors which, when used as a distortion map, will pull your image this way and that as you tweak the parameters. Use a low frequency Fractal Noise setting to add grotesque distortions to your image. Crank up the values a little to produce the sort of modesty-providing distortions you might find in a bathroom window. Further still and you've got a pointillistic masterpiece of shattered pixels. Unlink the horizontal and vertical frequencies and you can have a fluttering flag, or horizontal ripples.

But make sure you take the time to look at the edges. And what edges they are! From slight undulations, through spattered ink, to fuzzy vignettes. Imagine how these filters might look on shapes with even more edges, such as squares, stars and text. Better still, don't imagine; roll your sleeves up, dive into Inkscape's editor, and create your own filters.

Image Credits “La Gioconda” (aka “Mona Lisa”) by Leonardo da Vinci http://en.wikipedia.org/wiki/File:Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg

issue113/inkscape.1475485783.txt.gz · Dernière modification : 2016/10/03 11:09 de auntiee