How Krita's Vector Layers are Different from Clip Studio Paint's Vector Layers

Share
If you have used Clip Studio Paint before and you are thinking about migrating to Krita, or just trying Krita for a bit, you may run into one big problem: one of CSP's greatest features is something it calls "vector layers," which are used for line art, and Krita has something called vector layers as well, so you may reasonable assume that Krita's vector layers are just like CSP's vector layers, but unfortunately, you would be wrong: they're completely different things.

What CSP calls "vector layers" are also called "line art layers" in Paint Tool SAI, whereas what Krita calls "vector layers" are layers that use SVG technology to display scalable graphics. A key difference between these two is that is that line art layers can't contain "filled areas," they only contain brush or pen strokes, while SVG layers can contain filled areas and even text, but they don't actually contain brush strokes, which makes them useless for most line art.

What are "Vector" Layers?

Normally, when we work with digital images, we work with "raster" images. A raster image is a grid of pixels. Quite literally, the data of the digital image is merely a sequence of tuples of three numbers that tells the computer the intensities of red, green, and blue lights on the screen necessary to reproduce a single color. If our image has a resolution of 1 million pixels, it's a sequence of 1 million of these RGB tuples.

The problem with raster images is that they have a resolution. This means when the image was created we decided how many pixels of resolution it was going to have, and it will never be able to have more detail than it has pixels. If we increase the size of the image, it can't create data out of nowhere to fill the extra resolution it gained, so it has to stretch the data it already has to fit the new size. This stretching is performed with a scaling method such as nearest neighbor, linear interpolation, etc., which tries to calculate values for pixels out of existing data.

When we draw on a raster image, what happens is that we tell a computer program to perform a drawing action with a certain tool, with certain parameters, and then the computer program generates a temporary image for the brush stroke. For example, a 50x50px image for a brush of 50px of diameter. The program takes this temporary image and "applies" it to the canvas according to a blending mode, just like a typical layer in an image editor. Once the brush stroke is applied, the pixel data on the canvas changes permanently. The pixels of the brush are "burned" onto the canvas.

This sort of editing is also called destructive editing, because it modifies the data of the canvas in a way that can't be undone.

An alternative exists: non-destructive editing. For this case specifically, the term used is generally "vector" graphics or "scalable" graphcis.

The idea is that instead of the program immediately changing the pixels of the canvas after you use a tool, it keeps a list of the operations you have done, which parameters: which tools you used, which brushes, what color, what size, how much pen pressure, what tilt, with what speed, where the brush stroke started, where the brush stroke ended, how long it took, etc.

When you draw with vectors, you don't draw the pixels directly. Instead, the program records your actions, and then the program uses that recorded data to draw the pixels from scratch. This has one negative effect, and several positive effects.

Slow: the negative effect is that it's slow. With destructive editing, each brush stroke is saved permanently on the canvas pixel data. This means the program only needs to process the current brush stroke and can forget about the previous ones. With vectors, the idea is that if you give the program a blank canvas and the recorded data, it can recreate the whole thing from scratch, which means if you drew 1000 strokes, it has to draw 1000 strokes at once, which logically is going to take 1000 times longer than just drawing 1 stroke. For the program, the process of "rendering" a stroke is the same regardless if you do it manually in a raster layer or the program reproduces it automatically in a vector layer, but it will have to perform this process more times in a vector layer than it would normally in a raster layer. Normally, there are optimizations for this, such as creating a temporary rasterization of the finished image from the vector so it doesn't need to redraw the whole thing every time you have a vector layer visible on the screen.

Editable: the first positive effect is that you can edit the parameters directly. For example, say you drew a curve when you wanted to draw a straight line. In a raster layer, that stroke would become pixels, so the only way to fix this would be to move the pixels. More realistically, it would be easier to erase the stroke and redraw it, because moving the pixels won't look good most of the time. With a vector layer, we have access to the intermediate step before turning the strokes into pixels. We can change the stroke, and the program will redraw it from scratch with the modified parameters just as if we had never drawn it wrong in the first place.

Scalable: the second positive effect, which is vector's second name, is that they are scalable. When you move, rotate, or scale pixels, the values of the pixels on a grid need to be calculated from the original pixel data, and it's very easy to lose quality by making things blurry because data needs to be generated out of nowhere. With vectors, when you move, rotate, or scale vectors, what you're "moving" are the starting point and the ending point of a line, what you are "scaling" are radii of brushes, so the computer can easily generate more pixel data from the same amount of vector data at different positions and values.

Precise: specially useful for coloring line art: when you use pixels for line art, and then you need to select areas inside the line art to color them, you will need an algorithm to try to guess, based on the pixels' colors, where is the middle of the strokes. This is what bucket fill and magic wand tools do. With vectors, at least the way CSP implements it, it's not necessary to consider the pixel data because CSP has access to the actual stroke lines. It recorded where you drew the strokes, so it can use vector math to calculate where the areas to be filled are. Although this sounds more complicated mathematically, it's actually infinitely faster. Note that a single line with 2 points in a vector layer can fill hundreds or thousands of pixels in its rasterization. When you need to process things pixels per pixel, even the simplest algorithms can take too long, specially if they're performed on the CPU instead of the GPU. Vectors will always have less data to process than their rasterizations, which means we can do calculate things faster.

There is one caveat of vectors images.

The term vector comes from mathematical vectors. The idea is that you have a point in the center of a graph with horizontal and vertical (X, Y) coordinates, which is the 0, 0. This is called the origin point. A vector is a direction and a magnitude. For example, 10, 0 could means the direction to the right, with a magnitude of 10, if we assume the first coordinate goes from left-to-right (there are cases that's not true). We don't know what 10 means. Could be 10 meters, 10 pixels, could be anything. This is a vector. How do you make lines out of this? We simply follow an algorithm:

  1. Move 10 to the right.
  2. Start drawing a line.
  3. Move 5 to the top.
  4. Finish drawing th eline.

And this would create a line from 10, 0 to 10, -5.

When I was a child I remember there was a program you gave commands like these to make a turtle draw shapes.

If we wanted to scale this by 2, we would simply multiply all the values above by 2 and that's it. The "turtle" would have to move twice as much, but the amount of the steps (the amount of recorded data to reproduce) would remain the same.

The key problem here is how much data is recorded, and what kind of data can the program reproduce. In many cases, a "vector" graphic will contain a lot of data that aren't actually mathematical vectors in the geometric sense above. For example, the color of a stroke will need to be a tuple of RGB values. In low-level graphics programming, RGB tuples are sometimes called vectors, but that's just because a lot of calculations done on them are vector math, not because they have anything to do with geometry. The radius of a stroke is certainly not a vector. Pen pressure isn't a vector, etc.

SVG vs. Line Art

The SVG technology was created to draw shapes. This means the vector data is used to draw polygons, rectangles, circles, etc. Any of these shapes can have a stroke and a fill, either of which be a flat color or a gradient.

SVG doesn't support "pen pressure" data, or tilt, or anything like that. It's an open, general-purpose format, and lots of programs support it. Nowadays, even web browsers can display SVG images.

Krita has its own SVG parser. Which means some features that work in other SVG programs, like Inkscape, may not work with Krita because they didn't implement it in Krirta yet. One feature they did implement was SVG symbols, though. It's possible to add your own proprietary extensions to SVG, but Krita hasn't added any for pen pressure.

Essentially, this means Krita's vector layers are for (partial) compatibility with other SVG software, like Inkscape. They are unfortunately not for actually drawing in Krita like vector layers are in CSP or line art layers are in SAI.

In CSP and SAI, we have the opposite situation. Their vector layers contain only stroke data, and it's not possible to create areas filled with a single color using vectors. This is a common question by CSP users, in fact: why can't I just fill an area with a color like I can do in Inkscape? Aren't they both vectors? Yeah, but they're different vectors.

Honestly, I don't see any reason why Krita couldn't have vector layers like CSP, they merely don't have them at the moment because nobody implemented them.

Impure Vector Graphics

One last thing worth noting is that because vector layers are supposed to reproduce the recorded strokes perfectly, they need to be pure functions: if you give a pure function the same input, you'll always get the same output. Pure functions can't use data external to the inputted parameters. This sounds simple enough. Awkwardly, there are 2 common cases in drawing software where this purity can't be guaranteed with vector layers, and sure enough CSP is affected by these.

The first scenario are brushes that blur or smear colors. If this effect applies only to the current layer, that's not a problem, but if it considers colors from the whole canvas, i.e. from layers underneath the current layer, then if you executed the same steps with different layers underneath you would get different results, so purity can't be guaranteed.

The second scenario are brushes that use randomized parameters, such as scattering. The problem isn't that randomness isn't possible to reproduce. Actually it's the very opposite: in the typical computer program, randomness is deterministic, which means it's trivial to reproduce randomly generated values. The way it works is like this. When a program starts, it decides a first random number based on what time is on the clock, for example. This first number is called the random seed. The next time it needs a random number, it performs some math on this random seed that changes its value. The idea is that if this process is repeated infinitely, it will generate lots of random-looking numbers, so it's random enough for most practical cases. What this means is that if you start with the random seed X, and we generate 3 random values from it, it's always going to be the exact same 3 numbers for the same random seed X. If we store the seed with the vector data, we can reproduce randomness with purity. The problem is what happens if the number of steps changes. For example, for scattering, the program will generate a random position for each dab of the brush. A single line can have hundreds of dabs, so we'll have hundreds of random values in it. If we make the line longer, the number of dabs can increase, which means it won't look exactly the same as it was before if we tried to scale it, for example. If we stored only one random seed per vector layer instead of per stroke, strokes could change if we added or removed strokes to the layer. And, of course, if we don't store the seed, it's going to change every time the program tries to rasterize the vectors.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *