From b1fe1ca41264fd5a3efca6e4aabc47dc87b27b23 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 24 Mar 2017 05:30:47 +0800 Subject: [PATCH] fix bug where window can't load icon with ico(#192) --- .../paint/detail/image_impl_interface.hpp | 2 +- source/gui/detail/native_window_interface.cpp | 1 - source/paint/detail/image_ico.hpp | 319 ++++++++++++++++-- source/paint/detail/image_ico_ex.hpp | 262 -------------- source/paint/detail/image_ico_resource.hpp | 123 +++++++ source/paint/image.cpp | 172 ++-------- 6 files changed, 434 insertions(+), 445 deletions(-) delete mode 100644 source/paint/detail/image_ico_ex.hpp create mode 100644 source/paint/detail/image_ico_resource.hpp diff --git a/include/nana/paint/detail/image_impl_interface.hpp b/include/nana/paint/detail/image_impl_interface.hpp index 3e75d18e..4a99abaf 100644 --- a/include/nana/paint/detail/image_impl_interface.hpp +++ b/include/nana/paint/detail/image_impl_interface.hpp @@ -14,7 +14,7 @@ namespace nana{ namespace paint{ { image_impl_interface& operator=(const image_impl_interface& rhs); public: - typedef nana::paint::graphics& graph_reference; + using graph_reference = nana::paint::graphics&; virtual ~image_impl_interface() = 0; //The destructor is defined in ../image.cpp virtual bool open(const std::experimental::filesystem::path& file) = 0; virtual bool open(const void* data, std::size_t bytes) = 0; // reads image from memory diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index bdf75823..2e1d8761 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -23,7 +23,6 @@ #include #endif #include - #include "../../paint/detail/image_ico.hpp" #elif defined(NANA_X11) #include #endif diff --git a/source/paint/detail/image_ico.hpp b/source/paint/detail/image_ico.hpp index 44b49191..3a437b34 100644 --- a/source/paint/detail/image_ico.hpp +++ b/source/paint/detail/image_ico.hpp @@ -1,44 +1,299 @@ #ifndef NANA_PAINT_DETAIL_IMAGE_ICO_HPP #define NANA_PAINT_DETAIL_IMAGE_ICO_HPP -#include -#include +#include "image_pixbuf.hpp" +#include -namespace nana{ namespace paint -{ - namespace detail - { - class image_ico - :public image::image_impl_interface - { #if defined(NANA_WINDOWS) - struct handle_deleter - { - void operator()(HICON* handle) const; - };//end struct handle_deleter - typedef std::shared_ptr ptr_t; -#else - typedef std::shared_ptr ptr_t; +# include #endif - public: - image_ico(bool is_ico); + +namespace nana { +namespace paint { +namespace detail { +// These next two structs represent how the icon information is stored +// in an ICO file. +typedef struct +{ + uint8_t bWidth; // Width of the image + uint8_t bHeight; // Height of the image (times 2) + uint8_t bColorCount; // Number of colors in image (0 if >=8bpp) + uint8_t bReserved; // Reserved + uint16_t wPlanes; // Color Planes + uint16_t wBitCount; // Bits per pixel + uint32_t dwBytesInRes; // how many bytes in this resource? + uint32_t dwImageOffset; // where in the file is this image +} ICONDIRENTRY, *LPICONDIRENTRY; + +typedef struct +{ + uint16_t idReserved; // Reserved + uint16_t idType; // resource type (1 for icons) + uint16_t idCount; // how many images? + //ICONDIRENTRY idEntries[1]; // the entries for each image +} ICONDIR, *LPICONDIR; + +// size - 40 bytes +typedef struct +{ + uint32_t biSize; + uint32_t biWidth; + uint32_t biHeight; // Icon Height (added height of XOR-Bitmap and AND-Bitmap) + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + int32_t biSizeImage; + uint32_t biXPelsPerMeter; + uint32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; +} s_BITMAPINFOHEADER, *s_PBITMAPINFOHEADER; + +// 46 bytes +typedef struct +{ + s_BITMAPINFOHEADER icHeader; // DIB header + uint32_t icColors[1]; // Color table (short 4 bytes) //RGBQUAD + uint8_t icXOR[1]; // DIB bits for XOR mask + uint8_t icAND[1]; // DIB bits for AND mask +} ICONIMAGE, *LPICONIMAGE; - bool open(const std::experimental::filesystem::path& filename) override; - bool open(const void* data, std::size_t bytes) override; - bool alpha_channel() const override; - bool empty() const override; - void close() override; - nana::size size() const override; - virtual void paste(const nana::rectangle& src_r, graph_reference graph, const point& p_dst) const override; - virtual void stretch(const nana::rectangle&, graph_reference graph, const nana::rectangle& r) const override; - const ptr_t & ptr() const; - private: - const bool is_ico_; - nana::size size_; - ptr_t ptr_; - };//end class image_ico +class image_ico + : public basic_image_pixbuf +{ + bool _m_read_ico(const void* data, std::size_t /*size*/) + { + auto width = 0; + auto height = 0; + auto buffer = (unsigned char *)data; + auto icoDir = reinterpret_cast(buffer); + int iconsCount = icoDir->idCount; + if (icoDir->idReserved != 0 || icoDir->idType != 1 || iconsCount == 0 || iconsCount > 20) + return false; + + auto cursor = buffer; + cursor += 6; + auto dirEntry = reinterpret_cast(cursor); + auto maxSize = 0; + auto offset = 0; + auto maxBitCount = 0; + for (auto i = 0; i < iconsCount; i++, ++dirEntry) + { + int w = dirEntry->bWidth; + int h = dirEntry->bHeight; + int bitCount = dirEntry->wBitCount; + if (w * h > maxSize || bitCount > maxBitCount) // we choose icon with max resolution + { + width = w; + height = h; + offset = dirEntry->dwImageOffset; + maxSize = w * h; + maxBitCount = bitCount; + } + } + + if (offset == 0) return false; + + cursor = buffer; + cursor += offset; + auto icon = reinterpret_cast(cursor); + auto realBitsCount = static_cast(icon->icHeader.biBitCount); + auto hasAndMask = (realBitsCount < 32) && (height != static_cast(icon->icHeader.biHeight)); + cursor += 40; + pixbuf_.open(width, height); + + // rgba + vertical swap + if (realBitsCount >= 32) + { + for (auto x = 0; x < width; ++x) + for (auto y = 0; y < height; ++y) + { + pixbuf_.alpha_channel(true); + auto shift2 = 4 * (x + (height - y - 1) * width); + pixel_color_t image; + image.element.red = cursor[shift2 + 2]; + image.element.green = cursor[shift2 + 1]; + image.element.blue = cursor[shift2]; + image.element.alpha_channel = cursor[shift2 + 3]; + pixbuf_.pixel(x, y, image); + } + } + + else if (realBitsCount == 24) + { + for (auto x = 0; x < width; x++) + for (auto y = 0; y < height; y++) + { + pixbuf_.alpha_channel(true); + auto shift2 = 3 * (x + (height - y - 1) * width); + pixel_color_t image; + image.element.red = cursor[shift2 + 2]; + image.element.green = cursor[shift2 + 1]; + image.element.blue = cursor[shift2]; + image.element.alpha_channel = 255; + pixbuf_.pixel(x, y, image); + } + } + + else if (realBitsCount == 8) /// 256 colors + { + // 256 color table + auto colors = reinterpret_cast(cursor); + cursor += 256 * 4; + for (auto x = 0; x < width; x++) + for (auto y = 0; y < height; y++) + { + pixbuf_.alpha_channel(true); + + auto shift2 = (x + (height - y - 1) * width); + auto index = 4 * cursor[shift2]; + pixel_color_t image; + image.element.red = colors[index + 2]; + image.element.green = colors[index + 1]; + image.element.blue = colors[index]; + image.element.alpha_channel = 255; + pixbuf_.pixel(x, y, image); + } + } + + else if (realBitsCount == 4) /// 16 colors + { + // 16 color table + auto colors = reinterpret_cast(cursor); + cursor += 16 * 4; + for (auto x = 0; x < width; x++) + for (auto y = 0; y < height; y++) + { + auto shift2 = (x + (height - y - 1) * width); + auto index = cursor[shift2 / 2]; + if (shift2 % 2 == 0) + index = (index >> 4) & 0xF; + else + index = index & 0xF; + index *= 4; + pixbuf_.alpha_channel(true); + pixel_color_t image; + image.element.red = colors[index + 2]; + image.element.green = colors[index + 1]; + image.element.blue = colors[index]; + image.element.alpha_channel = 255; + pixbuf_.pixel(x, y, image); + } + } + + else if (realBitsCount == 1) /// 2 colors + { + // 2 color table + auto colors = reinterpret_cast(cursor); + cursor += 2 * 4; + auto boundary = width; //!!! 32 bit boundary (http://www.daubnet.com/en/file-format-ico) + while (boundary % 32 != 0) boundary++; + for (auto x = 0; x < width; x++) + for (auto y = 0; y < height; y++) + { + auto shift2 = (x + (height - y - 1) * boundary); + auto index = cursor[shift2 / 8]; + + // select 1 bit only + unsigned char bit = 7 - (x % 8); + index = (index >> bit) & 0x01; + index *= 4; + pixbuf_.alpha_channel(true); + pixel_color_t image; + image.element.red = colors[index + 2]; + image.element.green = colors[index + 1]; + image.element.blue = colors[index]; + image.element.alpha_channel = 255; + pixbuf_.pixel(x, y, image); + } + } + + // Read AND mask after base color data - 1 BIT MASK + if (hasAndMask) + { + auto boundary = width * realBitsCount; //!!! 32 bit boundary (http://www.daubnet.com/en/file-format-ico) + while (boundary % 32 != 0) boundary++; + cursor += boundary * height / 8; + boundary = width; + while (boundary % 32 != 0) boundary++; + for (auto y = 0; y < height; y++) + for (auto x = 0; x < width; x++) + { + unsigned char bit = 7 - (x % 8); + auto shift2 = (x + (height - y - 1) * boundary) / 8; + auto mask = (0x01 & (static_cast(cursor[shift2]) >> bit)); + auto pc = pixbuf_.pixel(x, y); + auto alpha = pc.element.alpha_channel; + alpha *= 1 - mask; + pc.element.alpha_channel = alpha; + pixbuf_.pixel(x, y, pc); + } + } + return true; } +public: + ~image_ico() + { +#if defined(NANA_WINDOWS) + if (native_handle_) + ::DestroyIcon(reinterpret_cast(native_handle_)); +#endif + } + + bool open(const std::experimental::filesystem::path& ico_file) override + { + std::ifstream file(ico_file.string(), std::ios::binary); + if (!file.is_open()) return false; + + // allocates a buffer for the image + file.seekg(0, std::ios::end); + const auto bytes = static_cast(file.tellg()); + file.seekg(0, std::ios::beg); + auto buffer = new char[bytes]; + + // read data from the file and set them in the buffer + file.read(buffer, bytes); + auto okret = _m_read_ico(buffer, bytes); + + // delete buffer and return + delete[] buffer; + + if (okret) + path_ = ico_file; + + return okret; + } + + bool open(const void* data, std::size_t bytes) override + { + if (_m_read_ico(data, bytes)) + { + native_handle_ = ::CreateIconFromResourceEx(reinterpret_cast(const_cast(data)), static_cast(bytes), TRUE, 0x00030000, 0, 0, LR_DEFAULTCOLOR); + return true; + } + return false; + } + + void* native_handle() + { +#if defined(NANA_WINDOWS) + if (native_handle_) + return native_handle_; + + native_handle_ = ::LoadImage(nullptr, path_.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); + return native_handle_; +#else + return nullptr; +#endif + } +private: + std::experimental::filesystem::path path_; +#if defined(NANA_WINDOWS) + void* native_handle_{nullptr}; +#endif +}; +}//end namespace detail }//end namespace paint }//end namespace nana diff --git a/source/paint/detail/image_ico_ex.hpp b/source/paint/detail/image_ico_ex.hpp deleted file mode 100644 index 9beef0c8..00000000 --- a/source/paint/detail/image_ico_ex.hpp +++ /dev/null @@ -1,262 +0,0 @@ -#ifndef NANA_PAINT_DETAIL_IMAGE_ICO_EX_HPP -#define NANA_PAINT_DETAIL_IMAGE_ICO_EX_HPP - -#include "image_pixbuf.hpp" - -namespace nana { -namespace paint { -namespace detail { -// These next two structs represent how the icon information is stored -// in an ICO file. -typedef struct -{ - uint8_t bWidth; // Width of the image - uint8_t bHeight; // Height of the image (times 2) - uint8_t bColorCount; // Number of colors in image (0 if >=8bpp) - uint8_t bReserved; // Reserved - uint16_t wPlanes; // Color Planes - uint16_t wBitCount; // Bits per pixel - uint32_t dwBytesInRes; // how many bytes in this resource? - uint32_t dwImageOffset; // where in the file is this image -} ICONDIRENTRY, *LPICONDIRENTRY; - -typedef struct -{ - uint16_t idReserved; // Reserved - uint16_t idType; // resource type (1 for icons) - uint16_t idCount; // how many images? - //ICONDIRENTRY idEntries[1]; // the entries for each image -} ICONDIR, *LPICONDIR; - -// size - 40 bytes -typedef struct -{ - uint32_t biSize; - uint32_t biWidth; - uint32_t biHeight; // Icon Height (added height of XOR-Bitmap and AND-Bitmap) - uint16_t biPlanes; - uint16_t biBitCount; - uint32_t biCompression; - int32_t biSizeImage; - uint32_t biXPelsPerMeter; - uint32_t biYPelsPerMeter; - uint32_t biClrUsed; - uint32_t biClrImportant; -} s_BITMAPINFOHEADER, *s_PBITMAPINFOHEADER; - -// 46 bytes -typedef struct -{ - s_BITMAPINFOHEADER icHeader; // DIB header - uint32_t icColors[1]; // Color table (short 4 bytes) //RGBQUAD - uint8_t icXOR[1]; // DIB bits for XOR mask - uint8_t icAND[1]; // DIB bits for AND mask -} ICONIMAGE, *LPICONIMAGE; - - -class image_ico_ex - : public basic_image_pixbuf -{ - bool _m_read_ico(const void* data, std::size_t /*size*/) - { - auto width = 0; - auto height = 0; - auto buffer = (unsigned char *)data; - auto icoDir = reinterpret_cast(buffer); - int iconsCount = icoDir->idCount; - if (icoDir->idReserved != 0 || icoDir->idType != 1 || iconsCount == 0 || iconsCount > 20) - return false; - - auto cursor = buffer; - cursor += 6; - auto dirEntry = reinterpret_cast(cursor); - auto maxSize = 0; - auto offset = 0; - auto maxBitCount = 0; - for (auto i = 0; i < iconsCount; i++, ++dirEntry) - { - int w = dirEntry->bWidth; - int h = dirEntry->bHeight; - int bitCount = dirEntry->wBitCount; - if (w * h > maxSize || bitCount > maxBitCount) // we choose icon with max resolution - { - width = w; - height = h; - offset = dirEntry->dwImageOffset; - maxSize = w * h; - maxBitCount = bitCount; - } - } - - if (offset == 0) return false; - - cursor = buffer; - cursor += offset; - auto icon = reinterpret_cast(cursor); - auto realBitsCount = static_cast(icon->icHeader.biBitCount); - auto hasAndMask = (realBitsCount < 32) && (height != static_cast(icon->icHeader.biHeight)); - cursor += 40; - pixbuf_.open(width, height); - - // rgba + vertical swap - if (realBitsCount >= 32) - { - for (auto x = 0; x < width; ++x) - for (auto y = 0; y < height; ++y) - { - pixbuf_.alpha_channel(true); - auto shift2 = 4 * (x + (height - y - 1) * width); - pixel_color_t image; - image.element.red = cursor[shift2 + 2]; - image.element.green = cursor[shift2 + 1]; - image.element.blue = cursor[shift2]; - image.element.alpha_channel = cursor[shift2 + 3]; - pixbuf_.pixel(x, y, image); - } - } - - else if (realBitsCount == 24) - { - for (auto x = 0; x < width; x++) - for (auto y = 0; y < height; y++) - { - pixbuf_.alpha_channel(true); - auto shift2 = 3 * (x + (height - y - 1) * width); - pixel_color_t image; - image.element.red = cursor[shift2 + 2]; - image.element.green = cursor[shift2 + 1]; - image.element.blue = cursor[shift2]; - image.element.alpha_channel = 255; - pixbuf_.pixel(x, y, image); - } - } - - else if (realBitsCount == 8) /// 256 colors - { - // 256 color table - auto colors = reinterpret_cast(cursor); - cursor += 256 * 4; - for (auto x = 0; x < width; x++) - for (auto y = 0; y < height; y++) - { - pixbuf_.alpha_channel(true); - - auto shift2 = (x + (height - y - 1) * width); - auto index = 4 * cursor[shift2]; - pixel_color_t image; - image.element.red = colors[index + 2]; - image.element.green = colors[index + 1]; - image.element.blue = colors[index]; - image.element.alpha_channel = 255; - pixbuf_.pixel(x, y, image); - } - } - - else if (realBitsCount == 4) /// 16 colors - { - // 16 color table - auto colors = reinterpret_cast(cursor); - cursor += 16 * 4; - for (auto x = 0; x < width; x++) - for (auto y = 0; y < height; y++) - { - auto shift2 = (x + (height - y - 1) * width); - auto index = cursor[shift2 / 2]; - if (shift2 % 2 == 0) - index = (index >> 4) & 0xF; - else - index = index & 0xF; - index *= 4; - pixbuf_.alpha_channel(true); - pixel_color_t image; - image.element.red = colors[index + 2]; - image.element.green = colors[index + 1]; - image.element.blue = colors[index]; - image.element.alpha_channel = 255; - pixbuf_.pixel(x, y, image); - } - } - - else if (realBitsCount == 1) /// 2 colors - { - // 2 color table - auto colors = reinterpret_cast(cursor); - cursor += 2 * 4; - auto boundary = width; //!!! 32 bit boundary (http://www.daubnet.com/en/file-format-ico) - while (boundary % 32 != 0) boundary++; - for (auto x = 0; x < width; x++) - for (auto y = 0; y < height; y++) - { - auto shift2 = (x + (height - y - 1) * boundary); - auto index = cursor[shift2 / 8]; - - // select 1 bit only - unsigned char bit = 7 - (x % 8); - index = (index >> bit) & 0x01; - index *= 4; - pixbuf_.alpha_channel(true); - pixel_color_t image; - image.element.red = colors[index + 2]; - image.element.green = colors[index + 1]; - image.element.blue = colors[index]; - image.element.alpha_channel = 255; - pixbuf_.pixel(x, y, image); - } - } - - // Read AND mask after base color data - 1 BIT MASK - if (hasAndMask) - { - auto boundary = width * realBitsCount; //!!! 32 bit boundary (http://www.daubnet.com/en/file-format-ico) - while (boundary % 32 != 0) boundary++; - cursor += boundary * height / 8; - boundary = width; - while (boundary % 32 != 0) boundary++; - for (auto y = 0; y < height; y++) - for (auto x = 0; x < width; x++) - { - unsigned char bit = 7 - (x % 8); - auto shift2 = (x + (height - y - 1) * boundary) / 8; - auto mask = (0x01 & (static_cast(cursor[shift2]) >> bit)); - auto pc = pixbuf_.pixel(x, y); - auto alpha = pc.element.alpha_channel; - alpha *= 1 - mask; - pc.element.alpha_channel = alpha; - pixbuf_.pixel(x, y, pc); - } - } - return true; - } -public: - - bool open(const std::experimental::filesystem::path& ico_file) override - { - std::ifstream file(ico_file.string(), std::ios::binary); - if (!file.is_open()) return false; - - // allocates a buffer for the image - file.seekg(0, std::ios::end); - const auto bytes = static_cast(file.tellg()); - file.seekg(0, std::ios::beg); - auto buffer = new char[bytes]; - - // read data from the file and set them in the buffer - file.read(buffer, bytes); - auto okret = _m_read_ico(buffer, bytes); - - // delete buffer and return - delete[] buffer; - return okret; - } - - bool open(const void* data, std::size_t bytes) override - { - return _m_read_ico(data, bytes); - } - -}; -}//end namespace detail -}//end namespace paint -}//end namespace nana - -#endif diff --git a/source/paint/detail/image_ico_resource.hpp b/source/paint/detail/image_ico_resource.hpp new file mode 100644 index 00000000..a7dbaa03 --- /dev/null +++ b/source/paint/detail/image_ico_resource.hpp @@ -0,0 +1,123 @@ +/* + * Icon Resource + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/paint/detail/image_ico_resource.hpp + */ + +#ifndef NANA_PAINT_DETAIL_IMAGE_ICO_RESOURCE_INCLUDED +#define NANA_PAINT_DETAIL_IMAGE_ICO_RESOURCE_INCLUDED + +#include +#include +#include + +#if defined(NANA_WINDOWS) +# include +#endif + +namespace nana{ namespace paint +{ + namespace detail + { + class image_ico_resource + :public image::image_impl_interface + { + public: + bool open(const std::experimental::filesystem::path& filename) override + { +#if defined(NANA_WINDOWS) + SHFILEINFO sfi; + ::SHGetFileInfo(filename.c_str(), 0, &sfi, sizeof sfi, SHGFI_ICON); + + native_handle_ = sfi.hIcon; +#endif + return (nullptr != native_handle_); + } + + bool open(const void* data, std::size_t bytes) override + { + return false; + } + + bool alpha_channel() const override + { + return false; + } + + bool empty() const override + { + return !native_handle_; + } + + void close() override + { +#if defined(NANA_WINDOWS) + if (native_handle_) + ::DestroyIcon(reinterpret_cast(native_handle_)); +#endif + } + + nana::size size() const override + { +#if defined(NANA_WINDOWS) + ICONINFO info; + if ((!native_handle_) || !::GetIconInfo(reinterpret_cast(native_handle_), &info)) + return{}; + + ::nana::size sz{ + info.xHotspot << 1, + info.yHotspot << 1 + }; + + ::DeleteObject(info.hbmColor); + ::DeleteObject(info.hbmMask); + return sz; +#else + return{}; +#endif + } + + virtual void paste(const nana::rectangle& src_r, graph_reference graph, const point& p_dst) const override + { + if (!native_handle_) + return; + +#if defined(NANA_WINDOWS) + ::DrawIconEx(graph.handle()->context, p_dst.x, p_dst.y, reinterpret_cast(native_handle_), src_r.width, src_r.height, 0, 0, DI_NORMAL); +#else + static_cast(src_r); //eliminate unused parameter compiler warning. + static_cast(p_dst); +#endif + + } + + virtual void stretch(const nana::rectangle&, graph_reference graph, const nana::rectangle& r) const override + { + if (!native_handle_) + return; + +#if defined(NANA_WINDOWS) + ::DrawIconEx(graph.handle()->context, r.x, r.y, reinterpret_cast(native_handle_), r.width, r.height, 0, 0, DI_NORMAL); +#else + static_cast(r); //eliminate unused parameter compiler warning. +#endif + } + + void* native_handle() + { + return native_handle_; + } + private: + void* native_handle_; + };//end class image_ico + } +}//end namespace paint +}//end namespace nana + +#endif diff --git a/source/paint/image.cpp b/source/paint/image.cpp index 6875a198..0f4cef18 100644 --- a/source/paint/image.cpp +++ b/source/paint/image.cpp @@ -1,7 +1,7 @@ /* * Paint Image Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -11,6 +11,7 @@ * @contributors: * nabijaczleweli(pr#106) */ + #include #include #include @@ -32,10 +33,10 @@ #endif #include "detail/image_bmp.hpp" -#include "detail/image_ico.hpp" #include "image_accessor.hpp" -#include "detail/image_ico_ex.hpp" +#include "detail/image_ico_resource.hpp" +#include "detail/image_ico.hpp" namespace fs = std::experimental::filesystem; @@ -46,9 +47,14 @@ namespace paint #if defined(NANA_WINDOWS) HICON image_accessor::icon(const nana::paint::image& img) { + auto ico_res = dynamic_cast(img.image_ptr_.get()); + if (ico_res) + return reinterpret_cast(ico_res->native_handle()); + auto ico = dynamic_cast(img.image_ptr_.get()); - if (ico && ico->ptr()) - return *(ico->ptr()); + if (ico) + return reinterpret_cast(ico->native_handle()); + return nullptr; } #else @@ -58,138 +64,6 @@ namespace paint } #endif - namespace detail - { - //class image_ico - image_ico::image_ico(bool is_ico): is_ico_(is_ico){} - - bool image_ico::open(const fs::path& file) - { - close(); -#if defined(NANA_WINDOWS) - HICON handle = 0; - if(is_ico_) - { - handle = (HICON)::LoadImage(0, file.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); - } - else - { - SHFILEINFO sfi; - ::SHGetFileInfo(file.c_str(), 0, &sfi, sizeof(sfi), SHGFI_ICON); - handle = sfi.hIcon; - } - - if(handle) - { - HICON * p = new HICON(handle); - ptr_ = std::shared_ptr(p, handle_deleter()); - ICONINFO info; - ::GetIconInfo(handle, &info); - size_.width = (info.xHotspot << 1); - size_.height = (info.yHotspot << 1); - - ::DeleteObject(info.hbmColor); - ::DeleteObject(info.hbmMask); - return true; - } -#else - static_cast(is_ico_); //eliminate the unused compiler warning in Linux. - static_cast(file); //to eliminate the unused parameter compiler warning. -#endif - return false; - } - - bool image_ico::open(const void* data, std::size_t bytes) - { - close(); -#if defined(NANA_WINDOWS) - // use actual resource size, stopped using CreateIconFromResource since it loads blurry image - HICON handle = ::CreateIconFromResourceEx((PBYTE)data, static_cast(bytes), TRUE, 0x00030000, 0, 0, LR_DEFAULTCOLOR); - if(handle) - { - ICONINFO info; - if (::GetIconInfo(handle, &info) != 0) - { - HICON * p = new HICON(handle); - ptr_ = std::shared_ptr(p, handle_deleter()); - size_.width = (info.xHotspot << 1); - size_.height = (info.yHotspot << 1); - ::DeleteObject(info.hbmColor); - ::DeleteObject(info.hbmMask); - return true; - } - } -#else - static_cast(is_ico_); //kill the unused compiler warning in Linux. - static_cast(data); //to eliminate unused parameter compiler warning. - static_cast(bytes); -#endif - return false; - } - - bool image_ico::alpha_channel() const - { - return false; - } - - bool image_ico::empty() const - { - return (nullptr == ptr_); - } - - void image_ico::close() - { - ptr_.reset(); - } - - nana::size image_ico::size() const - { - return size_; - } - - void image_ico::paste(const nana::rectangle& src_r, graph_reference graph, const point& p_dst) const - { - if(ptr_ && (graph.empty() == false)) - { -#if defined(NANA_WINDOWS) - ::DrawIconEx(graph.handle()->context, p_dst.x, p_dst.y, *ptr_, src_r.width, src_r.height, 0, 0, DI_NORMAL); -#else - static_cast(src_r); //eliminate unused parameter compiler warning. - static_cast(p_dst); -#endif - } - } - - void image_ico::stretch(const nana::rectangle&, graph_reference graph, const nana::rectangle& r) const - { - if(ptr_ && (graph.empty() == false)) - { -#if defined(NANA_WINDOWS) - ::DrawIconEx(graph.handle()->context, r.x, r.y, *ptr_, r.width, r.height, 0, 0, DI_NORMAL); -#else - static_cast(r); //eliminate unused parameter compiler warning. -#endif - } - } - - const image_ico::ptr_t& image_ico::ptr() const - { - return ptr_; - } - -#if defined(NANA_WINDOWS) - //struct handle_deleter - void image_ico::handle_deleter::operator()(HICON* p) const - { - if(p && *p) - ::DestroyIcon(*p); - delete p; - } - //end struct handle_deleter -#endif - //end class image_ico - } - image::image_impl_interface::~image_impl_interface() {} @@ -265,7 +139,7 @@ namespace paint { if (ext_ico == ext) { - ptr = std::make_shared(); + ptr = std::make_shared(); break; } @@ -305,7 +179,7 @@ namespace paint if (*reinterpret_cast("BM") == meta) ptr = std::make_shared(); else if (*reinterpret_cast("MZ") == meta) - ptr = std::make_shared(false); + ptr = std::make_shared(); } } @@ -339,7 +213,7 @@ namespace paint if (*reinterpret_cast("BM") == meta) ptr = std::make_shared(); else if (*reinterpret_cast("MZ") == meta) - ptr = std::make_shared(false); + ptr = std::make_shared(); else { if (bytes > 8 && (0x474e5089 == *reinterpret_cast(data))) @@ -357,16 +231,16 @@ namespace paint else if (bytes > 9 && (0x66697845 == *reinterpret_cast(reinterpret_cast(data)+5))) //Exif ptr = std::make_shared(); #endif - -#if defined(NANA_WINDOWS) - // suppose icon data is bitmap data - if (!ptr && bytes > 40 /* sizeof(BITMAPINFOHEADER) */ && (40 == *reinterpret_cast(data))) { - ptr = std::make_shared(true); + if ((!ptr) && (bytes > 40)) + { + switch (*reinterpret_cast(data)) + { + case 40: + case 0x00010000: + if (!ptr && bytes > 40) + ptr = std::make_shared(); + } } - else -#endif - if (!ptr && bytes > 40 && (0x00010000 == *reinterpret_cast(data))) - ptr = std::make_shared(); } }