Merge pull request #85 from enduro2d/hotfix/fix_image_noexcepts

Hotfix/fix image loading noexcept issues
This commit is contained in:
2019-07-27 05:20:10 +07:00
committed by GitHub
8 changed files with 147 additions and 112 deletions

View File

@@ -147,26 +147,16 @@ namespace e2d
switch ( format_ ) {
case image_data_format::g8:
E2D_ASSERT(bytes_per_pixel == 1);
return color32(pixel[0],
pixel[0],
pixel[0]);
return color32(pixel[0], pixel[0], pixel[0]);
case image_data_format::ga8:
E2D_ASSERT(bytes_per_pixel == 2);
return color32(pixel[0],
pixel[0],
pixel[0],
pixel[1]);
return color32(pixel[0], pixel[0], pixel[0], pixel[1]);
case image_data_format::rgb8:
E2D_ASSERT(bytes_per_pixel == 3);
return color32(pixel[0],
pixel[1],
pixel[2]);
return color32(pixel[0], pixel[1], pixel[2]);
case image_data_format::rgba8:
E2D_ASSERT(bytes_per_pixel == 4);
return color32(pixel[0],
pixel[1],
pixel[2],
pixel[3]);
return color32(pixel[0], pixel[1], pixel[2], pixel[3]);
default:
E2D_ASSERT_MSG(false, "unexpected image data format");
throw bad_image_access();
@@ -213,9 +203,13 @@ namespace e2d::images
image& dst,
const buffer& src) noexcept
{
return impl::try_load_image_dds(dst, src)
|| impl::try_load_image_pvr(dst, src)
|| impl::try_load_image_stb(dst, src);
try {
return impl::load_image_dds(dst, src)
|| impl::load_image_pvr(dst, src)
|| impl::load_image_stb(dst, src);
} catch (...) {
return false;
}
}
bool try_load_image(
@@ -232,20 +226,24 @@ namespace e2d::images
image_file_format format,
buffer& dst) noexcept
{
switch ( format ) {
case image_file_format::dds:
return impl::try_save_image_dds(src, dst);
case image_file_format::jpg:
return impl::try_save_image_jpg(src, dst);
case image_file_format::png:
return impl::try_save_image_png(src, dst);
case image_file_format::pvr:
return impl::try_save_image_pvr(src, dst);
case image_file_format::tga:
return impl::try_save_image_tga(src, dst);
default:
E2D_ASSERT_MSG(false, "unexpected image file format");
return false;
try {
switch ( format ) {
case image_file_format::dds:
return impl::save_image_dds(src, dst);
case image_file_format::jpg:
return impl::save_image_jpg(src, dst);
case image_file_format::png:
return impl::save_image_png(src, dst);
case image_file_format::pvr:
return impl::save_image_pvr(src, dst);
case image_file_format::tga:
return impl::save_image_tga(src, dst);
default:
E2D_ASSERT_MSG(false, "unexpected image file format");
return false;
}
} catch (...) {
return false;
}
}

View File

@@ -11,13 +11,13 @@
namespace e2d::images::impl
{
bool try_load_image_dds(image& dst, const buffer& src) noexcept;
bool try_load_image_pvr(image& dst, const buffer& src) noexcept;
bool try_load_image_stb(image& dst, const buffer& src) noexcept;
bool load_image_dds(image& dst, const buffer& src);
bool load_image_pvr(image& dst, const buffer& src);
bool load_image_stb(image& dst, const buffer& src);
bool try_save_image_dds(const image& src, buffer& dst) noexcept;
bool try_save_image_jpg(const image& src, buffer& dst) noexcept;
bool try_save_image_png(const image& src, buffer& dst) noexcept;
bool try_save_image_pvr(const image& src, buffer& dst) noexcept;
bool try_save_image_tga(const image& src, buffer& dst) noexcept;
bool save_image_dds(const image& src, buffer& dst);
bool save_image_jpg(const image& src, buffer& dst);
bool save_image_png(const image& src, buffer& dst);
bool save_image_pvr(const image& src, buffer& dst);
bool save_image_tga(const image& src, buffer& dst);
}

View File

@@ -116,7 +116,7 @@ namespace
namespace e2d::images::impl
{
bool try_load_image_dds(image& dst, const buffer& src) noexcept {
bool load_image_dds(image& dst, const buffer& src) {
if ( !is_dds(src.data(), src.size()) ) {
return false;
}
@@ -139,6 +139,7 @@ namespace e2d::images::impl
const v2u dimension = v2u(hdr.dwWidth, hdr.dwHeight);
std::size_t size;
switch ( format ) {
case image_data_format::rgb_dxt1:
case image_data_format::rgba_dxt3:

View File

@@ -108,7 +108,7 @@ namespace
static_assert(sizeof(pvr_header) == 52, "invalid PVR header size");
bool is_pvr(const void* data, std::size_t byte_size) {
bool is_pvr(const void* data, std::size_t byte_size) noexcept {
if ( byte_size > sizeof(pvr_header) ) {
const pvr_header* hdr = reinterpret_cast<const pvr_header*>(data);
return hdr->version == 0x03525650;
@@ -116,11 +116,17 @@ namespace
return false;
}
bool get_pvr_format(const pvr_header& hdr, image_data_format& out_format, u32& out_bytes_per_block, v2u& out_block_size) {
bool get_pvr_format(
const pvr_header& hdr,
image_data_format& out_format,
u32& out_bytes_per_block,
v2u& out_block_size) noexcept
{
if ( pvr_color_space(hdr.colorSpace) != pvr_color_space::linear ) {
return false;
}
const pvr_pixel_format fmt = pvr_pixel_format(hdr.pixelFormat0 | (u64(hdr.pixelFormat1) << 32));
const pvr_pixel_format fmt = pvr_pixel_format(
hdr.pixelFormat0 | (u64(hdr.pixelFormat1) << 32));
switch (fmt)
{
case pvr_pixel_format::pvrtc_2bpp_rgb:
@@ -197,25 +203,30 @@ namespace
namespace e2d::images::impl
{
bool try_load_image_pvr(image& dst, const buffer& src) noexcept {
bool load_image_pvr(image& dst, const buffer& src) {
if ( !is_pvr(src.data(), src.size()) ) {
return false;
}
const pvr_header& hdr = *reinterpret_cast<const pvr_header*>(src.data());
const u8* content = src.data() + sizeof(pvr_header) + hdr.metaDataSize;
if ( hdr.numSurfaces != 1 || hdr.numFaces != 1 || hdr.depth > 1 ) {
return false; // cubemap and volume textures are not supported
}
image_data_format format = image_data_format(-1);
u32 bytes_per_block = 0;
v2u block_size = v2u(1,1);
if ( !get_pvr_format(hdr, format, bytes_per_block, block_size) ) {
return false;
}
v2u dimension = v2u(hdr.width, hdr.height);
std::size_t size = bytes_per_block *
(dimension.x + block_size.x - 1) / block_size.x *
(dimension.y + block_size.y - 1) / block_size.y;
dst = image(dimension, format, buffer(content, size));
return true;
}

View File

@@ -57,33 +57,22 @@ namespace
return image_data_format::rgba8;
}
}
bool image_from_stb_description(
image& dst, const stbi_img_uptr& img, const v2u& img_size, u32 img_channels) noexcept
{
try {
const image_data_format img_format = image_format_from_stb_channels(img_channels);
if ( img && img_size.x > 0 && img_size.y > 0 ) {
buffer img_buffer(
img.get(),
math::numeric_cast<std::size_t>(img_size.x * img_size.y * img_channels));
dst.assign(img_size, img_format, std::move(img_buffer));
return true;
}
} catch (...) {
// nothing
}
return false;
}
}
namespace e2d::images::impl
{
bool try_load_image_stb(image& dst, const buffer& src) noexcept {
bool load_image_stb(image& dst, const buffer& src) {
v2u img_size;
u32 img_channels = 0;
const stbi_img_uptr img_ptr = load_stb_image(src, img_size, img_channels);
return img_ptr
&& image_from_stb_description(dst, img_ptr, img_size, img_channels);
if ( !img_ptr || !img_size.x || !img_size.y ) {
return false;
}
const image_data_format img_format = image_format_from_stb_channels(img_channels);
const std::size_t img_buffer_size = img_size.x * img_size.y * img_channels;
dst = image(img_size, img_format, buffer(img_ptr.get(), img_buffer_size));
return true;
}
}

View File

@@ -29,7 +29,7 @@ namespace
namespace e2d::images::impl
{
bool try_save_image_dds(const image& src, buffer& dst) noexcept {
bool save_image_dds(const image& src, buffer& dst) {
E2D_UNUSED(src, dst);
if ( is_save_image_dds_supported(src.format()) ) {
//TODO(BlackMat): implme

View File

@@ -35,7 +35,7 @@ namespace
namespace e2d::images::impl
{
bool try_save_image_pvr(const image& src, buffer& dst) noexcept {
bool save_image_pvr(const image& src, buffer& dst) {
E2D_UNUSED(src, dst);
if ( is_save_image_pvr_supported(src.format()) ) {
//TODO(BlackMat): implme

View File

@@ -21,6 +21,27 @@ namespace
{
using namespace e2d;
struct stb_write_context {
vector<u8> data;
std::exception_ptr exception{nullptr};
};
void stb_write_callback(void *context, void *data, int size) {
E2D_ASSERT(context && data && size > 0);
stb_write_context& ctx = *static_cast<stb_write_context*>(context);
if ( ctx.exception ) {
return;
}
try {
ctx.data.insert(
ctx.data.cend(),
reinterpret_cast<u8*>(data),
reinterpret_cast<u8*>(data) + math::numeric_cast<std::size_t>(size));
} catch (...) {
ctx.exception = std::current_exception();
}
}
int stb_channels_from_image_format(image_data_format format) noexcept {
switch ( format ) {
case image_data_format::g8: return 1;
@@ -30,70 +51,85 @@ namespace
default: return 0;
}
}
void stb_write_callback(void *context, void *data, int size) {
E2D_ASSERT(context && data && size > 0);
vector<u8>& ctx = *static_cast<vector<u8>*>(context);
ctx.insert(
ctx.cend(),
reinterpret_cast<u8*>(data),
reinterpret_cast<u8*>(data) + math::numeric_cast<std::size_t>(size));
}
}
namespace e2d::images::impl
{
bool try_save_image_jpg(const image& src, buffer& dst) noexcept {
bool save_image_jpg(const image& src, buffer& dst) {
int img_w = math::numeric_cast<int>(src.size().x);
int img_h = math::numeric_cast<int>(src.size().y);
int img_c = stb_channels_from_image_format(src.format());
try {
vector<u8> data;
if ( 0 != stbi_write_jpg_to_func(
stb_write_callback, &data, img_w, img_h, img_c, src.data().data(), 80) )
{
dst.assign(data.data(), data.size());
return true;
}
} catch (...) {
// nothing
const auto write_ctx = std::make_unique<stb_write_context>();
if ( !stbi_write_jpg_to_func(
stb_write_callback,
write_ctx.get(),
img_w,
img_h,
img_c,
src.data().data(),
80) )
{
return false;
}
return false;
if ( write_ctx->exception ) {
std::rethrow_exception(write_ctx->exception);
}
dst.assign(write_ctx->data.data(), write_ctx->data.size());
return true;
}
bool try_save_image_png(const image& src, buffer& dst) noexcept {
bool save_image_png(const image& src, buffer& dst) {
int img_w = math::numeric_cast<int>(src.size().x);
int img_h = math::numeric_cast<int>(src.size().y);
int img_c = stb_channels_from_image_format(src.format());
try {
vector<u8> data;
if ( 0 != stbi_write_png_to_func(
stb_write_callback, &data, img_w, img_h, img_c, src.data().data(), img_w * img_c) )
{
dst.assign(data.data(), data.size());
return true;
}
} catch (...) {
// nothing
const auto write_ctx = std::make_unique<stb_write_context>();
if ( !stbi_write_png_to_func(
stb_write_callback,
write_ctx.get(),
img_w,
img_h,
img_c,
src.data().data(),
img_w * img_c) )
{
return false;
}
return false;
if ( write_ctx->exception ) {
std::rethrow_exception(write_ctx->exception);
}
dst.assign(write_ctx->data.data(), write_ctx->data.size());
return true;
}
bool try_save_image_tga(const image& src, buffer& dst) noexcept {
bool save_image_tga(const image& src, buffer& dst) {
int img_w = math::numeric_cast<int>(src.size().x);
int img_h = math::numeric_cast<int>(src.size().y);
int img_c = stb_channels_from_image_format(src.format());
try {
vector<u8> data;
if ( 0 != stbi_write_tga_to_func(
stb_write_callback, &data, img_w, img_h, img_c, src.data().data()) )
{
dst.assign(data.data(), data.size());
return true;
}
} catch (...) {
// nothing
const auto write_ctx = std::make_unique<stb_write_context>();
vector<u8> data;
if ( !stbi_write_tga_to_func(
stb_write_callback,
write_ctx.get(),
img_w,
img_h,
img_c,
src.data().data()) )
{
return false;
}
return false;
if ( write_ctx->exception ) {
std::rethrow_exception(write_ctx->exception);
}
dst.assign(write_ctx->data.data(), write_ctx->data.size());
return true;
}
}