FLUID: how can I have SVG icons embedded in the code?

38 views
Skip to first unread message

Gonzalo Garramulo

unread,
Apr 17, 2024, 9:57:48 AMApr 17
to fltkg...@googlegroups.com
I've loaded some SVG icons into my .fl file.  However, when the .fl file
is converted, the .svg icons are turned into RGB images. Is there a way
to keep them as SVG so that they will scale properly?

--
Gonzalo Garramuño
ggar...@gmail.com

Ian MacArthur

unread,
Apr 17, 2024, 11:27:10 AMApr 17
to fltk.general
On Wednesday 17 April 2024 at 14:57:48 UTC+1 Gonzalo wrote:
I've loaded some SVG icons into my .fl file.  However, when the .fl file
is converted, the .svg icons are turned into RGB images. Is there a way
to keep them as SVG so that they will scale properly?

which might work?

I guess the crux is to store the ASCII text in fluid rather than the image (I think fluid converts the svg into an image...)
Maybe in fluid you can use the "binary data" option to store the raw svg text as a char array, and then interpret that data as ASCII in your code?
Might work - though I have not tried it as such...


 

Matthias Melcher

unread,
Apr 17, 2024, 12:50:49 PMApr 17
to fltk.general
This works with the current master branch since a few months or so.

If you open the Widget Properties dialog, you have two lines, one for Image and one for Inactive Image. Just add your .svg here. Current FLUID will store your image "compressed", so basically in its original format. If you click on the [...] button to the right of Browse..., you will get a small dialog box that lets you choose the actual size for the image after scaling, if it's compressed (original format) or not (RGBA), and if it is bound to the widget (basically if deleting the widget will also delete the image data).

Screenshot 2024-04-17 at 18.50.03.jpg

Matthias Melcher

unread,
Apr 17, 2024, 12:57:56 PMApr 17
to fltk.general

Tha Data Node type also improved quite a bit. You can choose if you want your data to be stored as text, binary, or zlib compressed. If you like, you can use Fl_PNG_Image("myImage", binaryData, binaryDataSze); to read an image that way instead of using the "Image" fields.

Gonzalo Garramulo

unread,
Apr 17, 2024, 4:40:40 PMApr 17
to fltkg...@googlegroups.com


El 17/4/24 a las 13:57, 'Matthias Melcher' via fltk.general escribió:

Tha Data Node type also improved quite a bit. You can choose if you want your data to be stored as text, binary, or zlib compressed. If you like, you can use Fl_PNG_Image("myImage", binaryData, binaryDataSze); to read an image that way instead of using the "Image" fields.

Yes.  I get the options and I added the image, but the output is an Fl_RGB_Image() not an Fl_SVG_Image() without having touched any of the options.  I am using a pretty recent branch on Linux:

265e5cd77b30581e7701927930d8fa887e0361df

As options, I get:

Scale     - Width/Height  set to 0,0
Storage   - compressed: ticked
          - bind to widget: off


No inactive image options.

BTW... have you thought of adding a version switch to fluid?  So it becomes easier to know if I am using the same version as yours?

-- 
Gonzalo Garramuño
ggar...@gmail.com

Ian MacArthur

unread,
Apr 18, 2024, 4:09:49 AMApr 18
to fltk.general
So, looking at the fluid from fltk-1.4 ( from a very recent git pull...) I see that what used to be the "Binary Data" blob is now called "Inline Data" and supports not just a binary chunk (as I expected form the 1.3 fluid) but optionally a text chunk or a compressed chunk.
Which seems like a useful thing - it means, for example, that I can easily store an SVG file as a text inclusion, from fluid, and it just works.
Which is jolly handy...

As an aside, can the newer FL SVG class mechanism handle scaling and such if a widget resizes? 
My current SVG code was written with FL-1.3 and uses nanosvg "directly" but I have to derive widgets with a resize() method to catch the widget size changing; and then re-rasterize on size changes.
But if the fl-1.4 code can do that for me "by magic" that would be useful.

