librsvg source for verification 2026-05-22

This commit is contained in:
2026-05-22 16:45:08 +08:00
commit 75af7ac721
2138 changed files with 161177 additions and 0 deletions

32
doc/librsvg-r.svg Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256" height="256" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="Gradient" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" style="stop-color:#ED333B;stop-opacity:1" />
<stop offset="100%" style="stop-color:#F66151;stop-opacity:1" />
</linearGradient>
<filter id="alpha-to-white">
<feColorMatrix in="SourceGraphic" type="matrix"
values="0 0 0 1 0
0 0 0 1 0
0 0 0 1 0
0 0 0 1 0"/>
</filter>
<g id="child-svg">
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 5 0 c -1.097656 0 -2 0.902344 -2 2 c 0 0.734375 0.402344 1.382812 1 1.730469 v 8.539062 c -0.597656 0.347657 -1 0.996094 -1 1.730469 c 0 1.097656 0.902344 2 2 2 s 2 -0.902344 2 -2 c 0 -0.734375 -0.402344 -1.382812 -1 -1.730469 v -8.539062 c 0.300781 -0.175781 0.554688 -0.429688 0.730469 -0.730469 h 2.269531 s 0.542969 0.015625 1.050781 0.269531 c 0.511719 0.253907 0.949219 0.5625 0.949219 1.730469 s -0.4375 1.476562 -0.949219 1.730469 c -0.132812 0.066406 -0.265625 0.117187 -0.394531 0.15625 c -0.359375 -0.535157 -0.96875 -0.886719 -1.65625 -0.886719 c -1.097656 0 -2 0.902344 -2 2 s 0.902344 2 2 2 c 0.15625 0 0.3125 -0.019531 0.457031 -0.054688 l 2.625 3.496094 c -0.054687 0.175782 -0.082031 0.363282 -0.082031 0.558594 c 0 1.097656 0.902344 2 2 2 s 2 -0.902344 2 -2 s -0.902344 -2 -2 -2 c -0.15625 0 -0.3125 0.019531 -0.457031 0.054688 l -2.417969 -3.222657 c 0.253906 -0.070312 0.539062 -0.171875 0.824219 -0.3125 c 0.988281 -0.496093 2.050781 -1.6875 2.050781 -3.519531 s -1.0625 -3.023438 -2.050781 -3.519531 c -0.992188 -0.496094 -1.949219 -0.480469 -1.949219 -0.480469 h -2.269531 c -0.347657 -0.597656 -0.996094 -1 -1.730469 -1 z m 0 1 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m 3 6 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m -3 6 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m 8 0 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m 0 0" fill="#2e3436"/>
</svg>
</g>
</defs>
<rect
width="256"
height="256"
fill="url(#Gradient)"
ry="128"
x="0"
y="0" />
<use xlink:href="#child-svg" filter="url(#alpha-to-white)"
transform="matrix(8,0,0,8,64,64)" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

32
doc/librsvg.svg Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256" height="256" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="Gradient" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" style="stop-color:#ED333B;stop-opacity:1" />
<stop offset="100%" style="stop-color:#F66151;stop-opacity:1" />
</linearGradient>
<filter id="alpha-to-white">
<feColorMatrix in="SourceGraphic" type="matrix"
values="0 0 0 1 0
0 0 0 1 0
0 0 0 1 0
0 0 0 1 0"/>
</filter>
<g id="child-svg">
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 5 0 c -1.097656 0 -2 0.902344 -2 2 c 0 0.734375 0.402344 1.382812 1 1.730469 v 8.539062 c -0.597656 0.347657 -1 0.996094 -1 1.730469 c 0 1.097656 0.902344 2 2 2 s 2 -0.902344 2 -2 c 0 -0.734375 -0.402344 -1.382812 -1 -1.730469 v -8.539062 c 0.300781 -0.175781 0.554688 -0.429688 0.730469 -0.730469 h 2.269531 s 0.542969 0.015625 1.050781 0.269531 c 0.511719 0.253907 0.949219 0.5625 0.949219 1.730469 s -0.4375 1.476562 -0.949219 1.730469 c -0.132812 0.066406 -0.265625 0.117187 -0.394531 0.15625 c -0.359375 -0.535157 -0.96875 -0.886719 -1.65625 -0.886719 c -1.097656 0 -2 0.902344 -2 2 s 0.902344 2 2 2 c 0.15625 0 0.3125 -0.019531 0.457031 -0.054688 l 2.625 3.496094 c -0.054687 0.175782 -0.082031 0.363282 -0.082031 0.558594 c 0 1.097656 0.902344 2 2 2 s 2 -0.902344 2 -2 s -0.902344 -2 -2 -2 c -0.15625 0 -0.3125 0.019531 -0.457031 0.054688 l -2.417969 -3.222657 c 0.253906 -0.070312 0.539062 -0.171875 0.824219 -0.3125 c 0.988281 -0.496093 2.050781 -1.6875 2.050781 -3.519531 s -1.0625 -3.023438 -2.050781 -3.519531 c -0.992188 -0.496094 -1.949219 -0.480469 -1.949219 -0.480469 h -2.269531 c -0.347657 -0.597656 -0.996094 -1 -1.730469 -1 z m 0 1 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m 3 6 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m -3 6 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m 8 0 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m 0 0" fill="#2e3436"/>
</svg>
</g>
</defs>
<rect
width="256"
height="256"
fill="url(#Gradient)"
ry="0"
x="0"
y="0" />
<use xlink:href="#child-svg" filter="url(#alpha-to-white)"
transform="matrix(8,0,0,8,64,64)" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

