2017-09-03 16:14:25 +03:00
|
|
|
//
|
|
|
|
// SVG Image header file for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2020-06-07 17:57:40 +03:00
|
|
|
// Copyright 2017-2020 by Bill Spitzak and others.
|
2017-09-03 16:14:25 +03:00
|
|
|
//
|
|
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
|
|
// file is missing or damaged, see the license at:
|
|
|
|
//
|
2020-06-07 17:57:40 +03:00
|
|
|
// https://www.fltk.org/COPYING.php
|
2017-09-03 16:14:25 +03:00
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// Please see the following page on how to report bugs and issues:
|
2017-09-03 16:14:25 +03:00
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// https://www.fltk.org/bugs.php
|
2017-09-03 16:14:25 +03:00
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef FL_SVG_IMAGE_H
|
|
|
|
#define FL_SVG_IMAGE_H
|
|
|
|
|
|
|
|
#include <FL/Fl_Image.H>
|
|
|
|
|
|
|
|
struct NSVGimage;
|
|
|
|
|
|
|
|
/** The Fl_SVG_Image class supports loading, caching and drawing of scalable vector graphics (SVG) images.
|
2020-07-01 19:03:10 +03:00
|
|
|
The FLTK library performs parsing and rasterization of SVG data using a modified version
|
2020-06-07 17:57:40 +03:00
|
|
|
of the \c nanosvg software (https://github.com/memononen/nanosvg).
|
|
|
|
The software modification allows the option to change the image ratio
|
2017-09-03 16:14:25 +03:00
|
|
|
while performing rasterization.
|
2020-06-07 17:57:40 +03:00
|
|
|
|
2020-07-01 19:03:10 +03:00
|
|
|
Use Fl_Image::fail() to check if the Fl_SVG_Image failed to load. fail() returns ERR_FILE_ACCESS
|
|
|
|
if the file could not be opened or read, and ERR_FORMAT if the SVG format could not be decoded.
|
2017-09-03 16:14:25 +03:00
|
|
|
If the image has loaded correctly, w(), h(), and d() should return values greater than zero.
|
2020-06-07 17:57:40 +03:00
|
|
|
|
2020-07-01 19:03:10 +03:00
|
|
|
Rasterization is not done until the image is first drawn or resize() or normalize() is called. Therefore,
|
2018-03-19 20:43:18 +03:00
|
|
|
\ref array is NULL until then. The delayed rasterization ensures an Fl_SVG_Image is always rasterized
|
|
|
|
to the exact screen resolution at which it is drawn.
|
2020-06-07 17:57:40 +03:00
|
|
|
|
|
|
|
The Fl_SVG_Image class draws images computed by \c nanosvg with the following known limitations
|
2020-07-01 19:03:10 +03:00
|
|
|
|
2020-06-07 17:57:40 +03:00
|
|
|
- text between \c <text\> and </text\> marks,
|
|
|
|
- \c image elements, and
|
|
|
|
- <use\> statements
|
|
|
|
|
|
|
|
are not rendered.
|
|
|
|
|
2020-07-01 19:03:10 +03:00
|
|
|
The FLTK library can optionally be built without SVG support; in that case,
|
2017-09-03 16:14:25 +03:00
|
|
|
class Fl_SVG_Image is unavailable.
|
2017-10-31 19:56:23 +03:00
|
|
|
|
|
|
|
Example of displaying a hard-coded svg file:
|
|
|
|
\code
|
2020-06-07 17:57:40 +03:00
|
|
|
#include <FL/Fl.H>
|
|
|
|
#include <FL/Fl_Window.H>
|
|
|
|
#include <FL/Fl_Box.H>
|
|
|
|
#include <FL/Fl_SVG_Image.H>
|
|
|
|
|
|
|
|
// A black rotated rectangle
|
|
|
|
const char *svg_data = "<svg viewBox=\"0 0 200 200\" version = \"1.1\">\n"
|
|
|
|
"<rect x=\"25\" y=\"50\" width=\"150\" height=\"100\" fill=\"black\" "
|
|
|
|
"transform=\"rotate(45 100 100)\"> </svg>\n";
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
Fl_SVG_Image *svg = new Fl_SVG_Image(0, svg_data); // create SVG object
|
|
|
|
Fl_Window *win = new Fl_Window(720, 486, "svg test");
|
|
|
|
Fl_Box *box = new Fl_Box(0, 0, win->w(), win->h());
|
|
|
|
box->image(svg); // assign svg object to Fl_Box
|
|
|
|
win->end();
|
|
|
|
win->show(argc,argv);
|
|
|
|
return(Fl::run());
|
|
|
|
}
|
2017-10-31 19:56:23 +03:00
|
|
|
\endcode
|
|
|
|
|
|
|
|
Example of displaying an svg image from a file:
|
|
|
|
\code
|
2020-06-07 17:57:40 +03:00
|
|
|
#include <errno.h> // errno
|
|
|
|
#include <string.h> // strerror
|
|
|
|
#include <FL/Fl.H>
|
|
|
|
#include <FL/Fl_Window.H>
|
|
|
|
#include <FL/Fl_Box.H>
|
|
|
|
#include <FL/Fl_SVG_Image.H>
|
|
|
|
#include <FL/fl_message.H>
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
Fl_Window *win = new Fl_Window(720, 486, "svg test");
|
|
|
|
Fl_Box *box = new Fl_Box(0, 0, win->w(), win->h());
|
|
|
|
|
|
|
|
// Load svg image from disk, assign to a box
|
|
|
|
const char *svgpath = "/var/tmp/simple.svg";
|
|
|
|
Fl_SVG_Image *svg = new Fl_SVG_Image(svgpath); // load SVG object from disk
|
|
|
|
switch (svg->fail()) {
|
|
|
|
case Fl_Image::ERR_FILE_ACCESS:
|
|
|
|
// File couldn't load? show path + os error to user
|
|
|
|
fl_alert("%s: %s", svgpath, strerror(errno));
|
|
|
|
return 1;
|
|
|
|
case Fl_Image::ERR_FORMAT:
|
|
|
|
// Parsing error
|
|
|
|
fl_alert("%s: couldn't decode image", svgpath);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
box->image(svg); // assign svg object to box
|
|
|
|
|
|
|
|
win->end();
|
|
|
|
win->show(argc,argv);
|
|
|
|
return(Fl::run());
|
|
|
|
}
|
2017-10-31 19:56:23 +03:00
|
|
|
\endcode
|
|
|
|
|
2019-08-27 19:38:56 +03:00
|
|
|
Example of fitting an svg image to a resizable Fl_Box:
|
|
|
|
\code
|
2020-06-07 17:57:40 +03:00
|
|
|
#include <FL/Fl_Window.H>
|
|
|
|
#include <FL/Fl_SVG_Image.H>
|
|
|
|
#include <FL/Fl_Box.H>
|
|
|
|
|
|
|
|
class resizable_box : public Fl_Box {
|
|
|
|
public:
|
2019-08-27 19:38:56 +03:00
|
|
|
resizable_box(int w, int h) : Fl_Box(0, 0, w, h, NULL) {}
|
|
|
|
virtual void resize(int x, int y, int w, int h) {
|
2020-06-07 17:57:40 +03:00
|
|
|
image()->scale(w, h, 1, 1); // p3 = proportional, p4 = can_expand
|
|
|
|
Fl_Box::resize(x, y, w, h);
|
2019-08-27 19:38:56 +03:00
|
|
|
}
|
2020-06-07 17:57:40 +03:00
|
|
|
};
|
2020-07-01 19:03:10 +03:00
|
|
|
|
2020-06-07 17:57:40 +03:00
|
|
|
int main(int argc, char **argv) {
|
|
|
|
Fl_Window *win = new Fl_Window(130, 130);
|
|
|
|
resizable_box *box = new resizable_box(win->w(), win->h());
|
|
|
|
Fl_SVG_Image *svg = new Fl_SVG_Image("/path/to/image.svg");
|
|
|
|
box->image(svg);
|
|
|
|
svg->scale(box->w(), box->h());
|
|
|
|
win->end();
|
|
|
|
win->resizable(win);
|
|
|
|
win->show(argc, argv);
|
|
|
|
return Fl::run();
|
|
|
|
}
|
2019-08-27 19:38:56 +03:00
|
|
|
\endcode
|
|
|
|
|
2017-09-03 16:14:25 +03:00
|
|
|
*/
|
|
|
|
class FL_EXPORT Fl_SVG_Image : public Fl_RGB_Image {
|
|
|
|
private:
|
|
|
|
typedef struct {
|
|
|
|
NSVGimage* svg_image;
|
|
|
|
int ref_count;
|
|
|
|
} counted_NSVGimage;
|
|
|
|
counted_NSVGimage* counted_svg_image_;
|
|
|
|
bool rasterized_;
|
|
|
|
int raster_w_, raster_h_;
|
|
|
|
bool to_desaturate_;
|
|
|
|
Fl_Color average_color_;
|
|
|
|
float average_weight_;
|
|
|
|
float svg_scaling_(int W, int H);
|
|
|
|
void rasterize_(int W, int H);
|
2020-11-18 12:03:02 +03:00
|
|
|
virtual void cache_size_(int &width, int &height);
|
2022-03-20 21:59:22 +03:00
|
|
|
void init_(const char *filename, const char *filedata, const Fl_SVG_Image *copy_source);
|
|
|
|
Fl_SVG_Image(const Fl_SVG_Image *source);
|
2017-09-03 16:14:25 +03:00
|
|
|
public:
|
|
|
|
/** Set this to \c false to allow image re-scaling that alters the image aspect ratio.
|
2017-11-03 12:04:56 +03:00
|
|
|
Upon object creation, proportional is set to \c true, and the aspect ratio is kept constant.*/
|
2017-09-03 16:14:25 +03:00
|
|
|
bool proportional;
|
2017-11-03 12:04:56 +03:00
|
|
|
Fl_SVG_Image(const char *filename, const char *svg_data = NULL);
|
2017-09-03 16:14:25 +03:00
|
|
|
virtual ~Fl_SVG_Image();
|
2022-03-20 21:59:22 +03:00
|
|
|
virtual Fl_Image *copy(int W, int H) const;
|
|
|
|
Fl_Image *copy() const {
|
|
|
|
return Fl_Image::copy();
|
|
|
|
}
|
2017-09-03 16:14:25 +03:00
|
|
|
void resize(int width, int height);
|
|
|
|
virtual void desaturate();
|
|
|
|
virtual void color_average(Fl_Color c, float i);
|
|
|
|
virtual void draw(int X, int Y, int W, int H, int cx = 0, int cy = 0);
|
|
|
|
void draw(int X, int Y) { draw(X, Y, w(), h(), 0, 0); }
|
2021-08-27 15:52:43 +03:00
|
|
|
virtual Fl_SVG_Image *as_svg_image() { return this; }
|
2020-06-15 20:05:34 +03:00
|
|
|
virtual void normalize();
|
2017-09-03 16:14:25 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // FL_SVG_IMAGE_H
|