Oh! Maybe that's Gonzalo's question then? Maybe it doesn't "automatically" do the resize and he expects that it would?
That being so, I guess you'd need to do it the "old way" that I do, i.e. have a resize() method to catch the widget changing size and re-rasterize.

Is that what it is?

Ian MacArthur

unread,
Apr 18, 2024, 4:24:04 AMApr 18
to fltk.general
So, answering my own question, I just threw something together in fluid-1.4 and it happily displays my "compiled in" SVG file and was really easy.

BUT: It doesn't rescale when I resize the widget. So I guess I do still need a resize() method to handle that still?

Ian MacArthur

unread,
Apr 18, 2024, 7:52:14 AMApr 18
to fltk.general
BUT: It doesn't rescale when I resize the widget. So I guess I do still need a resize() method to handle that still?



OK, tried this over lunch - here's an example as a fluid file, seems to work for me at any rate... You'll need to provide a SVG image called "test_img.svg" but other than that should just work.

fluid -c test1.fl
fltk-config --use-images --compile test1.cxx

====================== test1.fl ===

# data file for the Fltk User Interface Designer (fluid)
version 1.0400
header_name {.h}
code_name {.cxx}
decl {\#include <FL/Fl_SVG_Image.H>} {public global
}

decl {\#include <FL/Fl_Box.H>} {public global
}

data svg3 {private local filename {../img/test_img.svg} textmode
}

class svg_rsz {open : {public Fl_Box}
} {
  Function {svg_rsz(Fl_SVG_Image *svg2, int X, int Y, int W, int H, const char* L=0) : Fl_Box(X,Y,W,H,L)} {
    comment Constructor open
  } {
    code {svg = svg2;
svg->resize(w(),h());
image(svg);} {}
  }
  Function {resize(int x, int y, int w, int h)} {
    comment {A resize method} open return_type void
  } {
    code {Fl_Box::resize(x,y,w,h);
svg->resize(this->w(),this->h());} {}
  }
  decl {Fl_SVG_Image *svg;} {private local
  }
}

Function {} {open
} {
  code {Fl_SVG_Image *svg2 = new Fl_SVG_Image(NULL, svg3);} {}
  code {svg_rsz *boxA = NULL;} {selected
  }
  Fl_Window main_win {open
    private xywh {882 285 249 221} type Double resizable
    code0 {boxA = new svg_rsz(svg2, 15, 15, 180, 180);} visible
  } {}
}

===== end ====

 

Matthias Melcher

unread,
Apr 18, 2024, 8:13:18 AMApr 18
to fltk.general
ggar...@gmail.com schrieb am Mittwoch, 17. April 2024 um 22:40:40 UTC+2:

Yes.  I get the options and I added the image, but the output is an Fl_RGB_Image() not an Fl_SVG_Image() without having touched any of the options.  I am using a pretty recent branch on Linux:

Scale     - Width/Height  set to 0,0


Storage   - compressed: ticked
          - bind to widget: off

 

If your source image is a sag, then FLUID will store it internally as an svg. If the source is compressed, it will be stored compressed. When the image is drawn for the first time, the SVG is interpreted and the RGB data is cached for fast rendering. If your hardware supports that, the cache will be stored at the original resolution, and the image will be scaled when it is rendered, keeping full quality for HiDPI displays.That way, you can scale the output image. The SVG data is only interpreted once unless you explicitly call `uncache()` on your image.

The code generated by FLUID for a "compressed" (I should rename that to "original format") SVG is something like:

#include <FL/Fl_SVG_Image.H>

