mirror of
https://github.com/matrix-construct/construct
synced 2024-12-25 23:14:13 +01:00
ircd::png: Elaborate callback surface; add logger to prevent libpng writes to stderr.
This commit is contained in:
parent
1d6325949d
commit
66639ee119
2 changed files with 118 additions and 37 deletions
|
@ -14,6 +14,8 @@
|
|||
/// Portable Network Graphics; wrappers a la carte
|
||||
namespace ircd::png
|
||||
{
|
||||
IRCD_EXCEPTION(ircd::error, error)
|
||||
|
||||
bool is_animated(const const_buffer &);
|
||||
|
||||
extern const info::versions version_api, version_abi;
|
||||
|
|
153
ircd/png.cc
153
ircd/png.cc
|
@ -10,6 +10,23 @@
|
|||
|
||||
#include <RB_INC_PNG_H
|
||||
|
||||
namespace ircd::png
|
||||
{
|
||||
static void handle_error(png_structp, const char *) noexcept(false);
|
||||
static void handle_warn(png_structp, const char *) noexcept;
|
||||
static void *handle_alloc(png_structp, size_t) noexcept;
|
||||
static void handle_free(png_structp, void *) noexcept;
|
||||
static void handle_read(png_structp, uint8_t *, size_t) noexcept;
|
||||
|
||||
extern log::log log;
|
||||
}
|
||||
|
||||
decltype(ircd::png::log)
|
||||
ircd::png::log
|
||||
{
|
||||
"png"
|
||||
};
|
||||
|
||||
decltype(ircd::png::version_api)
|
||||
ircd::png::version_api
|
||||
{
|
||||
|
@ -43,7 +60,20 @@ ircd::png::is_animated(const const_buffer &buf)
|
|||
return false;
|
||||
|
||||
png_infop info {nullptr};
|
||||
png_structp handle {nullptr};
|
||||
png_structp handle
|
||||
{
|
||||
png_create_read_struct_2
|
||||
(
|
||||
PNG_LIBPNG_VER_STRING,
|
||||
nullptr,
|
||||
&handle_error,
|
||||
&handle_warn,
|
||||
nullptr,
|
||||
&handle_alloc,
|
||||
&handle_free
|
||||
)
|
||||
};
|
||||
|
||||
const unwind destroy
|
||||
{
|
||||
[&handle, &info]
|
||||
|
@ -52,52 +82,21 @@ ircd::png::is_animated(const const_buffer &buf)
|
|||
}
|
||||
};
|
||||
|
||||
if(unlikely(!(handle = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr))))
|
||||
if(unlikely(!handle))
|
||||
return false;
|
||||
|
||||
if(unlikely(!(info = png_create_info_struct(handle))))
|
||||
return false;
|
||||
|
||||
const_buffer src{buf};
|
||||
png_set_read_fn(handle, &src, []
|
||||
(auto handle, uint8_t *const ptr, size_t sz)
|
||||
{
|
||||
// Destination where libpng wants data
|
||||
const mutable_buffer dst
|
||||
{
|
||||
reinterpret_cast<char *>(ptr), sz
|
||||
};
|
||||
|
||||
// Get source buffer from our callback user data.
|
||||
const_buffer &src
|
||||
{
|
||||
*reinterpret_cast<const_buffer *>(png_get_io_ptr(handle))
|
||||
};
|
||||
|
||||
// Copy from our buffer to libpng buffer.
|
||||
const size_t copied
|
||||
{
|
||||
copy(dst, src)
|
||||
};
|
||||
|
||||
// Advance our source pointer for the amount copied.
|
||||
const size_t consumed
|
||||
{
|
||||
consume(src, copied)
|
||||
};
|
||||
|
||||
assert(copied == consumed);
|
||||
});
|
||||
const_buffer src {buf};
|
||||
png_set_read_fn(handle, &src, &handle_read);
|
||||
|
||||
// Invokes the read callback a few times to traverse the buffer.
|
||||
png_read_info(handle, info);
|
||||
|
||||
// If there's a non-zero result there's acTL for animation.
|
||||
uint32_t frames(0), plays(0);
|
||||
if(png_get_acTL(handle, info, &frames, &plays) != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
uint32_t num_frames {0}, num_plays {0};
|
||||
return png_get_acTL(handle, info, &num_frames, &num_plays) != 0;
|
||||
}
|
||||
#else
|
||||
{
|
||||
|
@ -107,3 +106,83 @@ ircd::png::is_animated(const const_buffer &buf)
|
|||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ircd::png::handle_read(png_structp handle,
|
||||
uint8_t *const ptr,
|
||||
size_t size)
|
||||
noexcept
|
||||
{
|
||||
// Destination where libpng wants data
|
||||
const mutable_buffer dst
|
||||
{
|
||||
reinterpret_cast<char *>(ptr), size
|
||||
};
|
||||
|
||||
// Get source buffer from our callback user data.
|
||||
const_buffer &src
|
||||
{
|
||||
*reinterpret_cast<const_buffer *>(png_get_io_ptr(handle))
|
||||
};
|
||||
|
||||
// Copy from our buffer to libpng buffer.
|
||||
const size_t copied
|
||||
{
|
||||
copy(dst, src)
|
||||
};
|
||||
|
||||
// Advance our source pointer for the amount copied.
|
||||
const size_t consumed
|
||||
{
|
||||
consume(src, copied)
|
||||
};
|
||||
|
||||
assert(copied == consumed);
|
||||
}
|
||||
|
||||
void *
|
||||
ircd::png::handle_alloc(png_structp handle,
|
||||
size_t size)
|
||||
noexcept
|
||||
{
|
||||
return std::malloc(size);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::png::handle_free(png_structp handle,
|
||||
void *const ptr)
|
||||
noexcept
|
||||
{
|
||||
std::free(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::png::handle_warn(png_structp handle,
|
||||
const char *const msg)
|
||||
noexcept
|
||||
{
|
||||
log::dwarning
|
||||
{
|
||||
log, "handle(%p) :%s",
|
||||
static_cast<const void *>(handle),
|
||||
msg,
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
ircd::png::handle_error(png_structp handle,
|
||||
const char *const msg)
|
||||
noexcept(false)
|
||||
{
|
||||
log::error
|
||||
{
|
||||
log, "handle(%p) :%s",
|
||||
static_cast<const void *>(handle),
|
||||
msg,
|
||||
};
|
||||
|
||||
throw error
|
||||
{
|
||||
"%s", msg
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue