Let me clear something up. Rotating and scaling up a bitmap will always result in a perceived quality loss. In the case of upscaling bitmaps, by making the image larger you need to show more data than was initially captured. Consider this picture where the information in the middle of the image is missing:
Now as a human with lots of experience in seeing pictures and real world objects, you might be able to recognize that these are some red rocks and could imagine the missing area filled in with more red rocks. We are just getting to the point where computers are capable of this sort of content aware fill, but right now the best algorithms usually end up looking something like this:
Now you may be thinking, “oh but I could fill it in more correctly in my mind”, and you’d likely be wrong. Take a moment to clearly visualize what you think is in the missing area, then click this link to see what it actually is:
Were you right? No you weren’t because not you, not the most sophisticated supercomputer in the world, not anybody, can know for certain what that missing information is unless it’s recorded somewhere. In the context of scaling a bitmap image, it is the exact same scenario, but on a much smaller scale. The black missing area of data we don’t know is the color between individual pixels (or more accurately the color distribution within a single pixel). Again we can’t just magically know this information. We can record the strokes and then redraw them to create this information, this is what vectors do, but bitmaps by there very definition don’t contain any information about how they were created, they are just a grid of pixels. How Pencil2D, and virtually any other software than has image scaling capabilities does this is through a process known as interpolation. To simplify, it’s like it blends adjacent pixels to guess at what the color is between them. If it sees a black and a white pixel next to each other, it says the value is probably gray. Yellow and red? How about orange inbetween then. Et cetera. It’s really doing this with some relatively basic mathematical formulas. Some programs (not Pencil2D) offer the option of using different formulas which will typically result in only very slight differences in the actual result. We do plan on adding this option eventually as it can be useful for certain use-cases (particularly pixel art).
As for rotating a bitmap, the underlying problem is the exact same that the distribution of colors within an individual pixel is unknown and unknowable. However it can be more helpful to think of it with a different example. Consider this enlarged version of a 3x3 pixel image:
Now imagine trying to rotate this red square by 45 degrees. Something like this:
However, there are two problems with this:
- You can only change the color of the 9 pixels/squares. Those red points sticking into the adjacent squares cannot be represented like that because you can’t you can’t draw or store part of a pixel in a bitmap. You screen is made up of a very tiny grid of pixels, which are square, not triangles, not whatever shape you want it to be, just squares.
- Even if you could represent the square fully as you can see there is potentially content underneath it which is not known.
The second issue is handled by most programs by assuming the underlying content is transparent or that it is some predefined background color. The first issue is handled by interpolation again. So the second pixel on the top of our example is mostly white with a little bit of red poking up on the bottom, so perhaps it would be best approximated by a white pixel with a little bit of pink to it. When you do this interpolation for every pixel, you get something like this:
Now does this look like it’s been rotated 45 degrees? No not really, but it’s the best that can be done when effectively trying to shove diamonds into square holes.
More importantly, consider what happens if we rotate this image 45 degrees again. In an ideal world, the result would look exactly the same as the original image because a square rotated by 45+45 degrees would be the same square. However, the information about the square’s rotation, and what parts of the white pixels have are red has already been lost, and all the computer sees is gray pixels, pink pixels, and a red pixel. Additionally most programs including Pencil2D will not allow you to make a rotated selection (you can rotate a selection, but not make a selection that is initially rotated). Nor do most programs allow you to select parts of a pixel on a bitmap. If you could make a rotated selection, you would see the red square get a little bit whiter as parts of the pink pixel is interpolated with the red pixel. If you end up just selecting the middle pixel and rotating again, the adjacent pixels will become even more pink because you’re effectively doing the exact same thing as you did the first time to the computer, rotating the unrotated red square in the middle by 45 degrees.
Vectors can be scaled and rotated without loosing significant quality only because they store the information to effectively redraw the strokes after scaling/rotating, although they are still subject to the limitations of your grid-of-pixels display and bitmap exports. We do not recommend using the vector layer in Pencil2D currently because it is very buggy, but it will be improved at some point. Technically you can store rotated bitmaps as separate objects, and some programs do this to prevent the reduction of quality when rotating an object multiple times, but there are challenges with that too, and again you’re still limited to square pixels when viewing it or rendering it. Pencil2D does actually already do this to some extent, you can see how it works by making a selection and then rotating it multiple times without applying your transformation (which happens when you press the enter key or deselect/change the selection). Once you apply the transformation it writes the object back to your frame, and you loose the information of what the object looked like before the rotation forever.
I will wrap up this dive into how bitmap scaling and rotation work by reiterating some key points. Degrading bitmap image quality is expected in these scenarios, and can never be fixed. We will likely add other interpolation algorithm options at some point, but these only change the appearance of the results, they are no more or less correct than any other method.