95 lines
2.3 KiB
C++
95 lines
2.3 KiB
C++
#include "assets/image_format.h"
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
|
|
namespace pp::assets {
|
|
|
|
namespace {
|
|
|
|
constexpr std::array png_signature {
|
|
std::byte { 0x89 },
|
|
std::byte { 0x50 },
|
|
std::byte { 0x4e },
|
|
std::byte { 0x47 },
|
|
std::byte { 0x0d },
|
|
std::byte { 0x0a },
|
|
std::byte { 0x1a },
|
|
std::byte { 0x0a },
|
|
};
|
|
|
|
[[nodiscard]] bool starts_with(std::span<const std::byte> bytes, std::span<const std::byte> prefix) noexcept
|
|
{
|
|
if (bytes.size() < prefix.size()) {
|
|
return false;
|
|
}
|
|
|
|
for (std::size_t i = 0; i < prefix.size(); ++i) {
|
|
if (bytes[i] != prefix[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
[[nodiscard]] bool is_prefix_of(std::span<const std::byte> bytes, std::span<const std::byte> signature) noexcept
|
|
{
|
|
if (bytes.size() >= signature.size()) {
|
|
return false;
|
|
}
|
|
|
|
for (std::size_t i = 0; i < bytes.size(); ++i) {
|
|
if (bytes[i] != signature[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
pp::foundation::Result<ImageFormat> detect_image_format(std::span<const std::byte> bytes) noexcept
|
|
{
|
|
if (bytes.empty()) {
|
|
return pp::foundation::Result<ImageFormat>::failure(
|
|
pp::foundation::Status::invalid_argument("image data must not be empty"));
|
|
}
|
|
|
|
if (starts_with(bytes, png_signature)) {
|
|
return pp::foundation::Result<ImageFormat>::success(ImageFormat::png);
|
|
}
|
|
|
|
if (is_prefix_of(bytes, png_signature)) {
|
|
return pp::foundation::Result<ImageFormat>::failure(
|
|
pp::foundation::Status::out_of_range("image data is a truncated PNG signature"));
|
|
}
|
|
|
|
if (bytes.size() < 3U) {
|
|
return pp::foundation::Result<ImageFormat>::failure(
|
|
pp::foundation::Status::out_of_range("image data is too short to identify"));
|
|
}
|
|
|
|
if (bytes[0] == std::byte { 0xff } && bytes[1] == std::byte { 0xd8 } && bytes[2] == std::byte { 0xff }) {
|
|
return pp::foundation::Result<ImageFormat>::success(ImageFormat::jpeg);
|
|
}
|
|
|
|
return pp::foundation::Result<ImageFormat>::failure(
|
|
pp::foundation::Status::invalid_argument("unsupported image signature"));
|
|
}
|
|
|
|
const char* image_format_name(ImageFormat format) noexcept
|
|
{
|
|
switch (format) {
|
|
case ImageFormat::png:
|
|
return "png";
|
|
case ImageFormat::jpeg:
|
|
return "jpeg";
|
|
}
|
|
|
|
return "unknown";
|
|
}
|
|
|
|
}
|