sammycage / lunasvg

lunasvg is a standalone SVG rendering library in C++
MIT License
818 stars 115 forks source link

Render svg element #161

Closed lolpie244 closed 3 months ago

lolpie244 commented 3 months ago

Hi! Could you please advice: is there any way to render one element from all svg?

Tried something like this, but still it renders all svg

auto element = document_->getElementById(id);
auto box = element.getBBox();
lunasvg::Matrix matrix;
box.transform(matrix);
auto width = static_cast<int>(std::ceil(box.x + box.w));
auto height = static_cast<int>(std::ceil(box.y + box.h));

lunasvg::Bitmap bitmap_(width, height);
document_->render(bitmap_, matrix);
sammycage commented 3 months ago

@lolpie244 No, but I see you have done it with your own fork, nice job!

lolpie244 commented 3 months ago

@sammycage unfortunately my code doesn't work( (it doens't display svg at all).

I suspect it's because LayoutGroup doens't have clip (?) Or is there any potential problem?

sammycage commented 3 months ago

@lolpie244 Oh, I see, maybe there is something wrong with the transformation matrix.

lolpie244 commented 3 months ago

@sammycage Hmm, could you please explain local variables of matrix (a, b, c, d, e, f)?

sammycage commented 3 months ago

E and F determine how the context is shifted horizontally and vertically. When B and C equal zero, A and D determine how the context is scaled horizontally and vertically. When A and D are set to one, B and C determine how the context is skewed horizontally and vertically.

lolpie244 commented 3 months ago

Oh, I see. Ok, I will try to implement it and will create pr if it goes well. Thank you for answers and this great library!

sammycage commented 3 months ago

Good luck

lolpie244 commented 3 months ago

Ok, i somehow managed to display element. But, I still don't know how to get proper offset (+40 in code)

auto element = document_->getElementById(id).getBBox();
auto scale_x = size.x / element.w;
auto scale_y = size.y / element.h;
lunasvg::Matrix matrix_(scale_x, 0, 0, scale_y, -element.x * scale_x + 40, -element.y * scale_y + 40);
lunasvg::Bitmap bitmap_(size.x, size.y);

~(and I hope you are ok with my dev log here)))~

sammycage commented 3 months ago

@lolpie244 Nice try! Could you please send me your test file?

sammycage commented 3 months ago

@lolpie244 Check this out, let me know if it doesn't work.


Bitmap DomElement::renderToBitmap(uint32_t width, uint32_t height, uint32_t backgroundColor) const
{
    auto elementBounds = m_element->box()->map(m_element->box()->strokeBoundingBox());
    if(width == 0 && height == 0) {
        width = static_cast<std::uint32_t>(std::ceil(elementBounds.w));
        height = static_cast<std::uint32_t>(std::ceil(elementBounds.h));
    } else if(width != 0 && height == 0) {
        height = static_cast<std::uint32_t>(std::ceil(width * elementBounds.h / elementBounds.w));
    } else if(height != 0 && width == 0) {
        width = static_cast<std::uint32_t>(std::ceil(height * elementBounds.w / elementBounds.h));
    }

    Matrix matrix(width / elementBounds.w, 0, 0, height / elementBounds.h, -elementBounds.x, -elementBounds.y);
    Bitmap bitmap(width, height);
    bitmap.clear(backgroundColor);
    RenderState state(nullptr, RenderMode::Display);
    state.canvas = Canvas::create(bitmap.data(), bitmap.width(), bitmap.height(), bitmap.stride());
    state.transform = Transform(matrix);
    m_element->box()->render(state);
    return bitmap;
}
lolpie244 commented 3 months ago

theme1.zip sorry about zip, github upload svg as markdown image

lolpie244 commented 3 months ago
    auto elementBounds = m_element->box()->map(m_element->box()->strokeBoundingBox());
    if(width == 0 && height == 0) {
        width = static_cast<std::uint32_t>(std::ceil(elementBounds.w));
        height = static_cast<std::uint32_t>(std::ceil(elementBounds.h));
    } else if(width != 0 && height == 0) {
        height = static_cast<std::uint32_t>(std::ceil(width * elementBounds.h / elementBounds.w));
    } else if(height != 0 && width == 0) {
        width = static_cast<std::uint32_t>(std::ceil(height * elementBounds.w / elementBounds.h));
    }

    Matrix matrix(width / elementBounds.w, 0, 0, height / elementBounds.h, -elementBounds.x, -elementBounds.y);
    Bitmap bitmap(width, height);
    bitmap.clear(backgroundColor);
    RenderState state(nullptr, RenderMode::Display);
    state.canvas = Canvas::create(bitmap.data(), bitmap.width(), bitmap.height(), bitmap.stride());
    state.transform = Transform(matrix);
    m_element->box()->render(state);
    return bitmap;

It works! Just need to made small corrections. I will submit pr, thanks!

lolpie244 commented 3 months ago

@sammycage https://github.com/sammycage/lunasvg/pull/162

sammycage commented 3 months ago

@lolpie244 Nice job