summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/Fl_SVG_Image.cxx206
-rw-r--r--src/Makefile3
-rw-r--r--src/fl_images_core.cxx9
4 files changed, 217 insertions, 2 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 34167488c..5c6532a59 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -367,6 +367,7 @@ set (IMGCPPFILES
Fl_JPEG_Image.cxx
Fl_PNG_Image.cxx
Fl_PNM_Image.cxx
+ Fl_SVG_Image.cxx
)
set (CFILES
diff --git a/src/Fl_SVG_Image.cxx b/src/Fl_SVG_Image.cxx
new file mode 100644
index 000000000..0e04f8201
--- /dev/null
+++ b/src/Fl_SVG_Image.cxx
@@ -0,0 +1,206 @@
+//
+// "$Id: Fl_SVG_Image.cxx 12239 2017-05-17 11:54:18Z manolo $"
+//
+// SVG image code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2017 by Bill Spitzak and others.
+//
+// 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+#include <config.h>
+
+#if defined(FLTK_USE_NANOSVG) || defined(FL_DOXYGEN)
+
+#include <FL/Fl_SVG_Image.H>
+#include <stdio.h>
+
+#define NANOSVG_ALL_COLOR_KEYWORDS // Include full list of color keywords.
+#define NANOSVG_IMPLEMENTATION // Expands implementation
+#include "../nanosvg/nanosvg.h"
+
+#define NANOSVGRAST_IMPLEMENTATION // Expands implementation
+#include "../nanosvg/altsvgrast.h"
+
+
+/** The constructor loads the SVG image from the given .svg filename or in-memory data.
+ \param filename A full path and name pointing to an SVG file.
+ \param filedata A pointer to the memory location of the SVG image data.
+ This parameter allows to load an SVG image from in-memory data, and requires that \p filename is NULL.
+ \note In-memory SVG data is modified by the object constructor and is no longer used after construction.
+ */
+Fl_SVG_Image::Fl_SVG_Image(const char *filename, char *filedata) : Fl_RGB_Image(NULL, 0, 0, 4) {
+ init_(filename, filedata, NULL);
+}
+
+
+// private constructor
+Fl_SVG_Image::Fl_SVG_Image(Fl_SVG_Image *source) : Fl_RGB_Image(NULL, 0, 0, 4) {
+ init_(NULL, NULL, source);
+}
+
+
+/** The destructor frees all memory and server resources that are used by the SVG image. */
+Fl_SVG_Image::~Fl_SVG_Image() {
+ if ( --counted_svg_image_->ref_count <= 0) {
+ nsvgDelete(counted_svg_image_->svg_image);
+ delete counted_svg_image_;
+ }
+}
+
+
+float Fl_SVG_Image::svg_scaling_(int W, int H) {
+ float f1 = float(W) / int(counted_svg_image_->svg_image->width+0.5);
+ float f2 = float(H) / int(counted_svg_image_->svg_image->height+0.5);
+ return (f1 < f2) ? f1 : f2;
+}
+
+
+void Fl_SVG_Image::init_(const char *filename, char *filedata, Fl_SVG_Image *copy_source) {
+ if (copy_source) {
+ filename = filedata = NULL;
+ counted_svg_image_ = copy_source->counted_svg_image_;
+ counted_svg_image_->ref_count++;
+ } else {
+ counted_svg_image_ = new counted_NSVGimage;
+ counted_svg_image_->svg_image = NULL;
+ counted_svg_image_->ref_count = 1;
+ }
+ to_desaturate_ = false;
+ average_weight_ = 1;
+ proportional = true;
+ if (filename) {
+ filedata = NULL;
+ FILE *fp = fopen(filename, "rb");
+ if (fp) {
+ fseek(fp, 0, SEEK_END);
+ size_t size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ filedata = (char*)malloc(size+1);
+ if (filedata) {
+ if (fread(filedata, 1, size, fp) == size) filedata[size] = '\0';
+ else {
+ free(filedata);
+ filedata = NULL;
+ }
+ }
+ fclose(fp);
+ } else ld(ERR_FILE_ACCESS);
+ }
+ if (filedata) {
+ counted_svg_image_->svg_image = nsvgParse(filedata, "px", 96);
+ if (filename) free(filedata);
+ if (counted_svg_image_->svg_image->width == 0 || counted_svg_image_->svg_image->height == 0) {
+ d(-1);
+ ld(ERR_FORMAT);
+ } else {
+ w(counted_svg_image_->svg_image->width + 0.5);
+ h(counted_svg_image_->svg_image->height + 0.5);
+ }
+ } else if (copy_source) {
+ w(copy_source->w());
+ h(copy_source->h());
+ }
+ rasterized_ = false;
+}
+
+
+void Fl_SVG_Image::rasterize_(int W, int H) {
+ static NSVGrasterizer *rasterizer = nsvgCreateRasterizer();
+ double fx, fy;
+ if (proportional) {
+ fx = svg_scaling_(W, H);
+ fy = fx;
+ } else {
+ fx = (double)W / counted_svg_image_->svg_image->width;
+ fy = (double)H / counted_svg_image_->svg_image->height;
+ }
+ array = new uchar[W*H*4];
+ nsvgAltRasterize(rasterizer, counted_svg_image_->svg_image, 0, 0, fx, fy, (uchar* )array, W, H, W*4);
+ alloc_array = 1;
+ data((const char * const *)&array, 1);
+ d(4);
+ if (to_desaturate_) Fl_RGB_Image::desaturate();
+ if (average_weight_ < 1) Fl_RGB_Image::color_average(average_color_, average_weight_);
+ rasterized_ = true;
+ raster_w_ = W;
+ raster_h_ = H;
+}
+
+
+Fl_Image *Fl_SVG_Image::copy(int W, int H) {
+ Fl_SVG_Image *svg2 = new Fl_SVG_Image(this);
+ svg2->to_desaturate_ = to_desaturate_;
+ svg2->average_weight_ = average_weight_;
+ svg2->average_color_ = average_color_;
+ svg2->w(W); svg2->h(H);
+ return svg2;
+}
+
+
+/** Have the svg data (re-)rasterized using the given width and height values.
+ By default, the resulting image width and height will preserve the width/height ratio
+ of the SVG data.
+ If \ref proportional was set to false, the image is rasterized to the given \c width
+ and \v height values.*/
+void Fl_SVG_Image::resize(int width, int height) {
+ if (ld() < 0) {
+ return;
+ }
+ int w1 = width, h1 = height;
+ if (proportional) {
+ float f = svg_scaling_(width, height);
+ w1 = int( int(counted_svg_image_->svg_image->width+0.5)*f + 0.5 );
+ h1 = int( int(counted_svg_image_->svg_image->height+0.5)*f + 0.5 );
+ }
+ w(w1); h(h1);
+ if (rasterized_ && w1 == raster_w_ && h1 == raster_h_) return;
+ if (array) {
+ delete[] array;
+ array = NULL;
+ }
+ uncache();
+ rasterize_(w1, h1);
+}
+
+
+void Fl_SVG_Image::draw(int X, int Y, int W, int H, int cx, int cy) {
+ resize(w(), h());
+ Fl_RGB_Image::draw(X, Y, W, H, cx, cy);
+}
+
+
+void Fl_SVG_Image::desaturate() {
+ to_desaturate_ = true;
+ Fl_RGB_Image::desaturate();
+}
+
+
+void Fl_SVG_Image::color_average(Fl_Color c, float i) {
+ average_color_ = c;
+ average_weight_ = i;
+ Fl_RGB_Image::color_average(c, i);
+}
+
+
+int Fl_SVG_Image::draw_scaled_(int X, int Y, int W, int H) {
+ w(W);
+ h(H);
+ draw(X, Y, W, H, 0, 0);
+ return 1;
+}
+
+#endif // FLTK_USE_NANOSVG
+
+
+//
+// End of "$Id: Fl_SVG_Image.cxx 12239 2017-05-17 11:54:18Z manolo $".
+//
diff --git a/src/Makefile b/src/Makefile
index 3c7575981..5803413b3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -209,7 +209,8 @@ IMGCPPFILES = \
Fl_Help_Dialog.cxx \
Fl_JPEG_Image.cxx \
Fl_PNG_Image.cxx \
- Fl_PNM_Image.cxx
+ Fl_PNM_Image.cxx \
+ Fl_SVG_Image.cxx
CFILES = fl_call_main.c flstring.c numericsort.c vsnprintf.c
diff --git a/src/fl_images_core.cxx b/src/fl_images_core.cxx
index 6982b1066..5af696764 100644
--- a/src/fl_images_core.cxx
+++ b/src/fl_images_core.cxx
@@ -31,6 +31,7 @@
#include <FL/Fl_JPEG_Image.H>
#include <FL/Fl_PNG_Image.H>
#include <FL/Fl_PNM_Image.H>
+#include <FL/Fl_SVG_Image.H>
#include <stdio.h>
#include <stdlib.h>
#include "flstring.h"
@@ -63,7 +64,7 @@ void fl_register_images() {
Fl_Image * // O - Image, if found
fl_check_images(const char *name, // I - Filename
uchar *header, // I - Header data from file
- int) { // I - Amount of data (not used)
+ int headerlen) { // I - Amount of data
if (memcmp(header, "GIF87a", 6) == 0 ||
memcmp(header, "GIF89a", 6) == 0) // GIF file
return new Fl_GIF_Image(name);
@@ -88,6 +89,12 @@ fl_check_images(const char *name, // I - Filename
return new Fl_JPEG_Image(name);
#endif // HAVE_LIBJPEG
+#ifdef FLTK_USE_NANOSVG
+ if ( (headerlen > 5 && memcmp(header, "<?xml", 5) == 0) ||
+ memcmp(header, "<svg", 4) == 0)
+ return new Fl_SVG_Image(name);
+#endif // FLTK_USE_NANOSVG
+
return 0;
}