sammycage / lunasvg

SVG rendering and manipulation library in C++
MIT License
866 stars 124 forks source link

API for background image #60

Closed zcream closed 2 years ago

zcream commented 2 years ago

Using Bitmap(std::uint8_t* data, std::uint32_t width, std::uint32_t height, std::uint32_t stride); one can supply a custom buffer with a background image.

However, both render and renderToBitmap have a background color. Does this mean that lunasvg will always overwrite the custom background?

sammycage commented 2 years ago

Since the Canvas format (ARGB32 Premultiplied) is not always the same as theBitmap format (RGBA plain), so we have to convert the Bitmap format to theCanvas format by erasing it with the backgroundColor before rendering.

zcream commented 2 years ago

Could the API offer an option to supply ARGB32 directly? It would be a simple change and save the byte swap and background fill.

zcream commented 2 years ago
void Document::renderARGB(Bitmap bitmap, const Matrix& matrix, std::uint32_t backgroundColor) const
{
    RenderState state(nullptr, RenderMode::Display);
    state.canvas = Canvas::create(bitmap.data(), bitmap.width(), bitmap.height(), bitmap.stride());
    state.transform = Transform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f);
//    state.canvas->clear(backgroundColor);
    root->render(state);
//  Comment out - pixels[x] = (a << 24) | (b << 16) | (g << 8) | r;   
state.canvas->rgba();
}
sammycage commented 2 years ago

The Canvas format is not always ARGB32_PREMULTIPLIED because I want to target multiple renderers

fdwr commented 2 years ago

@zcream I had the same experience. I'm rendering multiple SVG icons into an existing atlas texture (with the target bitmap subrect window adjusted accordingly) to draw toolbar and menu icons for arbitrary DPI's, and there's no need for the background pixels to be cleared because I already did that anyway. Additionally the atlas texture bitmap pixels passed into render() are BGRA premultiplied so that I can use them with multiple renderers (SDL, Cairo, GDI, GDI+, Direct3D, OpenGL) which either require or at least work most efficiently with premultiplied textures. So lunasvg undoing plutovg's canvas output is counterproductive here.

sammycage commented 2 years ago

73

sammycage commented 2 years ago

0d3e6a2897a76c907becbe48c1726685531ab455 You can now use one image buffer to render multiple images @fdwr @zcream

Example :


auto document = Document::loadFromFile("tiger.svg");

const int tileW = 300;
const int tileH = 300;

Bitmap bitmap(900, 900);
bitmap.clear(0xF0FFF0FF); // HoneyDew
for(int y = 0;y < bitmap.height();y += tileH)
{
    for(int x = 0;x < bitmap.width();x += tileW)
    {
        Matrix matrix(tileW / document->width(), 0, 0, tileH / document->height(), x, y);
        document->render(bitmap, matrix);
    }
}

bitmap.convertToRGBA();

stbi_write_png("tiledtiger.png", bitmap.width(), bitmap.height(), 4, bitmap.data(), 0);

tiledtiger.png :

tiledtiger