diff options
author | Reizner Evgeniy <razrfalcon@gmail.com> | 2018-04-23 15:49:21 +0300 |
---|---|---|
committer | Reizner Evgeniy <razrfalcon@gmail.com> | 2018-04-23 15:49:21 +0300 |
commit | f78f5601e69d298106b147ccf48d95c3dc24647f (patch) | |
tree | 3b8cf4aae02f4dda8a76bdd9a8ad8e6675ce5dc6 /capi | |
parent | 2a05593f7feb4a63993b49be1c5b9cbbcaa69afe (diff) |
C-API updated.
Diffstat (limited to 'capi')
-rw-r--r-- | capi/.gitignore | 1 | ||||
-rw-r--r-- | capi/include/Doxyfile | 5 | ||||
-rw-r--r-- | capi/include/resvg.h | 282 | ||||
-rw-r--r-- | capi/src/lib.rs | 100 |
4 files changed, 324 insertions, 64 deletions
diff --git a/capi/.gitignore b/capi/.gitignore new file mode 100644 index 0000000..eacffab --- /dev/null +++ b/capi/.gitignore @@ -0,0 +1 @@ +/include/html diff --git a/capi/include/Doxyfile b/capi/include/Doxyfile new file mode 100644 index 0000000..d143338 --- /dev/null +++ b/capi/include/Doxyfile @@ -0,0 +1,5 @@ +PROJECT_NAME = "resvg C-API" +OPTIMIZE_OUTPUT_FOR_C = YES +QUIET = YES +GENERATE_LATEX = NO +ENABLE_PREPROCESSING = NO diff --git a/capi/include/resvg.h b/capi/include/resvg.h index b301db9..55eb2f8 100644 --- a/capi/include/resvg.h +++ b/capi/include/resvg.h @@ -1,74 +1,155 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/** + * @file resvg.h + * + * resvg C-API + */ #ifndef RESVG_H #define RESVG_H #include <stdbool.h> +#include <stdint.h> #ifdef RESVG_CAIRO_BACKEND #include <cairo.h> #endif +/** + * @brief An opaque pointer to the global library handle. + * + * Must be invoked before any other \b resvg code. + * + * Currently, handles \b QGuiApplication object which must be created + * in order to draw text. If you don't plan to draw text - it's better to skip + * the initialization. + * + * If you are using this library from an existing Qt application you can skip it. + * + * Does nothing when only \b cairo backend is enabled/used. + * + * \b Note: \b QGuiApplication initialization is pretty slow (up to 100ms). + */ typedef struct resvg_handle resvg_handle; + +/** + * @brief An opaque pointer to the rendering tree. + */ typedef struct resvg_render_tree resvg_render_tree; +/** + * @brief An RGB color representation. + */ typedef struct resvg_color { - unsigned char r; - unsigned char g; - unsigned char b; + uint8_t r; /**< Red component. */ + uint8_t g; /**< Green component. */ + uint8_t b; /**< Blue component. */ } resvg_color; +/** + * @brief A "fit to" type. + * + * All types produce proportional scaling. + */ typedef enum resvg_fit_to_type { - RESVG_FIT_TO_ORIGINAL, - RESVG_FIT_TO_WIDTH, - RESVG_FIT_TO_HEIGHT, - RESVG_FIT_TO_ZOOM, + RESVG_FIT_TO_ORIGINAL, /**< Use an original image size. */ + RESVG_FIT_TO_WIDTH, /**< Fit an image to a specified width. */ + RESVG_FIT_TO_HEIGHT, /**< Fit an image to a specified height. */ + RESVG_FIT_TO_ZOOM, /**< Zoom an image using scaling factor */ } resvg_fit_to_type; +/** + * @brief A "fit to" property. + */ typedef struct resvg_fit_to { - resvg_fit_to_type type; - float value; + resvg_fit_to_type type; /**< Fit type. */ + float value; /**< Fit to value. Must be > 0. */ } resvg_fit_to; +/** + * @brief Rendering options. + */ typedef struct resvg_options { + /// SVG image path. Used to resolve relative image paths. const char *path; + /// Output DPI. Default: 96. double dpi; + /// Fits the image using specified options. + /// Default: \b RESVG_FIT_TO_ORIGINAL. resvg_fit_to fit_to; + /// Draw background. Default: false. bool draw_background; + /// Background color. resvg_color background; + /// Keep named groups. If set to \b true, all non-empty + /// groups with \b id attribute will not be removed. bool keep_named_groups; } resvg_options; +/** + * @brief A rectangle representation. + */ typedef struct resvg_rect { - double x; - double y; - double width; - double height; + double x; /**< X position. */ + double y; /**< Y position. */ + double width; /**< Width. */ + double height; /**< Height. */ } resvg_rect; +/** + * @brief A size representation. + */ typedef struct resvg_size { - unsigned int width; - unsigned int height; + uint32_t width; /**< Width. */ + uint32_t height; /**< Height. */ } resvg_size; +/** + * @brief A 2D transform representation. + */ typedef struct resvg_transform { - double a; - double b; - double c; - double d; - double e; - double f; + double a; /**< \b a value */ + double b; /**< \b b value */ + double c; /**< \b c value */ + double d; /**< \b d value */ + double e; /**< \b e value */ + double f; /**< \b f value */ } resvg_transform; - +/** + * @brief Initializes the library. + * + * See #resvg_handle for details. + * + * @return Library handle. + */ resvg_handle* resvg_init(); + +/** + * @brief Destroys the #resvg_handle. + * + * @param handle Library handle. + */ void resvg_destroy(resvg_handle *handle); +/** + * @brief Initializes the library log. + * + * Use it if you want to see any warnings. + * + * All warnings will be printed to the \b stderr. + */ void resvg_init_log(); +/** + * @brief Initializes the #resvg_options structure. + */ void resvg_init_options(resvg_options *opt) { opt->path = NULL; @@ -76,93 +157,212 @@ void resvg_init_options(resvg_options *opt) opt->fit_to.type = RESVG_FIT_TO_ORIGINAL; opt->fit_to.value = 0; opt->draw_background = false; + opt->background.r = 0; + opt->background.g = 0; + opt->background.b = 0; opt->keep_named_groups = false; } /** - * @brief Creates <b>resvg_render_tree</b> from file. + * @brief Creates #resvg_render_tree from file. * * .svg and .svgz files are supported. * - * @param file_path UTF-8 file path. Will panic on NULL value. - * @param dpi Target DPI. Impact units converting and text rendering. - * @param error The error string if NULL is returned. Should be destroyed via resvg_error_msg_destroy. - * @return Parsed render tree. NULL on error. Should be destroyed via resvg_rtree_destroy. + * @param file_path UTF-8 file path. + * @param opt Rendering options. + * @param error The error string if NULL was returned. Should be destroyed via #resvg_error_msg_destroy. + * @return Parsed render tree. NULL on error. Should be destroyed via #resvg_rtree_destroy. */ resvg_render_tree *resvg_parse_rtree_from_file(const char *file_path, const resvg_options *opt, char **error); /** - * @brief Creates <b>resvg_render_tree</b> from UTF-8 string. + * @brief Creates #resvg_render_tree from UTF-8 string. * - * @param text UTF-8 string. Will panic on NULL value. - * @param dpi Target DPI. Impact units converting and text rendering. - * @param error The error string if NULL is returned. Should be destroyed via resvg_error_msg_destroy. - * @return Parsed render tree. NULL on error. Should be destroyed via resvg_rtree_destroy. + * @param text UTF-8 string. + * @param opt Rendering options. + * @param error The error string if NULL was returned. Should be destroyed via #resvg_error_msg_destroy. + * @return Parsed render tree. NULL on error. Should be destroyed via #resvg_rtree_destroy. */ resvg_render_tree *resvg_parse_rtree_from_data(const char *text, const resvg_options *opt, char **error); -void resvg_get_image_size(const resvg_render_tree *rtree, - double *width, - double *height); +/** + * @brief Returns an image size. + * + * @param rtree Render tree. + * @return Image size. + */ +resvg_size resvg_get_image_size(const resvg_render_tree *rtree); + +/** + * @brief Returns an image viewbox. + * + * @param rtree Render tree. + * @return Image viewbox. + */ +resvg_rect resvg_get_image_viewbox(const resvg_render_tree *rtree); +/** + * @brief Returns \b true if a node with such an ID exists. + * + * @param rtree Render tree. + * @param id Node's ID. UTF-8 string. + * @return \b true if a node exists. \b false if a node doesn't exist or ID isn't a UTF-8 string. + */ bool resvg_node_exists(const resvg_render_tree *rtree, const char *id); +/** + * @brief Returns node's transform by ID. + * + * @param rtree Render tree. + * @param id Node's ID. UTF-8 string. + * @param ts Node's transform. + * @return \b false if a node with such an ID does not exist or ID isn't a UTF-8 string. + */ bool resvg_get_node_transform(const resvg_render_tree *rtree, const char *id, resvg_transform *ts); +/** + * @brief Destroys the #resvg_render_tree. + * + * @param rtree Render tree. + */ void resvg_rtree_destroy(resvg_render_tree *rtree); +/** + * @brief Destroys the error message. + * + * @param msg Error message. + */ void resvg_error_msg_destroy(char *msg); #ifdef RESVG_CAIRO_BACKEND +/** + * @brief Returns node's bounding box by ID. + * + * @param rtree Render tree. + * @param opt Rendering options. + * @param id Node's ID. + * @param bbox Node's bounding box. + * @return \b false if a node with such an ID does not exist + * @return \b false if ID isn't a UTF-8 string. + * @return \b false if ID is an empty string + */ bool resvg_cairo_get_node_bbox(const resvg_render_tree *rtree, const resvg_options *opt, const char *id, resvg_rect *bbox); +/** + * @brief Renders the #resvg_render_tree to file. + * + * @param rtree Render tree. + * @param opt Rendering options. + * @param file_path File path. + * @return \b false if \b file_path isn't an UTF-8 string. + * @return \b false on "Out of memory". + * @return \b false on file write error. + */ bool resvg_cairo_render_to_image(const resvg_render_tree *rtree, const resvg_options *opt, const char *file_path); +/** + * @brief Renders the #resvg_render_tree to canvas. + * + * @param rtree Render tree. + * @param opt Rendering options. + * @param size Canvas size. + * @param cr Canvas. + */ void resvg_cairo_render_to_canvas(const resvg_render_tree *rtree, const resvg_options *opt, resvg_size size, cairo_t *cr); +/** + * @brief Renders a Node by ID to canvas. + * + * Does nothing on error. + * + * @param rtree Render tree. + * @param opt Rendering options. + * @param size Canvas size. + * @param id Node's ID. + * @param cr Canvas. + */ void resvg_cairo_render_to_canvas_by_id(const resvg_render_tree *rtree, const resvg_options *opt, resvg_size size, const char *id, - void *painter); -#endif + cairo_t *cr); +#endif // RESVG_CAIRO_BACKEND #ifdef RESVG_QT_BACKEND +/** + * @brief Returns node's bounding box by ID. + * + * @param rtree Render tree. + * @param opt Rendering options. + * @param id Node's ID. + * @param bbox Node's bounding box. + * @return \b false if a node with such an ID does not exist, + * ID is an empty string or ID isn't a UTF-8 string. + */ bool resvg_qt_get_node_bbox(const resvg_render_tree *rtree, const resvg_options *opt, const char *id, resvg_rect *bbox); +/** + * @brief Renders the #resvg_render_tree to file. + * + * @param rtree Render tree. + * @param opt Rendering options. + * @param file_path File path. + * @return \b false if \b file_path isn't an UTF-8 string. + * @return \b false on "Out of memory". + * @return \b false on file write error. + */ bool resvg_qt_render_to_image(const resvg_render_tree *rtree, const resvg_options *opt, const char *file_path); +/** + * @brief Renders the #resvg_render_tree to canvas. + * + * @param rtree Render tree. + * @param opt Rendering options. + * @param size Canvas size. + * @param painter Canvas. + */ void resvg_qt_render_to_canvas(const resvg_render_tree *rtree, const resvg_options *opt, resvg_size size, void *painter); +/** + * @brief Renders a Node by ID to canvas. + * + * Does nothing on error. + * + * @param rtree Render tree. + * @param opt Rendering options. + * @param size Canvas size. + * @param id Node's ID. + * @param painter Canvas. + */ void resvg_qt_render_to_canvas_by_id(const resvg_render_tree *rtree, const resvg_options *opt, resvg_size size, const char *id, void *painter); -#endif +#endif // RESVG_QT_BACKEND #endif // RESVG_H diff --git a/capi/src/lib.rs b/capi/src/lib.rs index 7c7fad9..3329d11 100644 --- a/capi/src/lib.rs +++ b/capi/src/lib.rs @@ -16,13 +16,8 @@ extern crate cairo_sys; use std::fmt; use std::path; use std::ptr; -use std::ffi::{ - CStr, - CString, -}; -use std::os::raw::{ - c_char, -}; +use std::ffi::{ CStr, CString }; +use std::os::raw::c_char; #[cfg(feature = "qt-backend")] use resvg::qt; @@ -156,7 +151,10 @@ pub extern fn resvg_parse_rtree_from_file( None => on_err!(error, "Error: file path is not an UTF-8 string."), }; - let opt = to_native_opt(unsafe { &*opt }); + let opt = to_native_opt(unsafe { + assert!(!opt.is_null()); + &*opt + }); let rtree = match resvg::parse_rtree_from_file(file_path, &opt) { Ok(rtree) => rtree, @@ -178,7 +176,10 @@ pub extern fn resvg_parse_rtree_from_data( None => on_err!(error, "Error: SVG data is not an UTF-8 string."), }; - let opt = to_native_opt(unsafe { &*opt }); + let opt = to_native_opt(unsafe { + assert!(!opt.is_null()); + &*opt + }); let rtree = resvg::parse_rtree_from_data(text, &opt); @@ -240,7 +241,10 @@ fn render_to_image( None => return false, }; - let opt = to_native_opt(unsafe { &*opt }); + let opt = to_native_opt(unsafe { + assert!(!opt.is_null()); + &*opt + }); let img = backend.render_to_image(&rtree.0, &opt); let img = match img { @@ -269,7 +273,10 @@ pub extern fn resvg_qt_render_to_canvas( let painter = unsafe { qt::Painter::from_raw(painter) }; let size = resvg::ScreenSize::new(size.width, size.height); - let opt = to_native_opt(unsafe { &*opt }); + let opt = to_native_opt(unsafe { + assert!(!opt.is_null()); + &*opt + }); resvg::render_qt::render_to_canvas(&rtree.0, &opt, size, &painter); } @@ -292,7 +299,10 @@ pub extern fn resvg_cairo_render_to_canvas( let cr = unsafe { cairo::Context::from_glib_none(cr) }; let size = resvg::ScreenSize::new(size.width, size.height); - let opt = to_native_opt(unsafe { &*opt }); + let opt = to_native_opt(unsafe { + assert!(!opt.is_null()); + &*opt + }); resvg::render_cairo::render_to_canvas(&rtree.0, &opt, size, &cr); } @@ -313,22 +323,34 @@ pub extern fn resvg_qt_render_to_canvas_by_id( let painter = unsafe { qt::Painter::from_raw(painter) }; let size = resvg::ScreenSize::new(size.width, size.height); - let opt = to_native_opt(unsafe { &*opt }); + let opt = to_native_opt(unsafe { + assert!(!opt.is_null()); + &*opt + }); let id = match cstr_to_str(id) { Some(v) => v, None => return, }; + if id.is_empty() { + warn!("Node with an empty ID can not be painted."); + return; + } + if let Some(node) = rtree.0.node_by_svg_id(id) { if let Some(bbox) = resvg::render_qt::calc_node_bbox(&node, &opt) { let vbox = tree::ViewBox { rect: bbox, - .. tree::ViewBox::default() + aspect: tree::AspectRatio::default(), }; resvg::render_qt::render_node_to_canvas(&node, &opt, vbox, size, &painter); + } else { + warn!("A node with '{}' ID doesn't have a valid bounding box.", id); } + } else { + warn!("A node with '{}' ID wasn't found.", id); } } @@ -351,31 +373,41 @@ pub extern fn resvg_cairo_render_to_canvas_by_id( None => return, }; + if id.is_empty() { + warn!("Node with an empty ID can not be painted."); + return; + } + use glib::translate::FromGlibPtrNone; let cr = unsafe { cairo::Context::from_glib_none(cr) }; let size = resvg::ScreenSize::new(size.width, size.height); - let opt = to_native_opt(unsafe { &*opt }); + let opt = to_native_opt(unsafe { + assert!(!opt.is_null()); + &*opt + }); if let Some(node) = rtree.0.node_by_svg_id(id) { if let Some(bbox) = resvg::render_cairo::calc_node_bbox(&node, &opt) { let vbox = tree::ViewBox { rect: bbox, - .. tree::ViewBox::default() + aspect: tree::AspectRatio::default(), }; resvg::render_cairo::render_node_to_canvas(&node, &opt, vbox, size, &cr); + } else { + warn!("A node with '{}' ID doesn't have a valid bounding box.", id); } + } else { + warn!("A node with '{}' ID wasn't found.", id); } } #[no_mangle] pub extern fn resvg_get_image_size( rtree: *const resvg_render_tree, - width: *mut f64, - height: *mut f64, -) { +) -> resvg_size { let rtree = unsafe { assert!(!rtree.is_null()); &*rtree @@ -383,9 +415,28 @@ pub extern fn resvg_get_image_size( let size = rtree.0.svg_node().size; - unsafe { - *width = size.width; - *height = size.height; + resvg_size { + width: size.width as u32, + height: size.height as u32, + } +} + +#[no_mangle] +pub extern fn resvg_get_image_viewbox( + rtree: *const resvg_render_tree, +) -> resvg_rect { + let rtree = unsafe { + assert!(!rtree.is_null()); + &*rtree + }; + + let r = rtree.0.svg_node().view_box.rect; + + resvg_rect { + x: r.x(), + y: r.y(), + width: r.width(), + height: r.height(), } } @@ -439,7 +490,10 @@ fn get_node_bbox( }; - let opt = to_native_opt(unsafe { &*opt }); + let opt = to_native_opt(unsafe { + assert!(!opt.is_null()); + &*opt + }); match rtree.0.node_by_svg_id(id) { Some(node) => { |