static const char idata_checker[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\" ... ";
static Fl_Image *image_checker() {
  static Fl_Image *image = NULL;
  if (!image)
    image = new Fl_SVG_Image("checker.svg", idata_checker);
  return image;
}

BTW... have you thought of adding a version switch to fluid?  So it becomes easier to know if I am using the same version as yours?

It's only really an issue with unreleased code. FLUID releases in 1.3 follow the FLTK release scheme and the About box shows the version. I should try to add the GitHub tag or a running "build" number to prereleases. Open for suggestions.
 

Matthias Melcher

unread,
Apr 18, 2024, 8:14:53 AMApr 18
to fltk.general
Ian MacArthur schrieb am Donnerstag, 18. April 2024 um 13:52:14 UTC+2:
BUT: It doesn't rescale when I resize the widget. So I guess I do still need a resize() method to handle that still?

That is correct. FLTK does not resize any of the label images. Nice sample code. We could open the GitHub Wiki for working code, similar to Greg's cheat sheet.

Gonzalo Garramuño

unread,
Apr 18, 2024, 4:09:51 PMApr 18
to fltkg...@googlegroups.com


On 18/4/24 09:14, 'Matthias Melcher' via fltk.general wrote:

Ian MacArthur schrieb am Donnerstag, 18. April 2024 um 13:52:14 UTC+2:
BUT: It doesn't rescale when I resize the widget. So I guess I do still need a resize() method to handle that still?

I tried it and it works, but on Windows, with a certain .svg I got:

D:\a\mrv2\mrv2\BUILD-Msys-amd64\Release\mrv2\src\mrv2-build\lib\mrvWidgets\mrViewer.cxx(1529): error C2026: string too big, trailing characters truncated

I am attaching the .svg that I think is the issue.

-- 
Gonzalo Garramuño
ggar...@gmail.com
Scrub.svg

Ian MacArthur

unread,
Apr 19, 2024, 4:01:01 AMApr 19
to fltk.general
On Thursday 18 April 2024 at 21:09:51 UTC+1  Gonzalo wrote:
Ian MacArthur schrieb am Donnerstag, 18. April 2024 um 13:52:14 UTC+2:
BUT: It doesn't rescale when I resize the widget. So I guess I do still need a resize() method to handle that still?

I tried it and it works, but on Windows, with a certain .svg I got:

D:\a\mrv2\mrv2\BUILD-Msys-amd64\Release\mrv2\src\mrv2-build\lib\mrvWidgets\mrViewer.cxx(1529): error C2026: string too big, trailing characters truncated

I am attaching the .svg that I think is the issue.

Hmm, just dropped that SVG file into my little fluid test, and it seems to work OK. Is it possibly a different image that is causing the issue?
(I got a grey image showing a white outline, with a drop-shadow, of a stylised hand wiping a cloth over the surface; which seems like a credible image for a "scrub" icon, so I assume that is working OK.)

This was on Win10 with Msys, and gcc version 6.3.0 (MinGW.org GCC-6.3.0-1) - which is pretty ancient these days but still I use it...

What compiler are you using? That error message "C2026" looks a bit "lc"-ish to me, not like a gcc error, so maybe it's a compiler thing?

Hmm, OK, just checked - C2026 is a MS lc thing: 
<quote>
Before adjacent strings get concatenated, a string can't be longer than 16380 single-byte characters.
A Unicode string of about one half this length would also generate this error.
</quote>

The solution apparently is to dice the string up into separate quoted chunks, i.e. instead of doing :-

"this is a \
very long \
string"

We need to do :-

"this is a "
"very long "
"string"


 

GOUY MANOLO

unread,
Apr 19, 2024, 4:03:04 AMApr 19
to fltkg...@googlegroups.com
Yes, a resize method is necessary because images are not tied to their widget’s size. What Fltk does automatically is to change the image size when the display’s scaling factor changes. All of this applies to any kind of image, svg or other.

Manolo 

Le 18 avr. 2024 à 10:24, Ian MacArthur <imaca...@gmail.com> a écrit :


--
You received this message because you are subscribed to the Google Groups "fltk.general" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkgeneral...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fltkgeneral/065b5d10-0ce6-43ea-ab16-a8ed0dc64519n%40googlegroups.com.

Ian MacArthur

unread,
Apr 19, 2024, 4:22:11 AMApr 19
to fltk.general
On Friday 19 April 2024 at 09:01:01 UTC+1 Ian MacArthur wrote:
On Thursday 18 April 2024 at 21:09:51 UTC+1  Gonzalo wrote:
Ian MacArthur schrieb am Donnerstag, 18. April 2024 um 13:52:14 UTC+2:
BUT: It doesn't rescale when I resize the widget. So I guess I do still need a resize() method to handle that still?

I tried it and it works, but on Windows, with a certain .svg I got:

D:\a\mrv2\mrv2\BUILD-Msys-amd64\Release\mrv2\src\mrv2-build\lib\mrvWidgets\mrViewer.cxx(1529): error C2026: string too big, trailing characters truncated

I am attaching the .svg that I think is the issue.

Hmm, just dropped that SVG file into my little fluid test, and it seems to work OK. Is it possibly a different image that is causing the issue?
(I got a grey image showing a white outline, with a drop-shadow, of a stylised hand wiping a cloth over the surface; which seems like a credible image for a "scrub" icon, so I assume that is working OK.)

So, as a possible workaround, I tried storing the SVG file in "compressed" form in fluid, as Matt had suggested. That certainly makes it small enough (down from approx. 20K text to approx. 7K) but I can't then seem to get Fl_SVG_Image to load it, so... One for Matt maybe? As I am out of ideas now:

Here's the adapted fluid file, test2.fl:

=========== test2.fl ============

# data file for the Fltk User Interface Designer (fluid)
version 1.0400
header_name {.h}
code_name {.cxx}
decl {\#include <FL/Fl_SVG_Image.H>} {public global
}

decl {\#include <FL/Fl_Box.H>} {public global
}

data svg3 {private local filename {Scrub.svg} compressed

}

class svg_rsz {open : {public Fl_Box}
} {
  Function {svg_rsz(Fl_SVG_Image *svg2, int X, int Y, int W, int H, const char* L=0) : Fl_Box(X,Y,W,H,L)} {
    comment Constructor open
  } {
    code {svg = svg2;
svg->resize(w(),h());
image(svg);} {}
  }
  Function {resize(int x, int y, int w, int h)} {
    comment {A resize method} open return_type void
  } {
    code {Fl_Box::resize(x,y,w,h);
svg->resize(this->w(),this->h());} {}
  }
  decl {Fl_SVG_Image *svg;} {private local
  }
}

Function {} {open
} {
  code {Fl_SVG_Image *svg2 = new Fl_SVG_Image(NULL, svg3, svg3_size);} {selected

  }
  code {svg_rsz *boxA = NULL;} {}
  Fl_Window main_win {open
    private xywh {882 285 249 221} type Double resizable
    code0 {boxA = new svg_rsz(svg2, 15, 15, 180, 180);} visible
  } {}
}


=======================


Matthias Melcher

unread,
Apr 19, 2024, 5:39:11 AMApr 19
to fltk.general
Ian MacArthur schrieb am Freitag, 19. April 2024 um 10:01:01 UTC+2:
<quote>
Before adjacent strings get concatenated, a string can't be longer than 16380 single-byte characters.
A Unicode string of about one half this length would also generate this error.
</quote>

The solution apparently is to dice the string up into separate quoted chunks, i.e. instead of doing :-

"this is a \
very long \
string"

We need to do :-

"this is a "
"very long "
"string"

I'll implement that in FLUID today. If that fixes the VC issues, that'd be great. 

Matthias Melcher

unread,
Apr 19, 2024, 6:06:25 AMApr 19
to fltk.general
Ian MacArthur schrieb am Freitag, 19. April 2024 um 10:22:11 UTC+2:
So, as a possible workaround, I tried storing the SVG file in "compressed" form in fluid, as Matt had suggested. That certainly makes it small enough (down from approx. 20K text to approx. 7K) but I can't then seem to get Fl_SVG_Image to load it, so... One for Matt maybe? As I am out of ideas now:

There are two approaches to store images that are quite different. 

--- Using the Image: field in the Widget Properties

If you use the "Image:" field in the Widget Properties panel, you can tick "compressed" (which is named wrong, I will change that today as well), which will inline the image in ints original format. If you choose an .svg file, you get the verbatim XML data, and if you choose an .svgz, FLUID will store the binary data. The compression is done by the svg writer, and it's decompressed by FLTK's svg reader. FLUID does not change the data.

If "compressed" is not ticked, FLUID will convert the image (including SVG) to RGB first and store the pixels. The advantage is, that you don't need to link your app with the svg library or any other image library. The disadvantage is having a block of uncompressed pixels in your app.

--- Using the Inline Data node:

If you use the Inline Data node, you can choose binary, text, or compressed. Inline Data does not know what kind of data you store, so you have to choose the right type, and FLUID does not know how you will use the data later. You are using it for and svg, but FLUID does not know that. If your svg is uncompressed XML, you should choose text. If it is a compressed svgz, you should choose binary. If you select "compress", the FLUID will compress the data for you using zlib, but that is completely unrelated to the type of data. You have to uncompress it before you can use it:

For example you have an Inline Data node that you want to store in the program code compressed, named AppLicense. FLUID will generate three const values for you:
unsigned char AppLicense[], an array holding the compressed data, the implicit sizeof(AppLicense), holding the size of the compressed array, and int AppLicense_size, the size of the original uncompressed array. To use the data that FLUID stores compressed, you can sod something like:

    int uncompressed_size = AppLicense_size;

    unsigned char *AppLicenseUncompressed = (unsigned char *)::malloc(uncompressed_size);

    if (uncompress(AppLicenseUncompressed, &uncompressed_size, AppLicense, sizeof(AppLicense)) != Z_OK) { 

      /* error */ 

    }


FLUID Inline Data compression is not related in any way to image compression.
 

imm

unread,
Apr 19, 2024, 6:17:43 AMApr 19
to fltkg...@googlegroups.com
On Fri, 19 Apr 2024 at 11:06, 'Matthias Melcher' wrote:
>
> --- Using the Inline Data node:
>
> If you use the Inline Data node, you can choose binary, text, or compressed. Inline Data does not know what kind of data you store, so you have to choose the right type, and FLUID does not know how you will use the data later. You are using it for and svg, but FLUID does not know that. If your svg is uncompressed XML, you should choose text. If it is a compressed svgz, you should choose binary. If you select "compress", the FLUID will compress the data for you using zlib, but that is completely unrelated to the type of data. You have to uncompress it before you can use it:
>
> For example you have an Inline Data node that you want to store in the program code compressed, named AppLicense. FLUID will generate three const values for you:
> unsigned char AppLicense[], an array holding the compressed data, the implicit sizeof(AppLicense), holding the size of the compressed array, and int AppLicense_size, the size of the original uncompressed array. To use the data that FLUID stores compressed, you can sod something like:
>
> int uncompressed_size = AppLicense_size;
>
> unsigned char *AppLicenseUncompressed = (unsigned char *)::malloc(uncompressed_size);
>
> if (uncompress(AppLicenseUncompressed, &uncompressed_size, AppLicense, sizeof(AppLicense)) != Z_OK) {
>
> /* error */
>
> }
>

OK, so for the Inline Data node I have to uncompress the node myself... OK.
I had though that the :

Fl_SVG_Image::Fl_SVG_Image(const char * name, const unsigned char *
svg_data, size_t length)

method would do that for me, so that is what I used in my fluid file.

The docs say: "This constructor loads the SVG image from a block of
memory. This version is commonly used for compressed binary data, but
the reader recognizes if the data is uncompressed, and reads it as a
text block." so I was hopeful this would Just Work, but in testing it
does not. I'll try unpacking the data manually...

Though probably the raw text is fine for me anyway, TBH...

Matthias Melcher

unread,
Apr 19, 2024, 6:30:36 AMApr 19
to fltk.general
If you store a compressed SVG (svgz) as binary data in an Inline Data node, Fl_SVG_Image will uncompress it.

If you store an uncompressed  SVG (svg, no z) as Inline Data, and you ask FLUID to compress it, you need to manually uncompress it first and Fl_SVG_Image will then read the uncompressed data.

FLUID compression != SVG compression

The documentation means that Fl_SVG_Image::Fl_SVG_Image(const char *, const char*) read SVG data, and Fl_SVG_Image::Fl_SVG_Image(const char *, const unsigned char*, size_t) reads SVGZ data. But the SVGZ reader is smart enough to recognize SVG data and reads that too.

imm

unread,
Apr 19, 2024, 6:35:19 AMApr 19
to fltkg...@googlegroups.com
OK... got it!
> --
> You received this message because you are subscribed to the Google Groups "fltk.general" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to fltkgeneral...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/fltkgeneral/c502412b-804d-4bd5-b336-afff203fa9e7n%40googlegroups.com.

imm

unread,
Apr 19, 2024, 7:02:39 AMApr 19
to fltkg...@googlegroups.com
OK, this version works for the compressed data node approach.
Checking for errors and freeing the malloc'd buffer is left as an
exercise for the reader...

=========== test3.fl ==============
# data file for the Fltk User Interface Designer (fluid)
version 1.0400
header_name {.h}
code_name {.cxx}
decl {\#include <FL/Fl_SVG_Image.H>} {public global
}

decl {\#include <FL/Fl_Box.H>} {public global
}

decl {\#include <stdlib.h>} {private local
}

decl {\#include <zlib.h>} {private local
}

data svg3 {private local filename {Scrub.svg} compressed
}

class svg_rsz {open : {public Fl_Box}
} {
Function {svg_rsz(Fl_SVG_Image *svg2, int X, int Y, int W, int H,
const char* L=0) : Fl_Box(X,Y,W,H,L)} {
comment Constructor open
} {
code {svg = svg2;
svg->resize(w(),h());
image(svg);} {}
}
Function {resize(int x, int y, int w, int h)} {
comment {A resize method} open return_type void
} {
code {Fl_Box::resize(x,y,w,h);
svg->resize(this->w(),this->h());} {}
}
decl {Fl_SVG_Image *svg;} {private local
}
}

Function {} {open
} {
code {unsigned char *svg3U = (unsigned char *)::malloc(svg3_size);
fltk_z_uLongf u_sz = (fltk_z_uLongf)svg3_size;
if (uncompress(svg3U, &u_sz, svg3, sizeof(svg3)) != Z_OK)
{
/* error */
}} {}
code {Fl_SVG_Image *svg2 = new Fl_SVG_Image(NULL, (char *)svg3U);} {selected
}
code {svg_rsz *boxA = NULL;} {}
Fl_Window main_win {open
private xywh {882 285 249 221} type Double resizable
code0 {boxA = new svg_rsz(svg2, 15, 15, 180, 180);} visible
} {}
}

===============================

Matthias Melcher

unread,
Apr 19, 2024, 8:35:21 AMApr 19
to fltk.general
I changed the wording in the Image Properties dialog for images that inline to an image directly. I have not yet updated the Inline Data section, but I will try to find some good wording, probably quote some text from this discourse.

Gonzalo Garramuño

unread,
Apr 19, 2024, 1:58:50 PMApr 19
to fltkg...@googlegroups.com

On 19/4/24 05:01, Ian MacArthur wrote:
>
> What compiler are you using? That error message "C2026" looks a bit
> "lc"-ish to me, not like a gcc error, so maybe it's a compiler thing?
I am using MSVC 2022 Community Edition.  It may indeed be another image,
but I think that's the most complex SVG image I have.

--
Gonzalo Garramuño
ggar...@gmail.com

Matthias Melcher

unread,
Apr 19, 2024, 5:23:43 PMApr 19
to fltk.general

Oh, yeah, not sure if I mentioned that. The FLUID output for strings in git master now uses the string-by-string notation now, and no longer the backslash at the ned of a line. I also fixed escaped character output and verified it with some binary data.

I remember this issue from older VisualC compilers. I am surprised that 2022 still has this limit. Anyway, the workaround is fine.
Reply all
Reply to author
Forward
0 new messages