载入中...
搜索中...
未找到
SourcePng.cpp
浏览该文件的文档.
1#include "asset/SourcePng.h"
2#include <zlib.h>
3#include <algorithm>
4#include <limits>
5namespace eve::asset::detail {
7 std::span<const std::uint8_t> pixels, std::uint64_t maximumBytes) {
8 auto fail = [] {
10 Diagnostic::error(DiagnosticCode::InvalidArgument, "invalid PNG pixel dimensions or encoding budget", {},
11 {}, "asset.image.png"));
12 };
13 const std::uint64_t count = std::uint64_t(width) * height;
14 if (!width || !height || count > pixels.size() / 4 || count * 4 != pixels.size() ||
15 pixels.size() > std::numeric_limits<uLong>::max() - std::uint64_t(height))
16 return fail();
17 const std::uint64_t row = std::uint64_t(width) * 4, total = pixels.size() + std::uint64_t(height);
18 if (total > maximumBytes || total > std::numeric_limits<uLong>::max()) return fail();
19 uLongf bound = compressBound(static_cast<uLong>(total));
20 if (bound > maximumBytes || maximumBytes - bound < 57 || bound > UINT32_MAX - 4) return fail();
21 std::vector<std::uint8_t> scanlines;
22 scanlines.reserve(std::size_t(total));
23 for (std::size_t y = 0; y < height; ++y) {
24 scanlines.push_back(0);
25 scanlines.insert(scanlines.end(), pixels.begin() + y * row, pixels.begin() + (y + 1) * row);
26 }
27 std::vector<std::uint8_t> compressed(bound);
28 if (compress2(compressed.data(), &bound, scanlines.data(), static_cast<uLong>(total), 6) != Z_OK) return fail();
29 compressed.resize(bound);
30 std::vector<std::uint8_t> result{137, 80, 78, 71, 13, 10, 26, 10};
31 auto put = [](auto& out, std::uint32_t v) {
32 for (int shift = 24; shift >= 0; shift -= 8) out.push_back(std::uint8_t(v >> shift));
33 };
34 auto chunk = [&](const char* type, std::span<const std::uint8_t> payload) {
35 put(result, std::uint32_t(payload.size()));
36 const auto at = result.size();
37 result.insert(result.end(), type, type + 4);
38 result.insert(result.end(), payload.begin(), payload.end());
39 put(result, crc32(0, result.data() + at, static_cast<uInt>(payload.size() + 4)));
40 };
41 std::vector<std::uint8_t> header;
42 put(header, width);
43 put(header, height);
44 header.insert(header.end(), {8, 6, 0, 0, 0});
45 chunk("IHDR", header);
46 chunk("IDAT", compressed);
47 chunk("IEND", {});
48 return Result<std::vector<std::uint8_t>>::success(std::move(result));
49}
50} // namespace eve::asset::detail
Value::Object payload
float y
Definition AnimClip.cpp:738
float v
std::uint32_t height
std::uint32_t width
uint8_t * pixels
std::uint32_t count
std::size_t at
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
Result< std::vector< std::uint8_t > > encodeSourcePng(std::uint32_t width, std::uint32_t height, std::span< const std::uint8_t > pixels, std::uint64_t maximumBytes)
Encode top-down RGBA8 source pixels without transfer conversion.
Definition SourcePng.cpp:6