C API functions in libcairo or librsvg, to convert lengths to other units?

112 Views Asked by At

I'm trying to develop a C program based on https://github.com/songulabuzar/librsvg-minimal-example, which reads and renders and SVG file, using both librsvg and cairo libraries.

I have noticed, that both libraries contain enums that define length units.

In (lib)cairo, in https://github.com/freedesktop/cairo/blob/7bf3a78/src/cairo-svg.h there is:

typedef enum _cairo_svg_unit {
    CAIRO_SVG_UNIT_USER = 0,
    CAIRO_SVG_UNIT_EM,
    CAIRO_SVG_UNIT_EX,
    CAIRO_SVG_UNIT_PX,
    CAIRO_SVG_UNIT_IN,
    CAIRO_SVG_UNIT_CM,
    CAIRO_SVG_UNIT_MM,
    CAIRO_SVG_UNIT_PT,
    CAIRO_SVG_UNIT_PC,
    CAIRO_SVG_UNIT_PERCENT
} cairo_svg_unit_t;

... which is most obviously used with cairo_svg_surface_set_document_unit function (declared in the same header file).

On the other hand, (lib)rsvg in https://github.com/GNOME/librsvg/blob/d158d11/include/librsvg/rsvg.h defines:

typedef enum {
    RSVG_UNIT_PERCENT,
    RSVG_UNIT_PX,
    RSVG_UNIT_EM,
    RSVG_UNIT_EX,
    RSVG_UNIT_IN,
    RSVG_UNIT_CM,
    RSVG_UNIT_MM,
    RSVG_UNIT_PT,
    RSVG_UNIT_PC
} RsvgUnit;

... and specifically, it also defines a length with a unit:

typedef struct {
    double   length;
    RsvgUnit unit;
} RsvgLength;

So, what I'd like to know, is: is there a function in either of these APIs, that converts one length with units to another unit?

Say, I have a defined length of 1.5 inches (in librsvg, that would be a RsvgLength with { .length = 1.5, .unit = RSVG_UNIT_IN }) - is there a built-in function (in either of these APIs) to convert this kind of length to centimeters?

( as a reminder, for this example, 1.5 in = 3.81 cm ... I am aware that not all conversions would be a-priori possible, that is, converting cm to px (pixels) would also require the document DPI (dots-per-inch) ).

1

There are 1 best solutions below

0
On

Well, I tried looking through the code again, and I think I'm reasonably certain, that there are no unit conversion functions in neither (lib)cairo, nor (lib)rsvg (as of writing of this answer).

 * It is up to the calling application to convert lengths in non-pixel units
 * (i.e. those where the @unit field is not `RSVG_UNIT_PX`) into something
 * meaningful to the application.  For example, if your application knows the
 * dots-per-inch (DPI) it is using, it can convert lengths with @unit in
 * `RSVG_UNIT_IN` or other physical units.

So, I guess, no SVG unit conversion functions here (in these two libraries) as of writing of this answer.

There is also a similar enum CRNumType in https://gitlab.gnome.org/Archive/libcroco/-/blob/master/src/cr-num.h - but again, I cannot find any unit conversion functions there.

However, I found SVG unit conversion functions here:

Interestingly, both of these convert from "any" unit to pixels - but I couldn't find a reverse function. For reference, I'll paste nsvg__convertToPixels, as it looks like it can be more easily translated to librsvg:

static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length)
{
    NSVGattrib* attr = nsvg__getAttr(p);
    switch (c.units) {
        case NSVG_UNITS_USER:       return c.value;
        case NSVG_UNITS_PX:         return c.value;
        case NSVG_UNITS_PT:         return c.value / 72.0f * p->dpi;
        case NSVG_UNITS_PC:         return c.value / 6.0f * p->dpi;
        case NSVG_UNITS_MM:         return c.value / 25.4f * p->dpi;
        case NSVG_UNITS_CM:         return c.value / 2.54f * p->dpi;
        case NSVG_UNITS_IN:         return c.value * p->dpi;
        case NSVG_UNITS_EM:         return c.value * attr->fontSize;
        case NSVG_UNITS_EX:         return c.value * attr->fontSize * 0.52f; // x-height of Helvetica.
        case NSVG_UNITS_PERCENT:    return orig + c.value / 100.0f * length;
        default:                    return c.value;
    }
    return c.value;
}

So I guess, to implement an svg unit conversion from "any" unit to "any" unit, one has to implement the reverse function (so, something like nsvg__convertFromPixels), then call them both, with the pixel value of the length as "intermediary".