Add assets PNG metadata tests
This commit is contained in:
@@ -94,6 +94,7 @@ target_link_libraries(pp_foundation
|
||||
|
||||
add_library(pp_assets STATIC
|
||||
src/assets/image_format.cpp
|
||||
src/assets/image_metadata.cpp
|
||||
src/assets/ppi_header.cpp
|
||||
src/assets/settings_document.cpp)
|
||||
target_include_directories(pp_assets
|
||||
|
||||
@@ -86,9 +86,9 @@ Known local toolchain state:
|
||||
`platform-build` automation wrapper for `pp_foundation`, `pp_assets`,
|
||||
`pp_paint`, `pp_document`, `pp_renderer_api`, `pp_paint_renderer`,
|
||||
`pp_ui_core`, `pano_cli`, and their current headless test binaries,
|
||||
including foundation event/logging/task queue coverage, PPI header, settings
|
||||
document, paint brush/stroke coverage, UI color parsing, and layout XML
|
||||
parse coverage.
|
||||
including foundation event/logging/task queue coverage, PNG metadata, PPI
|
||||
header, settings document, paint brush/stroke coverage, UI color parsing, and
|
||||
layout XML parse coverage.
|
||||
- `panopainter_validate_shaders` validates the current combined GLSL shader
|
||||
files for one vertex stage marker, one fragment stage marker, valid marker
|
||||
order, and existing relative includes.
|
||||
|
||||
@@ -309,8 +309,9 @@ input. A synchronous event dispatcher, structured logging facade, bounded FIFO
|
||||
task queue, and deterministic `TraceRecorder` now record
|
||||
component/name/thread/frame/stroke metadata with filtering, capacity, and
|
||||
invalid-end tests. `pp_assets` has started with PNG/JPEG signature detection,
|
||||
PPI header recognition, and a pure typed settings document model, with
|
||||
corrupt/truncated/unsupported and key/value limit tests.
|
||||
PNG IHDR metadata parsing, PPI header recognition, and a pure typed settings
|
||||
document model, with corrupt/truncated/unsupported, extreme-dimension, and
|
||||
key/value limit tests.
|
||||
`pp_paint` has started with pure brush parameter validation/stamp evaluation,
|
||||
CPU reference math for the five current shader blend modes, and deterministic
|
||||
stroke spacing/interpolation. `pp_document` has
|
||||
@@ -528,7 +529,7 @@ Last verified on 2026-06-01:
|
||||
|
||||
```powershell
|
||||
cmake --preset windows-msvc-default
|
||||
cmake --build --preset windows-msvc-default --config Debug --target pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_document_tests pp_renderer_api_tests pp_paint_renderer_compositor_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests pano_cli PanoPainter
|
||||
cmake --build --preset windows-msvc-default --config Debug --target pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_assets_image_metadata_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_document_tests pp_renderer_api_tests pp_paint_renderer_compositor_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests pano_cli PanoPainter
|
||||
ctest --preset desktop-fast --build-config Debug
|
||||
powershell -ExecutionPolicy Bypass -File scripts\automation\test.ps1 -Preset desktop-fast -Configuration Debug
|
||||
powershell -ExecutionPolicy Bypass -File scripts\automation\build.ps1 -Preset windows-msvc-default -Configuration Debug -Target pano_cli
|
||||
@@ -552,6 +553,7 @@ Results:
|
||||
- `pp_foundation_task_queue_tests` passed.
|
||||
- `pp_foundation_trace_tests` passed.
|
||||
- `pp_assets_image_format_tests` passed.
|
||||
- `pp_assets_image_metadata_tests` passed.
|
||||
- `pp_assets_ppi_header_tests` passed.
|
||||
- `pp_assets_settings_document_tests` passed.
|
||||
- `pp_paint_brush_tests` passed.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string[]]$Presets = @("android-arm64"),
|
||||
[string[]]$Targets = @("pp_foundation", "pp_assets", "pp_paint", "pp_document", "pp_renderer_api", "pp_paint_renderer", "pp_ui_core", "pano_cli", "pp_foundation_binary_stream_tests", "pp_foundation_event_tests", "pp_foundation_log_tests", "pp_foundation_parse_tests", "pp_foundation_task_queue_tests", "pp_foundation_trace_tests", "pp_assets_image_format_tests", "pp_assets_ppi_header_tests", "pp_assets_settings_document_tests", "pp_paint_brush_tests", "pp_paint_blend_tests", "pp_paint_stroke_tests", "pp_document_tests", "pp_renderer_api_tests", "pp_paint_renderer_compositor_tests", "pp_ui_core_color_tests", "pp_ui_core_layout_value_tests", "pp_ui_core_layout_xml_tests")
|
||||
[string[]]$Targets = @("pp_foundation", "pp_assets", "pp_paint", "pp_document", "pp_renderer_api", "pp_paint_renderer", "pp_ui_core", "pano_cli", "pp_foundation_binary_stream_tests", "pp_foundation_event_tests", "pp_foundation_log_tests", "pp_foundation_parse_tests", "pp_foundation_task_queue_tests", "pp_foundation_trace_tests", "pp_assets_image_format_tests", "pp_assets_image_metadata_tests", "pp_assets_ppi_header_tests", "pp_assets_settings_document_tests", "pp_paint_brush_tests", "pp_paint_blend_tests", "pp_paint_stroke_tests", "pp_document_tests", "pp_renderer_api_tests", "pp_paint_renderer_compositor_tests", "pp_ui_core_color_tests", "pp_ui_core_layout_value_tests", "pp_ui_core_layout_xml_tests")
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
@@ -3,7 +3,7 @@ set -u
|
||||
|
||||
preset="${1:-android-arm64}"
|
||||
shift || true
|
||||
targets="${*:-pp_foundation pp_assets pp_paint pp_document pp_renderer_api pp_paint_renderer pp_ui_core pano_cli pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_document_tests pp_renderer_api_tests pp_paint_renderer_compositor_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests}"
|
||||
targets="${*:-pp_foundation pp_assets pp_paint pp_document pp_renderer_api pp_paint_renderer pp_ui_core pano_cli pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_assets_image_metadata_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_document_tests pp_renderer_api_tests pp_paint_renderer_compositor_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests}"
|
||||
start="$(date +%s)"
|
||||
|
||||
cmake --preset "$preset"
|
||||
|
||||
146
src/assets/image_metadata.cpp
Normal file
146
src/assets/image_metadata.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
#include "assets/image_metadata.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace pp::assets {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::byte 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 has_png_signature(std::span<const std::byte> bytes) noexcept
|
||||
{
|
||||
if (bytes.size() < 8U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < 8U; ++i) {
|
||||
if (bytes[i] != png_signature[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint32_t read_u32_be(std::span<const std::byte> bytes, std::size_t offset) noexcept
|
||||
{
|
||||
return (static_cast<std::uint32_t>(std::to_integer<std::uint8_t>(bytes[offset])) << 24U)
|
||||
| (static_cast<std::uint32_t>(std::to_integer<std::uint8_t>(bytes[offset + 1U])) << 16U)
|
||||
| (static_cast<std::uint32_t>(std::to_integer<std::uint8_t>(bytes[offset + 2U])) << 8U)
|
||||
| static_cast<std::uint32_t>(std::to_integer<std::uint8_t>(bytes[offset + 3U]));
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<ImageColorType> parse_png_color_type(std::byte value) noexcept
|
||||
{
|
||||
switch (std::to_integer<std::uint8_t>(value)) {
|
||||
case 0:
|
||||
return pp::foundation::Result<ImageColorType>::success(ImageColorType::grayscale);
|
||||
case 2:
|
||||
return pp::foundation::Result<ImageColorType>::success(ImageColorType::rgb);
|
||||
case 3:
|
||||
return pp::foundation::Result<ImageColorType>::success(ImageColorType::indexed);
|
||||
case 4:
|
||||
return pp::foundation::Result<ImageColorType>::success(ImageColorType::grayscale_alpha);
|
||||
case 6:
|
||||
return pp::foundation::Result<ImageColorType>::success(ImageColorType::rgba);
|
||||
default:
|
||||
return pp::foundation::Result<ImageColorType>::failure(
|
||||
pp::foundation::Status::invalid_argument("PNG color type is unsupported"));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint8_t component_count(ImageColorType color_type) noexcept
|
||||
{
|
||||
switch (color_type) {
|
||||
case ImageColorType::grayscale:
|
||||
case ImageColorType::indexed:
|
||||
return 1;
|
||||
case ImageColorType::grayscale_alpha:
|
||||
return 2;
|
||||
case ImageColorType::rgb:
|
||||
return 3;
|
||||
case ImageColorType::rgba:
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pp::foundation::Result<ImageMetadata> parse_png_metadata(std::span<const std::byte> bytes) noexcept
|
||||
{
|
||||
constexpr std::size_t png_ihdr_end = 33;
|
||||
if (bytes.size() < png_ihdr_end) {
|
||||
return pp::foundation::Result<ImageMetadata>::failure(
|
||||
pp::foundation::Status::out_of_range("PNG metadata is truncated"));
|
||||
}
|
||||
|
||||
if (!has_png_signature(bytes)) {
|
||||
return pp::foundation::Result<ImageMetadata>::failure(
|
||||
pp::foundation::Status::invalid_argument("PNG signature is invalid"));
|
||||
}
|
||||
|
||||
const auto ihdr_length = read_u32_be(bytes, 8);
|
||||
if (ihdr_length != 13U || bytes[12] != std::byte { 'I' } || bytes[13] != std::byte { 'H' }
|
||||
|| bytes[14] != std::byte { 'D' } || bytes[15] != std::byte { 'R' }) {
|
||||
return pp::foundation::Result<ImageMetadata>::failure(
|
||||
pp::foundation::Status::invalid_argument("PNG IHDR chunk is invalid"));
|
||||
}
|
||||
|
||||
const auto width = read_u32_be(bytes, 16);
|
||||
const auto height = read_u32_be(bytes, 20);
|
||||
if (width == 0 || height == 0 || width > max_image_dimension || height > max_image_dimension) {
|
||||
return pp::foundation::Result<ImageMetadata>::failure(
|
||||
pp::foundation::Status::out_of_range("PNG dimensions are outside the configured range"));
|
||||
}
|
||||
|
||||
const auto bit_depth = std::to_integer<std::uint8_t>(bytes[24]);
|
||||
if (bit_depth == 0U) {
|
||||
return pp::foundation::Result<ImageMetadata>::failure(
|
||||
pp::foundation::Status::invalid_argument("PNG bit depth is invalid"));
|
||||
}
|
||||
|
||||
const auto color_type = parse_png_color_type(bytes[25]);
|
||||
if (!color_type) {
|
||||
return pp::foundation::Result<ImageMetadata>::failure(color_type.status());
|
||||
}
|
||||
|
||||
return pp::foundation::Result<ImageMetadata>::success(ImageMetadata {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.bit_depth = bit_depth,
|
||||
.components = component_count(color_type.value()),
|
||||
.color_type = color_type.value(),
|
||||
});
|
||||
}
|
||||
|
||||
const char* image_color_type_name(ImageColorType color_type) noexcept
|
||||
{
|
||||
switch (color_type) {
|
||||
case ImageColorType::grayscale:
|
||||
return "grayscale";
|
||||
case ImageColorType::rgb:
|
||||
return "rgb";
|
||||
case ImageColorType::indexed:
|
||||
return "indexed";
|
||||
case ImageColorType::grayscale_alpha:
|
||||
return "grayscale_alpha";
|
||||
case ImageColorType::rgba:
|
||||
return "rgba";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
}
|
||||
34
src/assets/image_metadata.h
Normal file
34
src/assets/image_metadata.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "foundation/result.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
|
||||
namespace pp::assets {
|
||||
|
||||
constexpr std::uint32_t max_image_dimension = 262144;
|
||||
|
||||
enum class ImageColorType : std::uint8_t {
|
||||
grayscale,
|
||||
rgb,
|
||||
indexed,
|
||||
grayscale_alpha,
|
||||
rgba,
|
||||
};
|
||||
|
||||
struct ImageMetadata {
|
||||
std::uint32_t width = 0;
|
||||
std::uint32_t height = 0;
|
||||
std::uint8_t bit_depth = 0;
|
||||
std::uint8_t components = 0;
|
||||
ImageColorType color_type = ImageColorType::rgba;
|
||||
};
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<ImageMetadata> parse_png_metadata(
|
||||
std::span<const std::byte> bytes) noexcept;
|
||||
|
||||
[[nodiscard]] const char* image_color_type_name(ImageColorType color_type) noexcept;
|
||||
|
||||
}
|
||||
@@ -76,6 +76,16 @@ add_test(NAME pp_assets_image_format_tests COMMAND pp_assets_image_format_tests)
|
||||
set_tests_properties(pp_assets_image_format_tests PROPERTIES
|
||||
LABELS "assets;desktop-fast")
|
||||
|
||||
add_executable(pp_assets_image_metadata_tests
|
||||
assets/image_metadata_tests.cpp)
|
||||
target_link_libraries(pp_assets_image_metadata_tests PRIVATE
|
||||
pp_assets
|
||||
pp_test_harness)
|
||||
|
||||
add_test(NAME pp_assets_image_metadata_tests COMMAND pp_assets_image_metadata_tests)
|
||||
set_tests_properties(pp_assets_image_metadata_tests PROPERTIES
|
||||
LABELS "assets;desktop-fast")
|
||||
|
||||
add_executable(pp_assets_ppi_header_tests
|
||||
assets/ppi_header_tests.cpp)
|
||||
target_link_libraries(pp_assets_ppi_header_tests PRIVATE
|
||||
|
||||
113
tests/assets/image_metadata_tests.cpp
Normal file
113
tests/assets/image_metadata_tests.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "assets/image_metadata.h"
|
||||
#include "test_harness.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
|
||||
using pp::assets::ImageColorType;
|
||||
using pp::assets::image_color_type_name;
|
||||
using pp::assets::max_image_dimension;
|
||||
using pp::assets::parse_png_metadata;
|
||||
using pp::foundation::StatusCode;
|
||||
|
||||
namespace {
|
||||
|
||||
using PngHeader = std::array<std::byte, 33>;
|
||||
|
||||
PngHeader make_png_header(std::uint32_t width, std::uint32_t height, std::byte bit_depth, std::byte color_type)
|
||||
{
|
||||
PngHeader bytes {
|
||||
std::byte { 0x89 }, std::byte { 0x50 }, std::byte { 0x4e }, std::byte { 0x47 },
|
||||
std::byte { 0x0d }, std::byte { 0x0a }, std::byte { 0x1a }, std::byte { 0x0a },
|
||||
std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x0d },
|
||||
std::byte { 'I' }, std::byte { 'H' }, std::byte { 'D' }, std::byte { 'R' },
|
||||
std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 },
|
||||
std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 },
|
||||
bit_depth, color_type, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 },
|
||||
std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 },
|
||||
};
|
||||
|
||||
bytes[16] = static_cast<std::byte>((width >> 24U) & 0xffU);
|
||||
bytes[17] = static_cast<std::byte>((width >> 16U) & 0xffU);
|
||||
bytes[18] = static_cast<std::byte>((width >> 8U) & 0xffU);
|
||||
bytes[19] = static_cast<std::byte>(width & 0xffU);
|
||||
bytes[20] = static_cast<std::byte>((height >> 24U) & 0xffU);
|
||||
bytes[21] = static_cast<std::byte>((height >> 16U) & 0xffU);
|
||||
bytes[22] = static_cast<std::byte>((height >> 8U) & 0xffU);
|
||||
bytes[23] = static_cast<std::byte>(height & 0xffU);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void parses_png_ihdr_metadata(pp::tests::Harness& h)
|
||||
{
|
||||
const auto rgba = make_png_header(320, 240, std::byte { 8 }, std::byte { 6 });
|
||||
const auto rgb = make_png_header(17, 9, std::byte { 8 }, std::byte { 2 });
|
||||
|
||||
const auto rgba_result = parse_png_metadata(rgba);
|
||||
const auto rgb_result = parse_png_metadata(rgb);
|
||||
|
||||
PP_EXPECT(h, rgba_result.ok());
|
||||
PP_EXPECT(h, rgba_result.value().width == 320U);
|
||||
PP_EXPECT(h, rgba_result.value().height == 240U);
|
||||
PP_EXPECT(h, rgba_result.value().bit_depth == 8U);
|
||||
PP_EXPECT(h, rgba_result.value().components == 4U);
|
||||
PP_EXPECT(h, rgba_result.value().color_type == ImageColorType::rgba);
|
||||
PP_EXPECT(h, image_color_type_name(rgba_result.value().color_type) == std::string_view("rgba"));
|
||||
|
||||
PP_EXPECT(h, rgb_result.ok());
|
||||
PP_EXPECT(h, rgb_result.value().components == 3U);
|
||||
PP_EXPECT(h, rgb_result.value().color_type == ImageColorType::rgb);
|
||||
}
|
||||
|
||||
void maps_png_color_type_components(pp::tests::Harness& h)
|
||||
{
|
||||
const auto grayscale = parse_png_metadata(make_png_header(1, 1, std::byte { 8 }, std::byte { 0 }));
|
||||
const auto indexed = parse_png_metadata(make_png_header(1, 1, std::byte { 8 }, std::byte { 3 }));
|
||||
const auto gray_alpha = parse_png_metadata(make_png_header(1, 1, std::byte { 8 }, std::byte { 4 }));
|
||||
|
||||
PP_EXPECT(h, grayscale.ok());
|
||||
PP_EXPECT(h, grayscale.value().components == 1U);
|
||||
PP_EXPECT(h, grayscale.value().color_type == ImageColorType::grayscale);
|
||||
PP_EXPECT(h, indexed.ok());
|
||||
PP_EXPECT(h, indexed.value().components == 1U);
|
||||
PP_EXPECT(h, indexed.value().color_type == ImageColorType::indexed);
|
||||
PP_EXPECT(h, gray_alpha.ok());
|
||||
PP_EXPECT(h, gray_alpha.value().components == 2U);
|
||||
PP_EXPECT(h, gray_alpha.value().color_type == ImageColorType::grayscale_alpha);
|
||||
}
|
||||
|
||||
void rejects_corrupt_or_extreme_png_metadata(pp::tests::Harness& h)
|
||||
{
|
||||
const std::array<std::byte, 8> truncated {
|
||||
std::byte { 0x89 }, std::byte { 0x50 }, std::byte { 0x4e }, std::byte { 0x47 },
|
||||
std::byte { 0x0d }, std::byte { 0x0a }, std::byte { 0x1a }, std::byte { 0x0a },
|
||||
};
|
||||
auto bad_signature = make_png_header(1, 1, std::byte { 8 }, std::byte { 6 });
|
||||
bad_signature[0] = std::byte { 0x00 };
|
||||
auto bad_ihdr = make_png_header(1, 1, std::byte { 8 }, std::byte { 6 });
|
||||
bad_ihdr[15] = std::byte { 'X' };
|
||||
const auto zero_width = make_png_header(0, 1, std::byte { 8 }, std::byte { 6 });
|
||||
const auto too_large = make_png_header(max_image_dimension + 1U, 1, std::byte { 8 }, std::byte { 6 });
|
||||
const auto bad_depth = make_png_header(1, 1, std::byte { 0 }, std::byte { 6 });
|
||||
const auto bad_color = make_png_header(1, 1, std::byte { 8 }, std::byte { 5 });
|
||||
|
||||
PP_EXPECT(h, parse_png_metadata(truncated).status().code == StatusCode::out_of_range);
|
||||
PP_EXPECT(h, parse_png_metadata(bad_signature).status().code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, parse_png_metadata(bad_ihdr).status().code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, parse_png_metadata(zero_width).status().code == StatusCode::out_of_range);
|
||||
PP_EXPECT(h, parse_png_metadata(too_large).status().code == StatusCode::out_of_range);
|
||||
PP_EXPECT(h, parse_png_metadata(bad_depth).status().code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, parse_png_metadata(bad_color).status().code == StatusCode::invalid_argument);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pp::tests::Harness harness;
|
||||
harness.run("parses_png_ihdr_metadata", parses_png_ihdr_metadata);
|
||||
harness.run("maps_png_color_type_components", maps_png_color_type_components);
|
||||
harness.run("rejects_corrupt_or_extreme_png_metadata", rejects_corrupt_or_extreme_png_metadata);
|
||||
return harness.finish();
|
||||
}
|
||||
Reference in New Issue
Block a user