Closed viktoras-pal closed 2 years ago
<svg id="svg1" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<rect id="rect1" x="20" y="20" width="160" height="160" fill="red"/>
</svg>
Original
document->rotate(45)
document->rotate(45, document->width() / 2.0, document->heigth() / 2.0)
How to rotate a final SVG image so that it would be rendered correctly without cropping?
Is this what you meant by cropping?
Yes. The result should be a full square (not clipped with viewBox) : I have a collection of SVG map symbols and I want to draw them on a map at different rotation angles.
CSS transformation functions Rotate()/Scale() work similarly as needed:
<!DOCTYPE html>
<html>
<body>
<div style="transform:rotate(45deg); display:inline-block; margin:40px; background:yellow;">
<svg id="svg1" width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<rect id="rect1" x="20" y="20" width="160" height="160" fill="red"/>
</svg>
</div>
<div style="transform:rotate(45deg) scale(0.5); display:inline-block; margin:40px; background:yellow;">
<svg id="svg2" width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<rect id="rect1" x="20" y="20" width="160" height="160" fill="red"/>
</div>
</body>
</html>
Bitmap renderToBitmapRotated(Document* document, double angle, double scale, std::uint32_t bgColor)
{
const double pi = 3.14159265358979323846;
double radians = pi * angle / 180.0;
double sine = std::sin(radians);
double cosine = std::cos(radians);
double originalWidth = document->width();
double originalHeight = document->height();
double rotatedWidth = cosine * originalWidth + sine * originalHeight;
double rotatedHeight = cosine * originalHeight + sine * originalWidth;
document->scale(originalWidth / rotatedWidth, originalHeight / rotatedHeight);
document->translate(rotatedWidth / 2.0, rotatedHeight / 2.0);
document->rotate(angle);
document->translate(-originalWidth / 2.0, -originalHeight / 2.0);
document->scale(scale, scale);
Bitmap bitmap(originalWidth, originalHeight);
document->render(bitmap, {}, bgColor);
return bitmap;
}
Lemme know if it works :)
Thank you.
I changed Document* to std::unique_ptr
I tested it, but the result is not quite what it should be. When scale is 1, the resulting square is smaller than the original. Another problem is that if the viewBox is not square, the resulting shape is skewed:
<svg viewBox="0 0 240 140" xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="20" width="100" height="100" style="fill:red;" />
</svg>
Original:
After rotation:
When scale is 1, the resulting square is smaller than the original. Another problem is that if the viewBox is not square, the resulting shape is skewed:
When rotating an image the bounding box changes so I have to scale the whole image back to its original size.
Please try this one with the latest commit 8fafd4398a220a696e6e6fc4eff35eb05d570ea7
Bitmap renderToBitmapRotated(Document* document, double angle, double scale, std::uint32_t bgColor)
{
const double pi = 3.14159265358979323846;
double radians = pi * angle / 180.0;
double sine = std::sin(radians);
double cosine = std::cos(radians);
double originalWidth = document->width();
double originalHeight = document->height();
double rotatedWidth = cosine * originalWidth + sine * originalHeight;
double rotatedHeight = cosine * originalHeight + sine * originalWidth;
Matrix matrix;
//matrix.scale(originalWidth / rotatedWidth, originalHeight / rotatedHeight);
matrix.translate(rotatedWidth / 2.0, rotatedHeight / 2.0);
matrix.rotate(angle);
matrix.translate(-originalWidth / 2.0, -originalHeight / 2.0);
matrix.scale(scale, scale);
Bitmap bitmap(rotatedWidth, rotatedWidth);
document->render(bitmap, matrix, bgColor);
return bitmap;
}
N.B the resulting image might be larger than the original image
I made some corrections:
Bitmap renderToBitmapRotated(const Document* document, double angle, double scale, std::uint32_t bgColor)
{
const double pi = 3.14159265358979323846;
double radians = pi * angle / 180.0;
double sine = std::abs(std::sin(radians));
double cosine = std::abs(std::cos(radians));
double originalWidth = document->width();
double originalHeight = document->height();
double rotatedWidth = cosine * originalWidth + sine * originalHeight;
double rotatedHeight = cosine * originalHeight + sine * originalWidth;
Matrix matrix;
matrix.translate(rotatedWidth / 2.0, rotatedHeight / 2.0);
matrix.rotate(angle);
matrix.translate(-originalWidth / 2.0, -originalHeight / 2.0);
matrix.scale(scale, scale);
std::uint32_t width = static_cast<std::uint32_t>(std::ceil(rotatedWidth));
std::uint32_t height = static_cast<std::uint32_t>(std::ceil(rotatedHeight));
Bitmap bitmap(width, height);
document->render(bitmap, matrix, bgColor);
return bitmap;
}
Now everything works fine except when viewBox is undefined.
I haven’t tried scaling before. If the scale is not 1, it renders incorrectly.
Bitmap renderToBitmapRotated(Document* document, double angle, double scale, std::uint32_t bgColor)
{
const double pi = 3.14159265358979323846;
double radians = pi * angle / 180.0;
double sine = std::abs(std::sin(radians));
double cosine = std::abs(std::cos(radians));
double originalWidth = document->width();
double originalHeight = document->height();
double rotatedWidth = cosine * originalWidth + sine * originalHeight;
double rotatedHeight = cosine * originalHeight + sine * originalWidth;
double scaledWidth = rotatedWidth * scale;
double scaledHeight = rotatedHeight * scale;
Matrix matrix;
matrix.scale(scaledWidth / rotatedWidth, scaledHeight / rotatedHeight);
matrix.translate(rotatedWidth / 2.0, rotatedHeight / 2.0);
matrix.rotate(angle);
matrix.translate(-originalWidth / 2.0, -originalHeight / 2.0);
std::uint32_t width = static_cast<std::uint32_t>(std::ceil(scaledWidth));
std::uint32_t height = static_cast<std::uint32_t>(std::ceil(scaledHeight));
Bitmap bitmap(width, height);
document->render(bitmap, matrix, bgColor);
return bitmap;
}
I hope it works
Thank you, it works as expected now. Example:
<svg width="240" height="140" viewBox="100 0 240 140" xmlns="http://www.w3.org/2000/svg">
<rect x="110" y="10" width="220" height="120" style="fill:red;" stroke="blue" stroke-width="1" />
</svg>
Original: Scale: 0.5, rotation angles: 0/30/60/90/120
You could include this useful function to your library as a method of Document class.
Thank you for opening this issue <3 <3 <3
How to rotate a final SVG image so that it would be rendered correctly without cropping? It would be nice to have a method to render a rotated and scaled SVG image, like this:
Bitmap Document::renderToBitmapRotated(double angle, double scale, std::uint32_t backgroundColor) const;