nana/source/paint/detail/image_jpeg.hpp

118 lines
2.8 KiB
C++

#ifndef NANA_PAINT_DETAIL_IMAGE_JPEG_HPP
#define NANA_PAINT_DETAIL_IMAGE_JPEG_HPP
#include "image_pixbuf.hpp"
//Separate the libpng from the package that system provides.
#if defined(NANA_LIBJPEG)
#include <nana_extrlib/jpeglib.h>
#else
#include <jpeglib.h>
#endif
#include <stdio.h>
#include <csetjmp>
namespace nana
{
namespace paint{ namespace detail{
class image_jpeg
: public basic_image_pixbuf
{
struct error_mgr
{
struct ::jpeg_error_mgr pub;
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:
bool open(const std::filesystem::path& jpeg_file) override
{
auto fp = ::fopen(to_osmbstr(to_utf8(jpeg_file.native())).c_str(), "rb");
if(nullptr == fp) return false;
bool is_opened = 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_stdio_src(&jdstru, fp);
_m_read_jpg(jdstru);
jpeg_finish_decompress(&jdstru);
is_opened = true;
}
::jpeg_destroy_decompress(&jdstru);
::fclose(fp);
return is_opened;
}
bool open(const void* data, std::size_t bytes) override
{
bool is_opened = 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)), static_cast<unsigned long>(bytes));
_m_read_jpg(jdstru);
jpeg_finish_decompress(&jdstru);
is_opened = true;
}
::jpeg_destroy_decompress(&jdstru);
return is_opened;
}
private:
static void _m_error_handler(::j_common_ptr jdstru)
{
auto err_ptr = reinterpret_cast<error_mgr*>(jdstru->err);
err_ptr->pub.output_message(jdstru);
longjmp(err_ptr->setjmp_buf, 1);
}
};
}//end namespace detail
}//end namespace paint
}//end namespace nana
#endif