open png/jpg image with memory buffer
This commit is contained in:
parent
5a960ed88c
commit
3c8ee33ae8
@ -28,7 +28,7 @@ namespace paint
|
|||||||
public:
|
public:
|
||||||
class image_impl_interface;
|
class image_impl_interface;
|
||||||
|
|
||||||
image();
|
image() noexcept;
|
||||||
image(const image&);
|
image(const image&);
|
||||||
image(image&&);
|
image(image&&);
|
||||||
explicit image(const ::std::string& file);
|
explicit image(const ::std::string& file);
|
||||||
@ -41,13 +41,13 @@ namespace paint
|
|||||||
bool open(const ::std::wstring& file);
|
bool open(const ::std::wstring& file);
|
||||||
|
|
||||||
/// Opens an icon from a specified buffer
|
/// Opens an icon from a specified buffer
|
||||||
bool open_icon(const void* data, std::size_t bytes);
|
bool open(const void* data, std::size_t bytes);
|
||||||
bool empty() const;
|
bool empty() const noexcept;
|
||||||
operator unspecified_bool_t() const;
|
operator unspecified_bool_t() const;
|
||||||
void close();
|
void close() noexcept;
|
||||||
|
|
||||||
bool alpha() const;
|
bool alpha() const noexcept;
|
||||||
nana::size size() const;
|
nana::size size() const noexcept;
|
||||||
void paste(graphics& dst, const point& p_dst) const;
|
void paste(graphics& dst, const point& p_dst) const;
|
||||||
void paste(const nana::rectangle& r_src, graphics& dst, const point& p_dst) const;///< Paste the area of picture specified by r_src into the destination graphics specified by dst at position p_dst.
|
void paste(const nana::rectangle& r_src, graphics& dst, const point& p_dst) const;///< Paste the area of picture specified by r_src into the destination graphics specified by dst at position p_dst.
|
||||||
void stretch(const nana::rectangle& r_src, graphics& dst, const nana::rectangle& r_dst) const;///<Paste the picture into the dst, stretching or compressing the picture to fit the given area.
|
void stretch(const nana::rectangle& r_src, graphics& dst, const nana::rectangle& r_dst) const;///<Paste the picture into the dst, stretching or compressing the picture to fit the given area.
|
||||||
|
|||||||
@ -13,10 +13,12 @@
|
|||||||
#ifndef NANA_PAT_CLONEABLE_HPP
|
#ifndef NANA_PAT_CLONEABLE_HPP
|
||||||
#define NANA_PAT_CLONEABLE_HPP
|
#define NANA_PAT_CLONEABLE_HPP
|
||||||
|
|
||||||
|
#include <nana/c++defines.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
namespace nana{ namespace pat{
|
namespace nana{ namespace pat{
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
@ -99,9 +101,9 @@ namespace nana{ namespace pat{
|
|||||||
: public std::enable_if<(!std::is_base_of<cloneable, typename std::remove_reference<U>::type>::value) && std::is_base_of<base_t, typename std::remove_reference<U>::type>::value, int>
|
: public std::enable_if<(!std::is_base_of<cloneable, typename std::remove_reference<U>::type>::value) && std::is_base_of<base_t, typename std::remove_reference<U>::type>::value, int>
|
||||||
{};
|
{};
|
||||||
public:
|
public:
|
||||||
cloneable() = default;
|
cloneable() noexcept = default;
|
||||||
|
|
||||||
cloneable(std::nullptr_t){}
|
cloneable(std::nullptr_t) noexcept{}
|
||||||
|
|
||||||
template<typename T, typename member_enabled<T>::type* = nullptr>
|
template<typename T, typename member_enabled<T>::type* = nullptr>
|
||||||
cloneable(T&& t)
|
cloneable(T&& t)
|
||||||
@ -166,22 +168,22 @@ namespace nana{ namespace pat{
|
|||||||
return *fast_ptr_;
|
return *fast_ptr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const_base_ref operator*() const
|
const_base_ref operator*() const noexcept
|
||||||
{
|
{
|
||||||
return *fast_ptr_;
|
return *fast_ptr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
base_t * operator->()
|
base_t * operator->() noexcept
|
||||||
{
|
{
|
||||||
return fast_ptr_;
|
return fast_ptr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const_base_ptr operator->() const
|
const_base_ptr operator->() const noexcept
|
||||||
{
|
{
|
||||||
return fast_ptr_;
|
return fast_ptr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
base_t * get() const
|
base_t * get() const noexcept
|
||||||
{
|
{
|
||||||
return fast_ptr_;
|
return fast_ptr_;
|
||||||
}
|
}
|
||||||
@ -192,7 +194,7 @@ namespace nana{ namespace pat{
|
|||||||
cwrapper_.reset();
|
cwrapper_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
operator operator_bool_t() const volatile
|
operator operator_bool_t() const volatile noexcept
|
||||||
{
|
{
|
||||||
return (fast_ptr_ ? &inner_bool::true_stand : nullptr);
|
return (fast_ptr_ ? &inner_bool::true_stand : nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* A Thread Pool Implementation
|
* A Thread Pool Implementation
|
||||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
||||||
*
|
*
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#if defined(STD_THREAD_NOT_SUPPORTED)
|
#if defined(STD_THREAD_NOT_SUPPORTED)
|
||||||
#include <nana/std_thread.hpp>
|
#include <nana/std_thread.hpp>
|
||||||
@ -350,7 +351,7 @@ namespace nana
|
|||||||
struct animation::impl
|
struct animation::impl
|
||||||
{
|
{
|
||||||
bool looped{false};
|
bool looped{false};
|
||||||
volatile bool paused{true};
|
std::atomic<bool> paused{true};
|
||||||
std::size_t fps;
|
std::size_t fps;
|
||||||
|
|
||||||
std::list<frameset> framesets;
|
std::list<frameset> framesets;
|
||||||
|
|||||||
@ -25,6 +25,27 @@ namespace nana
|
|||||||
struct ::jpeg_error_mgr pub;
|
struct ::jpeg_error_mgr pub;
|
||||||
std::jmp_buf setjmp_buf;
|
std::jmp_buf setjmp_buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void _m_read_jpg(jpeg_decompress_struct& jdstru)
|
||||||
|
{
|
||||||
|
::jpeg_read_header(&jdstru, true); //Reject a tables-only JPEG file as an error
|
||||||
|
|
||||||
|
::jpeg_start_decompress(&jdstru);
|
||||||
|
|
||||||
|
//JSAMPLEs per row in output buffer
|
||||||
|
auto row_stride = jdstru.output_width * jdstru.output_components;
|
||||||
|
|
||||||
|
pixbuf_.open(jdstru.output_width, jdstru.output_height);
|
||||||
|
|
||||||
|
auto row_buf = jdstru.mem->alloc_sarray(reinterpret_cast<j_common_ptr>(&jdstru), JPOOL_IMAGE, row_stride, 1);
|
||||||
|
|
||||||
|
while (jdstru.output_scanline < jdstru.output_height)
|
||||||
|
{
|
||||||
|
::jpeg_read_scanlines(&jdstru, row_buf, 1);
|
||||||
|
|
||||||
|
pixbuf_.fill_row(jdstru.output_scanline - 1, reinterpret_cast<unsigned char*>(*row_buf), row_stride, jdstru.output_components * 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
bool open(const experimental::filesystem::path& jpeg_file) override
|
bool open(const experimental::filesystem::path& jpeg_file) override
|
||||||
{
|
{
|
||||||
@ -45,25 +66,10 @@ namespace nana
|
|||||||
|
|
||||||
::jpeg_stdio_src(&jdstru, fp);
|
::jpeg_stdio_src(&jdstru, fp);
|
||||||
|
|
||||||
::jpeg_read_header(&jdstru, true); //Reject a tables-only JPEG file as an error
|
_m_read_jpg(jdstru);
|
||||||
|
|
||||||
::jpeg_start_decompress(&jdstru);
|
|
||||||
|
|
||||||
//JSAMPLEs per row in output buffer
|
|
||||||
auto row_stride = jdstru.output_width * jdstru.output_components;
|
|
||||||
|
|
||||||
pixbuf_.open(jdstru.output_width, jdstru.output_height);
|
|
||||||
|
|
||||||
auto row_buf = jdstru.mem->alloc_sarray(reinterpret_cast<j_common_ptr>(&jdstru), JPOOL_IMAGE, row_stride, 1);
|
|
||||||
|
|
||||||
while (jdstru.output_scanline < jdstru.output_height)
|
|
||||||
{
|
|
||||||
::jpeg_read_scanlines(&jdstru, row_buf, 1);
|
|
||||||
|
|
||||||
pixbuf_.fill_row(jdstru.output_scanline - 1, reinterpret_cast<unsigned char*>(*row_buf), row_stride, jdstru.output_components * 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
jpeg_finish_decompress(&jdstru);
|
jpeg_finish_decompress(&jdstru);
|
||||||
|
is_opened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
::jpeg_destroy_decompress(&jdstru);
|
::jpeg_destroy_decompress(&jdstru);
|
||||||
@ -73,8 +79,27 @@ namespace nana
|
|||||||
|
|
||||||
bool open(const void* data, std::size_t bytes) override
|
bool open(const void* data, std::size_t bytes) override
|
||||||
{
|
{
|
||||||
throw std::logic_error("JPEG is not supported for raw data buffer");
|
bool is_opened = false;
|
||||||
return false;
|
|
||||||
|
struct ::jpeg_decompress_struct jdstru;
|
||||||
|
error_mgr jerr;
|
||||||
|
|
||||||
|
jdstru.err = ::jpeg_std_error(&jerr.pub);
|
||||||
|
jerr.pub.error_exit = _m_error_handler;
|
||||||
|
|
||||||
|
if (!setjmp(jerr.setjmp_buf))
|
||||||
|
{
|
||||||
|
::jpeg_create_decompress(&jdstru);
|
||||||
|
|
||||||
|
::jpeg_mem_src(&jdstru, const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(data)), bytes);
|
||||||
|
_m_read_jpg(jdstru);
|
||||||
|
|
||||||
|
jpeg_finish_decompress(&jdstru);
|
||||||
|
is_opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
::jpeg_destroy_decompress(&jdstru);
|
||||||
|
return is_opened;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static void _m_error_handler(::j_common_ptr jdstru)
|
static void _m_error_handler(::j_common_ptr jdstru)
|
||||||
|
|||||||
@ -19,6 +19,107 @@ namespace nana
|
|||||||
class image_png
|
class image_png
|
||||||
: public basic_image_pixbuf
|
: public basic_image_pixbuf
|
||||||
{
|
{
|
||||||
|
void _m_read_png(png_structp png_ptr, png_infop info_ptr)
|
||||||
|
{
|
||||||
|
::png_read_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
const int png_width = ::png_get_image_width(png_ptr, info_ptr);
|
||||||
|
const int png_height = ::png_get_image_height(png_ptr, info_ptr);
|
||||||
|
png_byte color_type = ::png_get_color_type(png_ptr, info_ptr);
|
||||||
|
const auto bit_depth = ::png_get_bit_depth(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
//do some extra work for palette/gray color type
|
||||||
|
if (PNG_COLOR_TYPE_PALETTE == color_type)
|
||||||
|
::png_set_palette_to_rgb(png_ptr);
|
||||||
|
else if ((PNG_COLOR_TYPE_GRAY == color_type) && (bit_depth < 8))
|
||||||
|
::png_set_gray_to_rgb(png_ptr);
|
||||||
|
|
||||||
|
auto is_alpha_enabled = (::png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) != 0);
|
||||||
|
if (is_alpha_enabled)
|
||||||
|
::png_set_tRNS_to_alpha(png_ptr);
|
||||||
|
|
||||||
|
//make sure 8-bit per channel
|
||||||
|
if (16 == bit_depth)
|
||||||
|
::png_set_strip_16(png_ptr);
|
||||||
|
|
||||||
|
::png_set_interlace_handling(png_ptr);
|
||||||
|
::png_read_update_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
//The following codes may longjmp while image_read error.
|
||||||
|
png_bytep * row_ptrs = new png_bytep[png_height];
|
||||||
|
const std::size_t png_rowbytes = ::png_get_rowbytes(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
pixbuf_.open(png_width, png_height);
|
||||||
|
|
||||||
|
is_alpha_enabled |= ((PNG_COLOR_MASK_ALPHA & color_type) != 0);
|
||||||
|
pixbuf_.alpha_channel(is_alpha_enabled);
|
||||||
|
|
||||||
|
if (is_alpha_enabled && (png_rowbytes == png_width * sizeof(pixel_argb_t)))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < png_height; ++i)
|
||||||
|
row_ptrs[i] = reinterpret_cast<png_bytep>(pixbuf_.raw_ptr(i));
|
||||||
|
|
||||||
|
::png_read_image(png_ptr, row_ptrs);
|
||||||
|
|
||||||
|
for (int i = 0; i < png_height; ++i)
|
||||||
|
{
|
||||||
|
auto p = pixbuf_.raw_ptr(i);
|
||||||
|
for (int u = 0; u < png_width; ++u)
|
||||||
|
{
|
||||||
|
auto t = p[u].element.red;
|
||||||
|
p[u].element.red = p[u].element.blue;
|
||||||
|
p[u].element.blue = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
png_byte * png_pixbuf = new png_byte[png_height * png_rowbytes];
|
||||||
|
|
||||||
|
for (int i = 0; i < png_height; ++i)
|
||||||
|
row_ptrs[i] = reinterpret_cast<png_bytep>(png_pixbuf + png_rowbytes * i);
|
||||||
|
|
||||||
|
::png_read_image(png_ptr, row_ptrs);
|
||||||
|
//::png_destroy_read_struct(&png_ptr, &info_ptr, 0);
|
||||||
|
|
||||||
|
std::size_t png_pixel_bytes = png_rowbytes / png_width;
|
||||||
|
|
||||||
|
pixel_argb_t * rgb_row_ptr = pixbuf_.raw_ptr(0);
|
||||||
|
for (int y = 0; y < png_height; ++y)
|
||||||
|
{
|
||||||
|
png_bytep png_ptr = row_ptrs[y];
|
||||||
|
|
||||||
|
pixel_argb_t * rgb_end = rgb_row_ptr + png_width;
|
||||||
|
|
||||||
|
if (is_alpha_enabled)
|
||||||
|
{
|
||||||
|
for (pixel_argb_t * i = rgb_row_ptr; i < rgb_end; ++i)
|
||||||
|
{
|
||||||
|
i->element.red = png_ptr[0];
|
||||||
|
i->element.green = png_ptr[1];
|
||||||
|
i->element.blue = png_ptr[2];
|
||||||
|
i->element.alpha_channel = png_ptr[3];
|
||||||
|
png_ptr += png_pixel_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (pixel_argb_t * i = rgb_row_ptr; i < rgb_end; ++i)
|
||||||
|
{
|
||||||
|
i->element.red = png_ptr[0];
|
||||||
|
i->element.green = png_ptr[1];
|
||||||
|
i->element.blue = png_ptr[2];
|
||||||
|
i->element.alpha_channel = 255;
|
||||||
|
png_ptr += png_pixel_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rgb_row_ptr = rgb_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] png_pixbuf;
|
||||||
|
}
|
||||||
|
delete[] row_ptrs;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
bool open(const experimental::filesystem::path& png_file) override
|
bool open(const experimental::filesystem::path& png_file) override
|
||||||
{
|
{
|
||||||
@ -44,109 +145,17 @@ namespace nana
|
|||||||
{
|
{
|
||||||
//The following codes may longjmp while init_io error.
|
//The following codes may longjmp while init_io error.
|
||||||
::png_init_io(png_ptr, fp);
|
::png_init_io(png_ptr, fp);
|
||||||
|
|
||||||
|
//8-byte of sig has been read, tell the libpng there are some bytes missing from start of file
|
||||||
::png_set_sig_bytes(png_ptr, 8);
|
::png_set_sig_bytes(png_ptr, 8);
|
||||||
::png_read_info(png_ptr, info_ptr);
|
|
||||||
|
|
||||||
const int png_width = ::png_get_image_width(png_ptr, info_ptr);
|
_m_read_png(png_ptr, info_ptr);
|
||||||
const int png_height = ::png_get_image_height(png_ptr, info_ptr);
|
|
||||||
png_byte color_type = ::png_get_color_type(png_ptr, info_ptr);
|
|
||||||
const auto bit_depth = ::png_get_bit_depth(png_ptr, info_ptr);
|
|
||||||
|
|
||||||
//do some extra work for palette/gray color type
|
|
||||||
if (PNG_COLOR_TYPE_PALETTE == color_type)
|
|
||||||
::png_set_palette_to_rgb(png_ptr);
|
|
||||||
else if ((PNG_COLOR_TYPE_GRAY == color_type) && (bit_depth < 8))
|
|
||||||
::png_set_gray_to_rgb(png_ptr);
|
|
||||||
|
|
||||||
bool is_alpha_enabled = (::png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) != 0);
|
|
||||||
if (is_alpha_enabled)
|
|
||||||
::png_set_tRNS_to_alpha(png_ptr);
|
|
||||||
|
|
||||||
//make sure 8-bit per channel
|
|
||||||
if (16 == bit_depth)
|
|
||||||
::png_set_strip_16(png_ptr);
|
|
||||||
|
|
||||||
::png_set_interlace_handling(png_ptr);
|
|
||||||
::png_read_update_info(png_ptr, info_ptr);
|
|
||||||
|
|
||||||
//The following codes may longjmp while image_read error.
|
|
||||||
png_bytep * row_ptrs = new png_bytep[png_height];
|
|
||||||
const std::size_t png_rowbytes = ::png_get_rowbytes(png_ptr, info_ptr);
|
|
||||||
|
|
||||||
pixbuf_.open(png_width, png_height);
|
|
||||||
|
|
||||||
is_alpha_enabled |= ((PNG_COLOR_MASK_ALPHA & color_type) != 0);
|
|
||||||
pixbuf_.alpha_channel(is_alpha_enabled);
|
|
||||||
|
|
||||||
if(is_alpha_enabled && (png_rowbytes == png_width * sizeof(pixel_argb_t)))
|
|
||||||
{
|
|
||||||
for(int i = 0; i < png_height; ++i)
|
|
||||||
row_ptrs[i] = reinterpret_cast<png_bytep>(pixbuf_.raw_ptr(i));
|
|
||||||
|
|
||||||
::png_read_image(png_ptr, row_ptrs);
|
|
||||||
::png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
|
||||||
|
|
||||||
for (int i = 0; i < png_height; ++i)
|
|
||||||
{
|
|
||||||
auto p = pixbuf_.raw_ptr(i);
|
|
||||||
for (int u = 0; u < png_width; ++u)
|
|
||||||
{
|
|
||||||
auto t = p[u].element.red;
|
|
||||||
p[u].element.red = p[u].element.blue;
|
|
||||||
p[u].element.blue = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
png_byte * png_pixbuf = new png_byte[png_height * png_rowbytes];
|
|
||||||
|
|
||||||
for(int i = 0; i < png_height; ++i)
|
|
||||||
row_ptrs[i] = reinterpret_cast<png_bytep>(png_pixbuf + png_rowbytes * i);
|
|
||||||
|
|
||||||
::png_read_image(png_ptr, row_ptrs);
|
|
||||||
::png_destroy_read_struct(&png_ptr, &info_ptr, 0);
|
|
||||||
|
|
||||||
std::size_t png_pixel_bytes = png_rowbytes / png_width;
|
|
||||||
|
|
||||||
pixel_argb_t * rgb_row_ptr = pixbuf_.raw_ptr(0);
|
|
||||||
for(int y = 0; y < png_height; ++y)
|
|
||||||
{
|
|
||||||
png_bytep png_ptr = row_ptrs[y];
|
|
||||||
|
|
||||||
pixel_argb_t * rgb_end = rgb_row_ptr + png_width;
|
|
||||||
|
|
||||||
if(is_alpha_enabled)
|
|
||||||
{
|
|
||||||
for(pixel_argb_t * i = rgb_row_ptr; i < rgb_end; ++i)
|
|
||||||
{
|
|
||||||
i->element.red = png_ptr[0];
|
|
||||||
i->element.green = png_ptr[1];
|
|
||||||
i->element.blue = png_ptr[2];
|
|
||||||
i->element.alpha_channel = png_ptr[3];
|
|
||||||
png_ptr += png_pixel_bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(pixel_argb_t * i = rgb_row_ptr; i < rgb_end; ++i)
|
|
||||||
{
|
|
||||||
i->element.red = png_ptr[0];
|
|
||||||
i->element.green = png_ptr[1];
|
|
||||||
i->element.blue = png_ptr[2];
|
|
||||||
i->element.alpha_channel = 255;
|
|
||||||
png_ptr += png_pixel_bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rgb_row_ptr = rgb_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete [] png_pixbuf;
|
|
||||||
}
|
|
||||||
delete [] row_ptrs;
|
|
||||||
is_opened = true;
|
is_opened = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,10 +163,60 @@ namespace nana
|
|||||||
return is_opened;
|
return is_opened;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class png_reader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
png_reader(const void* data, std::size_t bytes) noexcept
|
||||||
|
: data_ptr_(reinterpret_cast<const char*>(data)), bytes_(bytes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PNGCAPI read(png_structp png_ptr, png_bytep buf, png_size_t bytes)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<png_reader*>(::png_get_io_ptr(png_ptr));
|
||||||
|
|
||||||
|
auto read_bytes = self->bytes_ < bytes ? self->bytes_ : bytes;
|
||||||
|
|
||||||
|
if (read_bytes)
|
||||||
|
std::memcpy(buf, self->data_ptr_, read_bytes);
|
||||||
|
|
||||||
|
self->bytes_ -= read_bytes;
|
||||||
|
self->data_ptr_ += read_bytes;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const char* data_ptr_;
|
||||||
|
std::size_t bytes_;
|
||||||
|
};
|
||||||
|
|
||||||
bool open(const void* data, std::size_t bytes) override
|
bool open(const void* data, std::size_t bytes) override
|
||||||
{
|
{
|
||||||
throw std::logic_error("PNG is not supported for raw data buffer");
|
if (bytes < 8 || 0 != ::png_sig_cmp(reinterpret_cast<png_const_bytep>(data), 0, 8))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
auto png_ptr = ::png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
||||||
|
if (!png_ptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool is_opened = false;
|
||||||
|
|
||||||
|
png_infop info_ptr = ::png_create_info_struct(png_ptr);
|
||||||
|
|
||||||
|
if (info_ptr)
|
||||||
|
{
|
||||||
|
png_reader reader{ data, bytes };
|
||||||
|
|
||||||
|
if (!setjmp(png_jmpbuf(png_ptr)))
|
||||||
|
{
|
||||||
|
::png_set_read_fn(png_ptr, &reader, &png_reader::read);
|
||||||
|
|
||||||
|
_m_read_png(png_ptr, info_ptr);
|
||||||
|
is_opened = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||||
|
|
||||||
|
return is_opened;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}//end namespace detail
|
}//end namespace detail
|
||||||
|
|||||||
@ -163,7 +163,7 @@ namespace paint
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
//class image
|
//class image
|
||||||
image::image()
|
image::image() noexcept
|
||||||
{}
|
{}
|
||||||
|
|
||||||
image::image(const image& rhs)
|
image::image(const image& rhs)
|
||||||
@ -245,7 +245,7 @@ namespace paint
|
|||||||
if (ext_png == ext)
|
if (ext_png == ext)
|
||||||
{
|
{
|
||||||
#if defined(NANA_ENABLE_PNG)
|
#if defined(NANA_ENABLE_PNG)
|
||||||
ptr = std::make_shared<detail::image_png>;
|
ptr = std::make_shared<detail::image_png>();
|
||||||
#else
|
#else
|
||||||
return ptr;
|
return ptr;
|
||||||
#endif
|
#endif
|
||||||
@ -299,14 +299,53 @@ namespace paint
|
|||||||
return (image_ptr_ ? image_ptr_->open(path) : false);
|
return (image_ptr_ ? image_ptr_->open(path) : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool image::open_icon(const void* data, std::size_t bytes)
|
bool image::open(const void* data, std::size_t bytes)
|
||||||
{
|
{
|
||||||
image::image_impl_interface * helper = new detail::image_ico(true);
|
close();
|
||||||
image_ptr_ = std::shared_ptr<image_impl_interface>(helper);
|
|
||||||
return helper->open(data, bytes);
|
if (bytes > 2)
|
||||||
|
{
|
||||||
|
std::shared_ptr<image::image_impl_interface> ptr;
|
||||||
|
|
||||||
|
auto meta = *reinterpret_cast<const unsigned short*>(data);
|
||||||
|
|
||||||
|
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);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (bytes > 8 && (0x474e5089 == *reinterpret_cast<const unsigned*>(data)))
|
||||||
|
{
|
||||||
|
#if defined(NANA_ENABLE_PNG)
|
||||||
|
ptr = std::make_shared<detail::image_png>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if defined(NANA_ENABLE_JPEG)
|
||||||
|
//JFIF
|
||||||
|
if (bytes > 11 && (0xe0ffd8ff == *reinterpret_cast<const unsigned*>(data)) && 0x4649464A == *reinterpret_cast<const unsigned*>(reinterpret_cast<const char*>(data)+6))
|
||||||
|
ptr = std::make_shared<detail::image_jpeg>();
|
||||||
|
else if (bytes > 9 && (0x66697845 == *reinterpret_cast<const unsigned*>(reinterpret_cast<const char*>(data)+5))) //Exif
|
||||||
|
ptr = std::make_shared<detail::image_jpeg>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool image::empty() const
|
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
image_ptr_.swap(ptr);
|
||||||
|
return image_ptr_->open(data, bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool image::empty() const noexcept
|
||||||
{
|
{
|
||||||
return ((nullptr == image_ptr_) || image_ptr_->empty());
|
return ((nullptr == image_ptr_) || image_ptr_->empty());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* A Thread Pool Implementation
|
* A Thread Pool Implementation
|
||||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
||||||
*
|
*
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@ -15,6 +15,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#if defined(STD_THREAD_NOT_SUPPORTED)
|
#if defined(STD_THREAD_NOT_SUPPORTED)
|
||||||
#include <nana/std_mutex.hpp>
|
#include <nana/std_mutex.hpp>
|
||||||
@ -62,23 +63,22 @@ namespace threads
|
|||||||
{
|
{
|
||||||
#if defined(NANA_WINDOWS)
|
#if defined(NANA_WINDOWS)
|
||||||
typedef HANDLE thread_t;
|
typedef HANDLE thread_t;
|
||||||
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
|
#elif defined(NANA_POSIX)
|
||||||
typedef pthread_t thread_t;
|
typedef pthread_t thread_t;
|
||||||
#endif
|
#endif
|
||||||
impl * pool_ptr;
|
impl * pool_ptr;
|
||||||
task * task_ptr;
|
task * task_ptr;
|
||||||
thread_t handle;
|
thread_t handle;
|
||||||
volatile state thr_state;
|
std::atomic<state> thr_state;
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
#if defined(NANA_LINUX) || defined(NANA_MACOS)
|
#if defined(NANA_POSIX)
|
||||||
std::mutex wait_mutex;
|
std::mutex wait_mutex;
|
||||||
std::condition_variable wait_cond;
|
std::condition_variable wait_cond;
|
||||||
volatile bool suspended;
|
std::atomic<bool> suspended;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
impl(std::size_t thr_number)
|
impl(std::size_t thr_number)
|
||||||
: runflag_(true)
|
|
||||||
{
|
{
|
||||||
if(0 == thr_number) thr_number = 4;
|
if(0 == thr_number) thr_number = 4;
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ namespace threads
|
|||||||
pto->task_ptr = nullptr;
|
pto->task_ptr = nullptr;
|
||||||
#if defined(NANA_WINDOWS)
|
#if defined(NANA_WINDOWS)
|
||||||
pto->handle = (HANDLE)::_beginthreadex(0, 0, reinterpret_cast<unsigned(__stdcall*)(void*)>(&impl::_m_thr_starter), pto, 0, 0);
|
pto->handle = (HANDLE)::_beginthreadex(0, 0, reinterpret_cast<unsigned(__stdcall*)(void*)>(&impl::_m_thr_starter), pto, 0, 0);
|
||||||
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
|
#elif defined(NANA_POSIX)
|
||||||
pto->suspended = false;
|
pto->suspended = false;
|
||||||
::pthread_create(&(pto->handle), 0, reinterpret_cast<void*(*)(void*)>(&impl::_m_thr_starter), pto);
|
::pthread_create(&(pto->handle), 0, reinterpret_cast<void*(*)(void*)>(&impl::_m_thr_starter), pto);
|
||||||
#endif
|
#endif
|
||||||
@ -137,7 +137,7 @@ namespace threads
|
|||||||
#if defined(NANA_WINDOWS)
|
#if defined(NANA_WINDOWS)
|
||||||
::WaitForSingleObject(thr->handle, INFINITE);
|
::WaitForSingleObject(thr->handle, INFINITE);
|
||||||
::CloseHandle(thr->handle);
|
::CloseHandle(thr->handle);
|
||||||
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
|
#elif defined(NANA_POSIX)
|
||||||
::pthread_join(thr->handle, 0);
|
::pthread_join(thr->handle, 0);
|
||||||
::pthread_detach(thr->handle);
|
::pthread_detach(thr->handle);
|
||||||
#endif
|
#endif
|
||||||
@ -223,7 +223,7 @@ namespace threads
|
|||||||
pto->thr_state = state::idle;
|
pto->thr_state = state::idle;
|
||||||
#if defined(NANA_WINDOWS)
|
#if defined(NANA_WINDOWS)
|
||||||
::SuspendThread(pto->handle);
|
::SuspendThread(pto->handle);
|
||||||
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
|
#elif defined(NANA_POSIX)
|
||||||
std::unique_lock<std::mutex> lock(pto->wait_mutex);
|
std::unique_lock<std::mutex> lock(pto->wait_mutex);
|
||||||
pto->suspended = true;
|
pto->suspended = true;
|
||||||
pto->wait_cond.wait(lock);
|
pto->wait_cond.wait(lock);
|
||||||
@ -240,7 +240,7 @@ namespace threads
|
|||||||
if(n == 1 || n == static_cast<DWORD>(-1))
|
if(n == 1 || n == static_cast<DWORD>(-1))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
|
#elif defined(NANA_POSIX)
|
||||||
while(false == pto->suspended)
|
while(false == pto->suspended)
|
||||||
;
|
;
|
||||||
std::unique_lock<std::mutex> lock(pto->wait_mutex);
|
std::unique_lock<std::mutex> lock(pto->wait_mutex);
|
||||||
@ -327,7 +327,7 @@ namespace threads
|
|||||||
::_endthreadex(0);
|
::_endthreadex(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#elif defined(NANA_LINUX) || defined(NANA_MACOS)
|
#elif defined(NANA_POSIX)
|
||||||
static void * _m_thr_starter(pool_throbj * pto)
|
static void * _m_thr_starter(pool_throbj * pto)
|
||||||
{
|
{
|
||||||
pto->pool_ptr->_m_thr_runner(pto);
|
pto->pool_ptr->_m_thr_runner(pto);
|
||||||
@ -335,7 +335,7 @@ namespace threads
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
private:
|
private:
|
||||||
volatile bool runflag_;
|
std::atomic<bool> runflag_{ true };
|
||||||
std::recursive_mutex mutex_;
|
std::recursive_mutex mutex_;
|
||||||
|
|
||||||
struct signal
|
struct signal
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user