diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/Fl_SVG_Image.cxx | 206 | ||||
| -rw-r--r-- | src/Makefile | 3 | ||||
| -rw-r--r-- | src/fl_images_core.cxx | 9 |
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; } |
