summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2022-11-28 17:26:37 +0100
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2022-12-09 10:43:20 +0100
commit36cd0a397c6d8fee7ffc5b59d607ead523226e53 (patch)
tree91f0bd3628ae3d7b7553706b24b66b1bb4620c6b /src
parent0bb30d8f92839af826fb389fccd625c74e981a13 (diff)
New Fl_ICO_Image class to read Windows .ico icon files
Many thanks to @darealshinji for contributing all the code for this new FLTK image class (see branch Fl_ICO_Image of https://github.com/darealshinji/fltk).
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/Fl_BMP_Image.cxx48
-rw-r--r--src/Fl_ICO_Image.cxx202
-rw-r--r--src/Fl_PNG_Image.cxx20
-rw-r--r--src/Makefile1
-rw-r--r--src/fl_images_core.cxx6
6 files changed, 254 insertions, 24 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fb71a49b3..49825d6be 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -465,6 +465,7 @@ set (IMGCPPFILES
Fl_File_Icon2.cxx
Fl_GIF_Image.cxx
Fl_Help_Dialog.cxx
+ Fl_ICO_Image.cxx
Fl_JPEG_Image.cxx
Fl_PNG_Image.cxx
Fl_PNM_Image.cxx
diff --git a/src/Fl_BMP_Image.cxx b/src/Fl_BMP_Image.cxx
index de444f99b..7610652cb 100644
--- a/src/Fl_BMP_Image.cxx
+++ b/src/Fl_BMP_Image.cxx
@@ -1,7 +1,7 @@
//
// Fl_BMP_Image class for the Fast Light Tool Kit (FLTK).
//
-// Copyright 2011-2021 by Bill Spitzak and others.
+// Copyright 2011-2022 by Bill Spitzak and others.
// Copyright 1997-2010 by Easy Software Products.
// Image support by Matthias Melcher, Copyright 2000-2009.
//
@@ -129,7 +129,7 @@ Fl_BMP_Image::Fl_BMP_Image(const char *imagename, const unsigned char *data, con
format supports only 1 bit for alpha. To avoid code duplication, we use
an Fl_Image_Reader that reads data from either a file or from memory.
*/
-void Fl_BMP_Image::load_bmp_(Fl_Image_Reader &rdr)
+void Fl_BMP_Image::load_bmp_(Fl_Image_Reader &rdr, int ico_height, int ico_width)
{
int info_size, // Size of info header
width, // Width of image (pixels)
@@ -147,7 +147,7 @@ void Fl_BMP_Image::load_bmp_(Fl_Image_Reader &rdr)
row_order, // 1 = normal; -1 = flipped row order
start_y, // Beginning Y
end_y; // Ending Y
- long offbits; // Offset to image data
+ long offbits = 0; // Offset to image data
uchar bit, // Bit in image
byte; // Byte in image
uchar *ptr; // Pointer into pixels
@@ -163,17 +163,19 @@ void Fl_BMP_Image::load_bmp_(Fl_Image_Reader &rdr)
w(0); h(0); d(0); ld(0); // make sure these are all zero
// Get the header...
- byte = rdr.read_byte(); // Check "BM" sync chars
- bit = rdr.read_byte();
- if (byte != 'B' || bit != 'M') {
- ld(ERR_FORMAT);
- return;
- }
+ if (ico_height < 1) {
+ byte = rdr.read_byte(); // Check "BM" sync chars
+ bit = rdr.read_byte();
+ if (byte != 'B' || bit != 'M') {
+ ld(ERR_FORMAT);
+ return;
+ }
- rdr.read_dword(); // Skip size
- rdr.read_word(); // Skip reserved stuff
- rdr.read_word();
- offbits = (long)rdr.read_dword();// Read offset to image data
+ rdr.read_dword(); // Skip size
+ rdr.read_word(); // Skip reserved stuff
+ rdr.read_word();
+ offbits = (long)rdr.read_dword();// Read offset to image data
+ }
// Then the bitmap information...
info_size = rdr.read_dword();
@@ -196,12 +198,20 @@ void Fl_BMP_Image::load_bmp_(Fl_Image_Reader &rdr)
repcount = info_size - 12;
} else {
- // New BMP header...
- width = rdr.read_long();
- // If the height is negative, the row order is flipped
- temp = rdr.read_long();
- if (temp < 0) row_order = 1;
- height = abs(temp);
+ if (ico_height > 0 && ico_width > 0) {
+ rdr.read_long();
+ rdr.read_long();
+ width = ico_width;
+ height = ico_height;
+ } else {
+ // New BMP header...
+ w(rdr.read_long());
+ // If the height is negative, the row order is flipped
+ temp = rdr.read_long();
+ if (temp < 0) row_order = 1;
+ height = abs(temp);
+ }
+
rdr.read_word();
depth = rdr.read_word();
compression = rdr.read_dword();
diff --git a/src/Fl_ICO_Image.cxx b/src/Fl_ICO_Image.cxx
new file mode 100644
index 000000000..9de71737b
--- /dev/null
+++ b/src/Fl_ICO_Image.cxx
@@ -0,0 +1,202 @@
+//
+// Fl_ICO_Image class for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2022 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:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// https://www.fltk.org/str.php
+//
+
+
+//
+// Include necessary header files...
+//
+
+#include <FL/Fl.H>
+#include "config.h"
+#include "Fl_Image_Reader.h"
+#include <FL/Fl_ICO_Image.H>
+#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
+# include <FL/Fl_PNG_Image.H>
+#endif
+
+/**
+ Loads the named icon image from the given .ico filename or from memory
+ \param filename Name of a .ico file, or of the in-memory image
+ \param id When id is -1 (default), the highest-resolution icon is loaded;
+ when id ≥ 0, load the icon with this ID;
+ when id = -2, load all IconDirEntry structures but no image.
+ \param data NULL, or in-memory icon data
+ \param datasize Size in bytes of the \p data byte array (used when \p data is not NULL)
+*/
+Fl_ICO_Image::Fl_ICO_Image(const char *filename, int id, const unsigned char *data, const size_t datasize)
+: Fl_BMP_Image(0,0),
+ idcount_(0),
+ icondirentry_(0)
+{
+ Fl_Image_Reader rdr;
+ int r;
+
+ w(0); h(0); d(0); ld(0);
+ alloc_array = 0;
+ array = 0;
+
+ if (data) {
+ r = rdr.open(filename, data, datasize);
+ } else {
+ r = rdr.open(filename);
+ }
+
+ if (r == -1) {
+ ld(ERR_FILE_ACCESS);
+ } else {
+ load_ico_(rdr, id);
+ }
+}
+
+/** Destructor */
+Fl_ICO_Image::~Fl_ICO_Image() {
+ delete[] icondirentry_;
+}
+
+
+/*
+ This method attempts to load the biggest image resource available
+ inside a .ICO file (Windows Icon format).
+ */
+void Fl_ICO_Image::load_ico_(Fl_Image_Reader &rdr, int id)
+{
+ int pickedID = -1;
+
+ // Check file header (ICONDIR, 6 bytes)
+
+ if (rdr.read_word() != 0 || rdr.read_word() != 1) {
+ Fl::error("Fl_ICO_Image: %s is not an ICO file.\n", rdr.name());
+ ld(ERR_FORMAT);
+ return;
+ }
+
+ idcount_ = rdr.read_word();
+
+ if (idcount() == 0) {
+ Fl::error("Fl_ICO_Image: %s - no image resources found\n", rdr.name());
+ ld(ERR_FORMAT);
+ return;
+ }
+
+
+ // read entries (IconDirEntry, 16 bytes each)
+
+ icondirentry_ = new IconDirEntry[idcount()];
+
+ for (int i = 0; i < idcount(); ++i) {
+ icondirentry_[i].bWidth = (int)rdr.read_byte();
+ icondirentry_[i].bHeight = (int)rdr.read_byte();
+ icondirentry_[i].bColorCount = (int)rdr.read_byte();
+ icondirentry_[i].bReserved = (int)rdr.read_byte();
+ icondirentry_[i].wPlanes = (int)rdr.read_word();
+ icondirentry_[i].wBitCount = (int)rdr.read_word();
+ icondirentry_[i].dwBytesInRes = (int)rdr.read_dword();
+ icondirentry_[i].dwImageOffset = (int)rdr.read_dword();
+
+ if (icondirentry_[i].bWidth == 0) icondirentry_[i].bWidth = 256;
+ if (icondirentry_[i].bHeight == 0) icondirentry_[i].bHeight = 256;
+ }
+
+ if (id <= -2) return;
+
+ if (!icondirentry_ || idcount() < 1 || id >= idcount()) {
+ ld(ERR_FORMAT);
+ return;
+ }
+
+ if (id == -1) {
+ // pick icon with highest resolution + highest bitcount
+ int highestRes = 0, bitcount = 0;
+ for (int i = 0; i < idcount(); ++i) {
+ int res = icondirentry_[i].bWidth * icondirentry_[i].bHeight;
+ if (res > highestRes || (res == highestRes && icondirentry_[i].wBitCount > bitcount)) {
+ highestRes = res;
+ bitcount = icondirentry_[i].wBitCount;
+ pickedID = i;
+ }
+ }
+ } else {
+ pickedID = id;
+ }
+
+ if (pickedID < 0 ||
+ icondirentry_[pickedID].bWidth <= 0 ||
+ icondirentry_[pickedID].bHeight <= 0 ||
+ icondirentry_[pickedID].dwImageOffset <= 0||
+ icondirentry_[pickedID].dwBytesInRes <= 0)
+ {
+ ld(ERR_FORMAT);
+ return;
+ }
+
+ rdr.seek(icondirentry_[pickedID].dwImageOffset);
+
+
+ // Check for a PNG image resource
+ uchar b[8];
+ for (int i=0; i<8; ++i) b[i] = rdr.read_byte();
+
+ if (b[0]==0x89 && b[1]=='P' && b[2]=='N' && b[3]=='G' &&
+ b[4]=='\r' && b[5]=='\n' && b[6]==0x1A && b[7]=='\n')
+ {
+#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
+ Fl_PNG_Image *png = new Fl_PNG_Image(rdr.name(), icondirentry_[pickedID].dwImageOffset);
+
+ int loaded = png ? png->fail() : ERR_FILE_ACCESS;
+ if (loaded < 0) {
+ w(0); h(0); d(0);
+ ld(loaded);
+ if (png) delete png;
+ return;
+ }
+
+ w(png->w());
+ h(png->h());
+ d(png->d());
+
+ // take over pointer of Fl_PNG_Image's array
+ array = png->array;
+ alloc_array = 1;
+ png->array = NULL;
+ png->alloc_array = 0;
+
+ delete png;
+ return;
+#else
+ Fl::error("Fl_ICO_Image: %s - cannot decode PNG resource (no libpng support)!\n", rdr.name());
+ w(0); h(0); d(0);
+ ld(ERR_FORMAT);
+ return;
+#endif
+ }
+
+
+ // Bitmap resource
+
+ w(icondirentry_[pickedID].bWidth);
+ h(icondirentry_[pickedID].bHeight);
+ d(4);
+
+ if (((size_t)w()) * h() * d() > max_size()) {
+ Fl::warning("ICO file \"%s\" is too large!\n", rdr.name());
+ w(0); h(0); d(0);
+ ld(ERR_FORMAT);
+ return;
+ }
+
+ rdr.seek(icondirentry_[pickedID].dwImageOffset);
+ load_bmp_(rdr, h(), w());
+}
diff --git a/src/Fl_PNG_Image.cxx b/src/Fl_PNG_Image.cxx
index e4584b188..6dbc75b15 100644
--- a/src/Fl_PNG_Image.cxx
+++ b/src/Fl_PNG_Image.cxx
@@ -4,7 +4,7 @@
// Copyright 1997-2012 by Easy Software Products.
// Image support by Matthias Melcher, Copyright 2000-2009.
//
-// Copyright 2013-2021 by Bill Spitzak and others.
+// Copyright 2013-2022 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
@@ -87,9 +87,15 @@ extern "C" {
*/
Fl_PNG_Image::Fl_PNG_Image (const char *filename): Fl_RGB_Image(0,0,0)
{
- load_png_(filename, NULL, 0);
+ load_png_(filename, 0, NULL, 0);
}
+// private c'tor used by Fl_ICO_Image
+// \param offset Offset to seek for the begin of PNG data inside a .ICO file
+Fl_PNG_Image::Fl_PNG_Image (const char *filename, int offset): Fl_RGB_Image(0,0,0)
+{
+ load_png_(filename, offset, NULL, 0);
+}
/**
\brief Constructor that reads a PNG image from memory.
@@ -106,11 +112,11 @@ Fl_PNG_Image::Fl_PNG_Image (const char *filename): Fl_RGB_Image(0,0,0)
Fl_PNG_Image::Fl_PNG_Image (
const char *name_png, const unsigned char *buffer, int maxsize): Fl_RGB_Image(0,0,0)
{
- load_png_(name_png, buffer, maxsize);
+ load_png_(name_png, 0, buffer, maxsize);
}
-void Fl_PNG_Image::load_png_(const char *name_png, const unsigned char *buffer_png, int maxsize)
+void Fl_PNG_Image::load_png_(const char *name_png, int offset, const unsigned char *buffer_png, int maxsize)
{
#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
int i; // Looping var
@@ -134,6 +140,12 @@ void Fl_PNG_Image::load_png_(const char *name_png, const unsigned char *buffer_p
delete fp;
return;
}
+ if (offset > 0 && fseek(*fp, (long)offset, SEEK_SET) == -1) {
+ fclose(*fp);
+ ld(ERR_FORMAT);
+ delete fp;
+ return;
+ }
}
const char *display_name = (name_png ? name_png : "In-memory PNG data");
diff --git a/src/Makefile b/src/Makefile
index a55173867..d8640f2b5 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -228,6 +228,7 @@ IMGCPPFILES = \
Fl_File_Icon2.cxx \
Fl_GIF_Image.cxx \
Fl_Help_Dialog.cxx \
+ Fl_ICO_Image.cxx \
Fl_JPEG_Image.cxx \
Fl_PNG_Image.cxx \
Fl_PNM_Image.cxx \
diff --git a/src/fl_images_core.cxx b/src/fl_images_core.cxx
index 07224fa31..5c2a7e98b 100644
--- a/src/fl_images_core.cxx
+++ b/src/fl_images_core.cxx
@@ -2,7 +2,7 @@
// FLTK images library core.
//
// Copyright 1997-2010 by Easy Software Products.
-// Copyright 2011-2021 by Bill Spitzak and others.
+// Copyright 2011-2022 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
@@ -31,6 +31,7 @@
#include <FL/Fl_PNG_Image.H>
#include <FL/Fl_PNM_Image.H>
#include <FL/Fl_SVG_Image.H>
+#include <FL/Fl_ICO_Image.H>
#include <FL/fl_utf8.h>
#include <stdio.h>
#include <stdlib.h>
@@ -95,6 +96,9 @@ fl_check_images(const char *name, // I - Filename
if (memcmp(header, "BM", 2) == 0) // BMP file
return new Fl_BMP_Image(name);
+ if (memcmp(header, "\0\0\1\0", 4) == 0 && header[5] == 0) // ICO file
+ return new Fl_ICO_Image(name);
+
// PNM
if (header[0] == 'P' && header[1] >= '1' && header[1] <= '7')