39
doc/librsvg.toml Normal file
View File

@@ -0,0 +1,39 @@
# Configuration for https://gitlab.gnome.org/GNOME/gi-docgen
[library]
version = "2.62.1"
description = "Librsvg - load and render SVG documents"
authors = "Librsvg developers"
license = "LGPL-2.1-or-later"
browse_url = "https://gitlab.gnome.org/GNOME/librsvg/"
repository_url = "https://gitlab.gnome.org/GNOME/librsvg.git"
website_url = "https://gnome.pages.gitlab.gnome.org/librsvg/"
devhelp = true
search_index = true
logo_url = "librsvg-r.svg"
[source-location]
# The base URL for the web UI
base_url = "https://gitlab.gnome.org/GNOME/librsvg/-/blob/main/"
# The format for links, using "filename" and "line" for the format
file_format = "{filename}#L{line}"
[theme]
name = "basic"
show_index_summary = true
show_class_hierarchy = true
[extra]
content_files = [
"overview.md",
"recommendations.md",
"migrating.md"
]
content_images = [
"librsvg-r.svg"
]
urlmap_file = "urlmap.js"
[[object]]
name = "Rsvg.DEPRECATED_FOR"
hidden = true

59
doc/load-and-render.c Normal file
View File

@@ -0,0 +1,59 @@
/* gcc -Wall -g -O2 -o load-and-render load-and-render.c `pkg-config --cflags --libs rsvg-2.0` */
#include <stdlib.h>
#include <librsvg/rsvg.h>
#define WIDTH 640
#define HEIGHT 480
int
main (void)
{
/* First, load an SVG document into an RsvgHandle */
GError *error = NULL;
GFile *file = g_file_new_for_path ("hello.svg");
RsvgHandle *handle = rsvg_handle_new_from_gfile_sync (file, RSVG_HANDLE_FLAGS_NONE, NULL, &error);
if (!handle)
{
g_printerr ("could not load: %s", error->message);
exit (1);
}
/* Create a Cairo image surface and a rendering context for it */
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
cairo_t *cr = cairo_create (surface);
/* Render the handle scaled proportionally into that whole surface */
RsvgRectangle viewport = {
.x = 0.0,
.y = 0.0,
.width = WIDTH,
.height = HEIGHT,
};
if (!rsvg_handle_render_document (handle, cr, &viewport, &error))
{
g_printerr ("could not render: %s", error->message);
exit (1);
}
/* Write a PNG file */
if (cairo_surface_write_to_png (surface, "hello.png") != CAIRO_STATUS_SUCCESS)
{
g_printerr ("could not write output file");
exit (1);
}
/* Free our memory and we are done! */
cairo_destroy (cr);
cairo_surface_destroy (surface);
g_object_unref (handle);
g_object_unref (file);
return 0;
}

51
doc/meson.build Normal file
View File

