| 53 | namespace oid::host { |
| 54 | |
| 55 | std::vector<unsigned char> rasterize_svg(const unsigned char* svg_data, |
| 56 | const std::size_t svg_size, |
| 57 | const int out_w, |
| 58 | const int out_h) { |
| 59 | if (svg_data == nullptr || svg_size == 0 || out_w <= 0 || out_h <= 0) { |
| 60 | return {}; |
| 61 | } |
| 62 | |
| 63 | // nsvgParse mutates its input and expects NUL termination. |
| 64 | std::string buf(reinterpret_cast<const char*>(svg_data), svg_size); |
| 65 | NSVGimage* image = nsvgParse(buf.data(), "px", 96.0f); |
| 66 | if (image == nullptr || image->width <= 0.0f || image->height <= 0.0f || |
| 67 | image->shapes == nullptr) { |
| 68 | if (image != nullptr) { |
| 69 | nsvgDelete(image); |
| 70 | } |
| 71 | return {}; |
| 72 | } |
| 73 | |
| 74 | NSVGrasterizer* rast = nsvgCreateRasterizer(); |
| 75 | if (rast == nullptr) { |
| 76 | nsvgDelete(image); |
| 77 | return {}; |
| 78 | } |
| 79 | |
| 80 | std::vector<unsigned char> rgba(static_cast<std::size_t>(out_w) * |
| 81 | static_cast<std::size_t>(out_h) * 4); |
| 82 | // Qt's setVectorIcon renders the whole SVG into a w x h pixmap; the |
| 83 | // target sizes are chosen to match each icon's aspect, so a single |
| 84 | // x-derived scale fills the buffer the same way. |
| 85 | const float scale = static_cast<float>(out_w) / image->width; |
| 86 | nsvgRasterize( |
| 87 | rast, image, 0.0f, 0.0f, scale, rgba.data(), out_w, out_h, out_w * 4); |
| 88 | |
| 89 | nsvgDeleteRasterizer(rast); |
| 90 | nsvgDelete(image); |
| 91 | return rgba; |
| 92 | } |
| 93 | |
| 94 | } // namespace oid::host |