fix bug where window can't load icon with ico(#192)

This commit is contained in:
Jinhao
2017-03-24 05:30:47 +08:00
parent c8d0b2a621
commit b1fe1ca412
6 changed files with 434 additions and 445 deletions

View File

@@ -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 <nana/push_ignore_diagnostic>
#include <nana/detail/platform_spec_selector.hpp>
#include <nana/paint/image.hpp>
@@ -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<paint::detail::image_ico_resource*>(img.image_ptr_.get());
if (ico_res)
return reinterpret_cast<HICON>(ico_res->native_handle());
auto ico = dynamic_cast<paint::detail::image_ico*>(img.image_ptr_.get());
if (ico && ico->ptr())
return *(ico->ptr());
if (ico)
return reinterpret_cast<HICON>(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<HICON>(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<void>(is_ico_); //eliminate the unused compiler warning in Linux.
static_cast<void>(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<DWORD>(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<HICON>(p, handle_deleter());
size_.width = (info.xHotspot << 1);
size_.height = (info.yHotspot << 1);
::DeleteObject(info.hbmColor);
::DeleteObject(info.hbmMask);
return true;
}
}
#else
static_cast<void>(is_ico_); //kill the unused compiler warning in Linux.
static_cast<void>(data); //to eliminate unused parameter compiler warning.
static_cast<void>(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<void>(src_r); //eliminate unused parameter compiler warning.
static_cast<void>(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<void>(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<detail::image_ico_ex>();
ptr = std::make_shared<detail::image_ico>();
break;
}
@@ -305,7 +179,7 @@ namespace paint
if (*reinterpret_cast<const short*>("BM") == meta)
ptr = std::make_shared<detail::image_bmp>();
else if (*reinterpret_cast<const short*>("MZ") == meta)
ptr = std::make_shared<detail::image_ico>(false);
ptr = std::make_shared<detail::image_ico_resource>();
}
}
@@ -339,7 +213,7 @@ namespace paint
if (*reinterpret_cast<const short*>("BM") == meta)
ptr = std::make_shared<detail::image_bmp>();
else if (*reinterpret_cast<const short*>("MZ") == meta)
ptr = std::make_shared<detail::image_ico>(false);
ptr = std::make_shared<detail::image_ico_resource>();
else
{
if (bytes > 8 && (0x474e5089 == *reinterpret_cast<const unsigned*>(data)))
@@ -357,16 +231,16 @@ namespace paint
else if (bytes > 9 && (0x66697845 == *reinterpret_cast<const unsigned*>(reinterpret_cast<const char*>(data)+5))) //Exif
ptr = std::make_shared<detail::image_jpeg>();
#endif
#if defined(NANA_WINDOWS)
// suppose icon data is bitmap data
if (!ptr && bytes > 40 /* sizeof(BITMAPINFOHEADER) */ && (40 == *reinterpret_cast<const uint32_t*>(data))) {
ptr = std::make_shared<detail::image_ico>(true);
if ((!ptr) && (bytes > 40))
{
switch (*reinterpret_cast<const unsigned*>(data))
{
case 40:
case 0x00010000:
if (!ptr && bytes > 40)
ptr = std::make_shared<detail::image_ico>();
}
}
else
#endif
if (!ptr && bytes > 40 && (0x00010000 == *reinterpret_cast<const unsigned*>(data)))
ptr = std::make_shared<detail::image_ico_ex>();
}
}