@@ -0,0 +1,51 @@
docs_src = files(
'librsvg.toml',
'librsvg-r.svg',
'librsvg.svg',
'load-and-render.c',
'migrating.md',
'overview.md',
'recommendations.md',
'urlmap.js',
)
if build_gir.allowed()
girepository_folder = gi_dep.get_variable(pkgconfig: 'girdir')
build_stamp = custom_target(
'doc_build_stamp',
command: [
gidocgen,
'generate',
'-C',
'@INPUT0@',
'--content-dir',
meson.current_source_dir(),
'--add-include-path',
girepository_folder,
'--output-dir',
'@OUTDIR@',
'@INPUT1@'
],
input: files('librsvg.toml') + rsvg_gir[0],
output: 'Rsvg-2.0',
install: true,
# custom_target will make an Rsvg-2.0 directory for us
install_dir: get_option('datadir') / 'doc'
)
endif
custom_target('man',
input: files(
'../rsvg-convert.rst'
),
output: '@BASENAME@.1',
command: [
rst2man,
'--syntax-highlight=none',
'@INPUT@',
'@OUTPUT@'
],
install: true,
install_dir: get_option('mandir') / 'man1',
)

336
doc/migrating.md Normal file
View File

@@ -0,0 +1,336 @@
---
Title: Migrating from old APIs
---
# Migrating from old APIs
## Migrating from the deprecated API that does not use viewports
First, some context. Until librsvg version 2.44, the only way to
render an [class@Rsvg.Handle] into a Cairo context was with the
functions [`rsvg_handle_render_cairo(handle,
cairo_t)`](method.Handle.render_cairo.html) and
[`rsvg_handle_render_cairo_sub(handle, cairo_t,
id)`](method.Handle.render_cairo_sub.html) — respectively, to
render the whole document, and to render a single \"layer\" from it.
Both functions assumed that the SVG document was to be rendered at its
\"natural size\", or to the size overridden with
[method@Rsvg.Handle.set_size_callback]. Since the Cairo context can already
have an affine transform applied to it, that transform can further
change the size of the rendered image.
Librsvg 2.46 introduced the following functions, designed to replace the
`render_cairo` ones:
* [method@Rsvg.Handle.render_document] - renders the whole document
* [method@Rsvg.Handle.render_layer] - renders a single layer
* [method@Rsvg.Handle.render_element] - renders a single element
* Plus corresponding functions to get the geometries of the
document/layer/element.
All of those functions take a viewport argument. Let\'s see what this
means. But first, some history.
### Historical note: before librsvg supported viewports
When librsvg was first written, its API basically consisted of only functions to
load an [class@Rsvg.Handle], plus `rsvg_handle_get_pixbuf()` to render it
directly to a GdkPixbuf image. Internally the library used libart (a pre-Cairo
2D rendering library), but did not expose it in the public API.
The only way to specify a size at which to render an [class@Rsvg.Handle] was
with [method@Rsvg.Handle.set_size_callback], and the callback would run at an
unspecified time during *loading*: when just enough of the SVG document had been
loaded to read in the `width/height` attributes of the toplevel `<svg>` element,
the callback would let the application override these values with its own
desired size.
Some years later, Cairo was introduced, and it started to replace libart. Unlike
libart, which could only render to in-memory RGBA buffers, Cairo had a notion of
\"backends\": it could render to RGBA buffers, or it could translate its drawing
model commands into PDF or PostScript. In Cairo\'s terms, one creates a
[`cairo_surface_t`][cairo_surface_t] of a particular kind (in-memory image
surface, PDF surface, EPS surface, etc.), and then a [`cairo_t`][cairo_t]
context for the surface. The context is what makes the drawing commands
available.
Being able to render SVG documents directly to PDF or PostScript was clearly
attractive, so librsvg\'s API of `rsvg_handle_get_pixbuf()` would clearly
not be enough. It would be better to pass a [`cairo_t`][cairo_t] for an
already-created surface, and have librsvg issue its drawing commands to it. Then
the application would be in control of the surface type, or in the case of GTK
widgets, they would already get a [`cairo_t`][cairo_t] passed to their drawing
functions. Librsvg got modified to export a
[`rsvg_handle_render_cairo(handle, cairo_t)`](method.Handle.render_cairo.html),
and then it reimplemented the old `rsvg_handle_get_pixbuf()` in terms of
Cairo.
At this point, librsvg still kept the notion of rendering SVG documents
at their \"natural size\": the `<svg>` element\'s `width` and `height`
attributes converted to pixels (e.g. converting from `width="5cm"` by
using the dots-per-inch value from the [class@Rsvg.Handle]), or if those
attributes don\'t exist, by using the `viewBox` as a pixel size. The
assumption was that if you needed a different size, you could always
start by setting the transformation matrix on your [`cairo_t`][cairo_t] and then
rendering to that.
[cairo_surface_t]: https://www.cairographics.org/manual/cairo-cairo-surface-t.html
[cairo_t]: https://www.cairographics.org/manual/cairo-cairo-t.html
### The problem with not having viewports
Most applications which use librsvg to render SVG assets for their user
interface generally work in the same way. For example, to take an SVG
icon and render it, they do something like this:
1. Create an [class@Rsvg.Handle] by loading it from the SVG icon data.
2. Ask the [class@Rsvg.Handle] for its dimensions.
3. Divide the dimensions by the GUI\'s preferred size for icons.
4. Translate a Cairo context so the icon will appear at the desired location.
Scale the Cairo context by the result of the previous step to obtain the
desired dimensions.
5. Render the [class@Rsvg.Handle] in that Cairo context.
This is\... too much work. The web world has moved on to using the CSS
box model practically everywhere. To embed an image you specify *where*
and at *what size* you want to place it, and it gets done automatically.
You actually have to do extra work if you want to do non-standard things
like scale an image non-proportionally.
### The new rendering API that uses viewports
Starting with librsvg 2.46, the following functions are available:
```c
typedef struct {
double x;
double y;
double width;
double height;
} RsvgRectangle;
gboolean rsvg_handle_render_document (RsvgHandle *handle,
cairo_t *cr,
const RsvgRectangle *viewport,
GError **error);
gboolean rsvg_handle_render_layer (RsvgHandle *handle,
cairo_t *cr,
const char *id,
const RsvgRectangle *viewport,
GError **error);
gboolean rsvg_handle_render_element (RsvgHandle *handle,
cairo_t *cr,
const char *id,
const RsvgRectangle *element_viewport,
GError **error);
```
For brevity we will omit the `rsvg_handle` namespace prefix, and just talk about
the actual function names. You can see that
[`render_document`](method.Handle.render_document.html) is basically the same as
[`render_cairo`](method.Handle.render_cairo.html), but it has an extra
`viewport` argument. The same occurs in
[`render_layer`](method.Handle.render_layer.html) versus
[`render_cairo_sub`](method.Handle.render_cairo_sub.html).
In both of those cases — [`render_document`](method.Handle.render_document.html)
and [`render_layer`](method.Handle.render_layer.html) —, the `viewport` argument
specifies a rectangle into which the SVG will be positioned and scaled to fit.
Consider something like this:
```c
RsvgRectangle viewport = {
.x = 10.0,
.y = 20.0,
.width = 640.0,
.height = 480.0,
};
rsvg_handle_render_document (handle, cr, &viewport, NULL);
```
This is equivalent to first figuring out the scaling factor to make the SVG fit
proportionally in 640×480 pixels, then translating the `cr` by (10, 20) pixels,
and then calling [method@Rsvg.Handle.render_cairo]. If the SVG has different
proportions than the width and height of the rectangle, it will be rendered and
centered to fit the rectangle.
---
**Note:** [method@Rsvg.Handle.render_element] is new in librsvg 2.46. It
extracts a single element from the SVG and renders it scaled to the viewport you
specify. It is different from `render_layer` (or the old-style
`render_cairo_sub`) in that those ones act as if they rendered the whole
## document\'s area, but they only paint the layer you specify
---
Even better: the old functions to get an SVG\'s natural dimensions, like
[method@Rsvg.Handle.get_dimensions], returned integers instead of floating-point
numbers, so you could not always get an exact fit. Please use the new
`get_geometry` functions that take viewports; they will give you easier and
better results:
* [method@Rsvg.Handle.get_geometry_for_layer]
* [method@Rsvg.Handle.get_geometry_for_element]
### New API for obtaining an SVG's dimensions
Per the previous section, you should seldom need to obtain the \"natural
size\" of an SVG document now that you can render it directly into a
viewport. But if you still need to know what the SVG document specifies
for its own size, you can use the following functions, depending on the
level of detail you require:
```c
gboolean rsvg_handle_get_intrinsic_size_in_pixels (RsvgHandle *handle,
gdouble *out_width,
gdouble *out_height);
```
[method@Rsvg.Handle.get_intrinsic_size_in_pixels] returns an exact width and
height in floating-point pixels. **You should round up to the next integer** if
you need to allocate a pixel buffer big enough, to avoid clipping the last
column or row of pixels, which may be only partially covered. For example, if a
document's width is `41.3` CSS pixels, you should create a raster image `42`
pixels wide so it fits without clipping the last pixel. You can do this with the
`ceil()` function.
[method@Rsvg.Handle.get_intrinsic_size_in_pixels] works by resolving the
`width/height` attributes of the toplevel `<svg>` element against the
handle\'s current DPI and the `font-size` that is defined for the
`<svg>` element.
However, that is only possible if the `width/height` attributes actually
exist and are in physical units. The function will return FALSE if the
SVG has no resolvable units, for example if the `width/height`
attributes are specified in percentages (e.g. `width="50%"`), since the
function has no knowledge of the viewport where you will place the SVG,
or if those attributes are not specified.
The other way of obtaining an SVG\'s dimensions is to actually query its
\"intrinsic dimensions\", i.e. what is actually specified in the SVG
document:
```c
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;
typedef struct {
double length;
RsvgUnit unit;
} RsvgLength;
void rsvg_handle_get_intrinsic_dimensions (RsvgHandle *handle,
gboolean *out_has_width,
RsvgLength *out_width,
gboolean *out_has_height,
RsvgLength *out_height,
gboolean *out_has_viewbox,
RsvgRectangle *out_viewbox);
```
[method@Rsvg.Handle.get_intrinsic_dimensions] will tell you precisely if the
toplevel `<svg>` has `width/height` attributes and their values, and also
whether it has a `viewBox` and its value.
---
**Note:** Remember that SVGs are *scalable*. They are not like raster images
which have an exact size in pixels, and which you must always take into account
to scale them to a convenient size. For SVGs, you can just render them to a
viewport, and avoid working directly with their size — which is kind of
arbitrary, and all that matters is the
## document's aspect ratio
---
### SVGs with no intrinsic dimensions nor aspect ratio
SVG documents that have none of the `width`, `height`, or `viewBox` attributes
are thankfully not very common, but they are hard to deal with: the software
cannot immediately know their natural size or aspect ratio, so they cannot be
easily scaled to fit within a viewport. If you need to measure the extents of
all the objects in an SVG document, you can use
[method@Rsvg.Handle.get_geometry_for_element] by passing `NULL` for the target
element's `id`; this will measure all the elements in the document.
## Migrating to the geometry APIs
Until librsvg 2.44, the available APIs to query the geometry of a layer
or element were these:
```c
struct _RsvgPositionData {
int x;
int y;
};
gboolean rsvg_handle_get_position_sub (RsvgHandle *handle,
RsvgPositionData *position_data,
const char *id);
struct _RsvgDimensionData {
int width;
int height;
gdouble em;
gdouble ex;
};
gboolean rsvg_handle_get_dimensions_sub (RsvgHandle *handle,
RsvgDimensionData *dimension_data,
const char *id);
```
These functions are inconvenient — separate calls to get the position
and dimensions —, and also inexact, since they only return integer
values, while SVG uses floating-point units.
Since librsvg 2.46, you can use these functions instead:
```c
typedef struct {
double x;
double y;
double width;
double height;
} RsvgRectangle;
gboolean rsvg_handle_get_geometry_for_layer (RsvgHandle *handle,
const char *id,
const RsvgRectangle *viewport,
RsvgRectangle *out_ink_rect,
RsvgRectangle *out_logical_rect,
GError **error);
gboolean rsvg_handle_get_geometry_for_element (RsvgHandle *handle,
const char *id,
RsvgRectangle *out_ink_rect,
RsvgRectangle *out_logical_rect,
GError **error);
```
These functions return exact floating-point values. They also give you
the ink rectangle, or area covered by paint, as well as the logical
rectangle, which is the extents of unstroked paths (i.e. just the
outlines).
* [method@Rsvg.Handle.get_geometry_for_layer]
* [method@Rsvg.Handle.get_geometry_for_element]

