librsvg source for verification 2026-05-22
This commit is contained in:
32
doc/librsvg-r.svg
Normal file
32
doc/librsvg-r.svg
Normal 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
32
doc/librsvg.svg
Normal 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
39
doc/librsvg.toml
Normal 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
59
doc/load-and-render.c
Normal 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
51
doc/meson.build
Normal 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
336
doc/migrating.md
Normal 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
142
doc/overview.md
Normal 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
243
doc/recommendations.md
Normal 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
10
doc/urlmap.js
Normal 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/' ],
|
||||
]
|
||||
Reference in New Issue
Block a user