142
doc/overview.md Normal file
View File

@@ -0,0 +1,142 @@
---
Title: Overview of Librsvg
---
# Overview of Librsvg
Librsvg is a library for rendering Scalable Vector Graphics files (SVG).
Specifically, it can take non-animated, non-scripted SVG documents and
render them into a [Cairo](https://www.cairographics.org/) surface.
Normally this means an in-memory raster surface, but it could also be
any of the other surface types that Cairo supports.
Librsvg supports many of the graphic features in the [SVG
1.1](https://www.w3.org/TR/SVG/) and [SVG2](https://www.w3.org/TR/SVG2/)
specifications. The main features of SVG that librsvg does not support
are the following:
* Scripting or animation: Librsvg reads SVG data and renders it to a static
image. There is no provision to execute scripts that may control animation
parameters.
* Access to the DOM: Librsvg creates an internal representation of the SVG data,
but it does not provide outside access to the resulting Document Object Model
(DOM).
* SVG fonts: Instead, librsvg relies on the system's fonts, particularly those
that are available through Cairo/Pango.
Librsvg's API is divided into two main parts: one for loading SVG data
and one for rendering it. In the *loading stage*, you create an
[class@Rsvg.Handle] object from SVG data, which can come from a file or from a
stream of bytes. In the *rendering stage*, you take an [class@Rsvg.Handle] and
ask it to render itself to a Cairo context.
## Loading
[class@Rsvg.Handle] is an object that represents SVG data in memory. Your
program creates an [class@Rsvg.Handle] from an SVG file, or from a memory buffer
that contains SVG data, or in the most general form, from a
[class@Gio.InputStream] that will provide SVG data. At this stage you can get
either I/O errors or parsing errors. If loading completes successfully, the
[class@Rsvg.Handle] will be ready for rendering.
Generally you should use [ctor@Rsvg.Handle.new_from_gfile_sync] or
[ctor@Rsvg.Handle.new_from_stream_sync] to load an SVG document into an
[class@Rsvg.Handle]. There are other convenience functions to load an SVG
document, but these two functions let one set the "
[base file](class.Handle.html#the-base-file-and-resolving-references-to-external-files)
" and the [flags@Rsvg.HandleFlags] in a single call.
## Rendering
Once you have an SVG image loaded into an [class@Rsvg.Handle], you can render it
to a Cairo context any number of times, or to different Cairo contexts,
as needed. As a convenience, you can pick a single element in the SVG by
its `id` attribute and render only that element; this is so that
sub-elements can be extracted conveniently out of a larger SVG.
Generally you should use [method@Rsvg.Handle.render_document] to render the
whole SVG document at any size you choose into a Cairo context.
## Example: simple loading and rendering
The following program loads `hello.svg`, renders it scaled to fit within
640×480 pixels, and writes a `hello.png` file.
Note the following:
* [method@Rsvg.Handle.render_document] will scale the document proportionally
to fit the viewport you specify, and it will center the image within that
viewport.
* Librsvg does not paint a background color by default, so in the following
example all unfilled areas of the SVG will appear as fully transparent. If you
wish to have a specific background, fill the viewport area yourself before
rendering the SVG.
```c
/* gcc -Wall -g -O2 -o load-and-render load-and-render.c `pkg-config --cflags --libs rsvg-2.0` */
#include <stdlib.h>
#include <librsvg/rsvg.h>
#define WIDTH 640
#define HEIGHT 480
int
main (void)
{
/* First, load an SVG document into an RsvgHandle */
GError *error = NULL;
GFile *file = g_file_new_for_path ("hello.svg");
RsvgHandle *handle = rsvg_handle_new_from_gfile_sync (file, RSVG_HANDLE_FLAGS_NONE, NULL, &error);
if (!handle)
{
g_printerr ("could not load: %s", error->message);
exit (1);
}
/* Create a Cairo image surface and a rendering context for it */
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
cairo_t *cr = cairo_create (surface);
/* Set the dots-per-inch */
rsvg_handle_set_dpi (handle, 96.0);
/* Render the handle scaled proportionally into that whole surface */
RsvgRectangle viewport = {
.x = 0.0,
.y = 0.0,
.width = WIDTH,
.height = HEIGHT,
};
if (!rsvg_handle_render_document (handle, cr, &viewport, &error))
{
g_printerr ("could not render: %s", error->message);
exit (1);
}
/* Write a PNG file */
if (cairo_surface_write_to_png (surface, "hello.png") != CAIRO_STATUS_SUCCESS)
{
g_printerr ("could not write output file");
exit (1);
}
/* Free our memory and we are done! */
cairo_destroy (cr);
cairo_surface_destroy (surface);
g_object_unref (handle);
g_object_unref (file);
return 0;
}
```

243
doc/recommendations.md Normal file
View File

@@ -0,0 +1,243 @@
---
Title: Recommendations for Applications
---
# Recommendations for Applications
Let's consider two common cases for rendering SVG documents:
* Your application uses fixed-size assets, for example, "all icons at 16×16
pixels".
* Your application needs to accept arbitrarily-sized SVG documents, to either
render them at a fixed size, or to render them at a "natural" size.
In either case, librsvg assumes that for rendering you have already
obtained a Cairo surface, and a Cairo context to draw on the surface.
For the case of fixed-size assets, this is easy; you create a surface
of the size you know you want, and tell librsvg to render to it at
that exact size. For the case of wanting to use a "natural" size, you
first have to ask librsvg about the document's size so you can create
an appropriately-sized surface. Let's see how to do both cases.
## Rendering SVG assets at a fixed size
This is the case when you have a known `WIDTH` and `HEIGHT`, and you
want to tell librsvg to render an SVG at that size:
```c
GError *error = NULL;
GFile *file = g_file_new_for_path ("hello.svg");
RsvgHandle *handle = rsvg_handle_new_from_gfile_sync (file, RSVG_HANDLE_FLAGS_NONE, NULL, &error); /* 1 */
if (!handle)
{
g_error ("could not load: %s", error->message);
}
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT); /* 2 */
cairo_t *cr = cairo_create (surface);
/* Render the handle scaled proportionally into that whole surface */
RsvgRectangle viewport = { /* 3 */
.x = 0.0,
.y = 0.0,
.width = WIDTH,
.height = HEIGHT,
};
if (!rsvg_handle_render_document (handle, cr, &viewport, &error)) /* 4 */
{
g_error ("could not render: %s", error->message);
}
/* The surface is now rendered */
```
1. Load the SVG document.
2. Create an image surface of the size you want.
3. Declare a viewport of that size. If you want a non-zero `(x, y)` offset you
can set it right there.
4. Render the document within that viewport. Done!
This will scale the SVG document proportionally to make it fit in
`WIDTH×HEIGHT` pixels.
## Picking a "natural" size for SVG documents
In some cases, your application may not want to use a predefined size,
but instead query the SVG for a "natural" size at which to render. Some
SVG documents make this easy, and some don't.
### SVG documents with intrinsic dimensions in absolute units
Consider an SVG document that starts like this:
```xml
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100">
```
This is completely unambiguous; the SVG says that its intrinsic size
is 200×100 pixels. It can be scaled arbitrarily, but of course most
of the time you'll want to scale it proportionally at that 2:1 ratio.
Here is a slightly more complicated case:
```xml
<svg xmlns="http://www.w3.org/2000/svg" width="10cm" height="5cm">
```
The SVG says that its intrinsic size is 10cm × 5cm. This is not hard
to convert to pixels if you know the Dots-Per-Inch (DPI) at which you
want to render things, but it is a small inconvenience.
And here is a more complicated case still:
```xml
<svg xmlns="http://www.w3.org/2000/svg" width="10em" height="5em">
<style>
* { font-size: 2cm; }
</style>
```
This means that the width is 10 times the font size of 2cm, and the
height is 5 times the font size.
In general an application cannot figure this out easily, since it
would need a CSS parser and cascading engine to even be able to know
what the font size is for the toplevel `<svg>`. Fortunately, librsvg
already does that!
In all those cases, the width and height are in physical units (px,
cm, mm, etc.), or font-based units (em, ex) that can be resolved to
pixels. You can use [method@Rsvg.Handle.get_intrinsic_size_in_pixels]
to do the conversion easily if all you want to do is to create a
surface with the "natural" number of pixels:
```c
gboolean rsvg_handle_get_intrinsic_size_in_pixels (RsvgHandle *handle,
gdouble *out_width,
gdouble *out_height);
```
However, the documentation for [that
function](method.Handle.get_intrinsic_size_in_pixels.html) indicates
that it may return `FALSE` in some cases. Let's see what those ugly
cases are.
### SVG documents with just proportions
What if we have this:
```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
```
This document has no intrinsic dimensions, but it clearly states that
its *proportions* are 200:100, or 2:1. It will look good when scaled
to a rectangle that is twice as wide as it is tall. Our old friend
[method@Rsvg.Handle.render_document] will still scale the SVG
proportionally to fit the viewport size you pass in. But what if you
must pick a size yourself, instead of having a predefined viewport?
In that case you bite the bullet, call
[method@Rsvg.Handle.get_intrinsic_dimensions] and make your own choice
about what to do with the proportions that come in the `viewBox`:
```c
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;
typedef struct {
double length;
RsvgUnit unit;
} RsvgLength;
void rsvg_handle_get_intrinsic_dimensions (RsvgHandle *handle,
gboolean *out_has_width,
RsvgLength *out_width,
gboolean *out_has_height,
RsvgLength *out_height,
gboolean *out_has_viewbox,
RsvgRectangle *out_viewbox);
```
You'll cleverly note that I have not answered your question. You have
an SVG with only a `viewBox`, and you want to pick a reasonable size
to render it.
And here is where I want to say, SVG documents are **scalable**. Pick
a size, any size for a viewport! Here are some suggestions:
* The size of your window's visible area.
* The size of your device's screen.
* The size of your sheet of paper, minus the margins.
Take that size, pass it as the viewport size to
[method@Rsvg.Handle.render_document], and be done with it.
### SVG documents without any usable sizing information at all
This is pretty nasty, but *possibly* not useless for doing special
effects in web browsers:
```xml
<svg xmlns="http://www.w3.org/2000/svg">
```
That's right, no `width`, no `height`, no `viewBox`. There is no easy
way to figure out a suitable size for this. You have two options:
* Shrug your shoulders, and [method@Rsvg.Handle.render_document] with a
comfortable viewport size like in the last section.
* Do a best-effort job of actually computing the geometries of all the elements
in the document. You can use [method@Rsvg.Handle.get_geometry_for_element] by
passing `NULL` for the target element's `id`; this will measure all the
elements in the document. This is not expensive for typical SVGs, but it is
not "almost instantaneous" like just asking for intrinsic dimensions would be.
If this is starting to sound too complicated, please remember that
**SVG documents are scalable**. That's their whole reason for being!
Pick a size for a viewport, and ask librsvg to render the document
within that viewport with [method@Rsvg.Handle.render_document].
## Recommendations for applications with SVG assets
Before librsvg 2.46, applications would normally load an SVG asset, then
they would query librsvg for the SVG's size, and then they would
compute the dimensions of their user interface based on the SVG's size.
With librsvg 2.46 and later, applications may have an easier time by
letting the UI choose whatever size it wants, or by hardcoding a size
for SVG assets, and then asking librsvg to render SVG assets at that
particular size. Applications can use [method@Rsvg.Handle.render_document],
which takes a destination viewport, to do this in a single step.
To extract individual elements from an SVG document and render them in
arbitrary locations — for example, to extract a single icon from a
document full of icons —, applications can use
[method@Rsvg.Handle.render_element].
### Injecting a user stylesheet
It is sometimes convenient for applications to inject an extra
stylesheet while rendering an SVG document. You can do this with
[method@Rsvg.Handle.set_stylesheet]. During the CSS cascade, the specified
stylesheet will be used with a ["User"
origin](https://drafts.csswg.org/css-cascade-3/#cascading-origins).

10
doc/urlmap.js Normal file
View File

@@ -0,0 +1,10 @@
// A map between namespaces and base URLs for their online documentation
baseURLs = [
[ 'GLib', 'https://docs.gtk.org/glib/' ],
[ 'GObject', 'https://docs.gtk.org/gobject/' ],
[ 'Gio', 'https://docs.gtk.org/gio/' ],
[ 'Gdk', 'https://docs.gtk.org/gdk4/' ],
[ 'Pango', 'https://docs.gtk.org/Pango/' ],
[ 'PangoCairo', 'https://docs.gtk.org/PangoCairo/' ],
[ 'GdkPixbuf', 'https://docs.gtk.org/gdk-pixbuf/' ],
]