Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ca-png.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
43#ifndef CA_PNG_H
44#define CA_PNG_H
45
46#include <array>
47#include <concepts>
48#include <cstdint>
49#include <filesystem>
50#include <fstream>
51#include <ostream>
52#include <string>
53
54#include <ah-errors.H>
55#include <tpl_array.H>
56
57#include <ca-frame-stream.H>
58#include <ca-io.H>
59#include <tpl_ca_concepts.H>
60
61namespace Aleph {
62namespace CA {
63
64namespace ca_png_detail {
65
66inline void append_be32(Array<std::uint8_t> &out, const std::uint32_t value)
67{
68 out.append(static_cast<std::uint8_t>((value >> 24) & 0xffu));
69 out.append(static_cast<std::uint8_t>((value >> 16) & 0xffu));
70 out.append(static_cast<std::uint8_t>((value >> 8) & 0xffu));
71 out.append(static_cast<std::uint8_t>(value & 0xffu));
72}
73
74inline void write_be32(std::ostream &out, const std::uint32_t value)
75{
76 const char bytes[4]
77 = {static_cast<char>((value >> 24) & 0xffu), static_cast<char>((value >> 16) & 0xffu),
78 static_cast<char>((value >> 8) & 0xffu), static_cast<char>(value & 0xffu)};
79 out.write(bytes, 4);
80}
81
82[[nodiscard]] inline std::uint32_t crc32(const std::uint8_t *data, const std::size_t n)
83{
84 std::uint32_t crc = 0xffffffffu;
85 for (std::size_t i = 0; i < n; ++i)
86 {
87 crc ^= data[i];
88 for (int k = 0; k < 8; ++k)
89 crc = (crc & 1u) != 0 ? 0xedb88320u ^ (crc >> 1) : (crc >> 1);
90 }
91 return crc ^ 0xffffffffu;
92}
93
94[[nodiscard]] inline std::uint32_t adler32(const Array<std::uint8_t> &data)
95{
96 constexpr std::uint32_t mod = 65521u;
97 std::uint32_t a = 1;
98 std::uint32_t b = 0;
99 for (std::size_t i = 0; i < data.size(); ++i)
100 {
101 a = (a + data(i)) % mod;
102 b = (b + a) % mod;
103 }
104 return (b << 16) | a;
105}
106
108{
110 out.reserve(raw.size() + raw.size() / 65535 + 16);
111 out.append(std::uint8_t{0x78});
112 out.append(std::uint8_t{0x01});
113
114 std::size_t pos = 0;
115 do
116 {
117 const std::size_t remaining = raw.size() - pos;
118 const std::uint16_t block = static_cast<std::uint16_t>(remaining > 65535u ? 65535u : remaining);
119 const bool is_final = pos + block == raw.size();
120 out.append(static_cast<std::uint8_t>(is_final ? 0x01 : 0x00));
121 out.append(static_cast<std::uint8_t>(block & 0xffu));
122 out.append(static_cast<std::uint8_t>((block >> 8) & 0xffu));
123 const std::uint16_t nlen = static_cast<std::uint16_t>(~block);
124 out.append(static_cast<std::uint8_t>(nlen & 0xffu));
125 out.append(static_cast<std::uint8_t>((nlen >> 8) & 0xffu));
126 for (std::size_t i = 0; i < block; ++i)
127 out.append(raw(pos + i));
128 pos += block;
129 } while (pos < raw.size());
130
131 append_be32(out, adler32(raw));
132 return out;
133}
134
135inline void write_chunk(std::ostream &out, const char type[4], const Array<std::uint8_t> &payload)
136{
137 write_be32(out, static_cast<std::uint32_t>(payload.size()));
138 out.write(type, 4);
139 if (not payload.is_empty())
140 out.write(reinterpret_cast<const char *>(&payload.base()),
141 static_cast<std::streamsize>(payload.size()));
142
144 crc_data.reserve(4 + payload.size());
145 for (int i = 0; i < 4; ++i)
146 crc_data.append(static_cast<std::uint8_t>(type[i]));
147 for (std::size_t i = 0; i < payload.size(); ++i)
148 crc_data.append(payload(i));
149 write_be32(out, crc32(&crc_data.base(), crc_data.size()));
150}
151
152} // namespace ca_png_detail
153
170template <typename Lattice, typename Mapper>
171inline void write_png(std::ostream &out, const Lattice &frame, Mapper &&mapper)
172 requires requires(Mapper &&m, const typename Lattice::state_type &v) {
173 { m(v) } -> std::convertible_to<RGB8>;
174 }
175{
176 static_assert(LatticeLike<Lattice>, "write_png requires a LatticeLike frame");
177 static_assert(Lattice::rank == 2, "write_png requires a rank-2 frame");
178 using coord_t = typename Lattice::coord_type;
179
180 const ca_size_t rows = frame.size(0);
181 const ca_size_t cols = frame.size(1);
182 ah_domain_error_if(rows == 0 or cols == 0) << "write_png: PNG dimensions must be non-zero";
183
185 raw.reserve(rows * (1 + cols * 3));
186 for (ca_size_t r = 0; r < rows; ++r)
187 {
188 raw.append(std::uint8_t{0});
189 for (ca_size_t c = 0; c < cols; ++c)
190 {
191 const RGB8 rgb
192 = mapper(frame.at(coord_t{static_cast<ca_index_t>(r), static_cast<ca_index_t>(c)}));
193 raw.append(rgb.r);
194 raw.append(rgb.g);
195 raw.append(rgb.b);
196 }
197 }
198
199 static constexpr unsigned char signature[8] = {0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n'};
200 out.write(reinterpret_cast<const char *>(signature), 8);
201
203 ca_png_detail::append_be32(ihdr, static_cast<std::uint32_t>(cols));
204 ca_png_detail::append_be32(ihdr, static_cast<std::uint32_t>(rows));
205 ihdr.append(std::uint8_t{8}); // bit depth
206 ihdr.append(std::uint8_t{2}); // truecolour RGB
207 ihdr.append(std::uint8_t{0}); // deflate
208 ihdr.append(std::uint8_t{0}); // adaptive filtering
209 ihdr.append(std::uint8_t{0}); // no interlace
211
214 ca_png_detail::write_chunk(out, "IEND", {});
215
216 ah_runtime_error_if(not out) << "write_png: output stream failed";
217}
218
225template <typename Lattice>
226inline void write_png(std::ostream &out, const Lattice &frame)
227{
229}
230
239template <typename Mapper>
241{
242 std::filesystem::path pattern_;
244 std::size_t zero_pad_ = 6;
245
246public:
252 Png_Frame_Sink(std::filesystem::path path_pattern, Mapper mapper, const std::size_t zero_pad = 6)
253 : pattern_(std::move(path_pattern)), mapper_(std::move(mapper)), zero_pad_(zero_pad)
254 {}
255
261 template <typename Lattice>
262 void accept(const std::size_t step, const Lattice &frame)
263 {
264 const std::filesystem::path path = format_step_path(pattern_, step, zero_pad_);
265 if (const auto parent = path.parent_path(); not parent.empty())
266 std::filesystem::create_directories(parent);
267 std::ofstream out(path, std::ios::binary);
268 ah_runtime_error_if(not out) << "Png_Frame_Sink::accept: cannot open '" << path.string() << "'";
269 write_png(out, frame, mapper_);
270 }
271
273 static void flush() {}
274};
275
276template <typename Mapper>
277Png_Frame_Sink(std::filesystem::path, Mapper, std::size_t = 6) -> Png_Frame_Sink<Mapper>;
278
279} // namespace CA
280} // namespace Aleph
281
282#endif // CA_PNG_H
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:271
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
size_t * rows
Definition ca-c-api.h:112
size_t cols
Definition ca-c-api.h:105
Directory-backed frame sinks for CA trajectories.
File-format readers and writers for cellular-automata frames.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
constexpr bool is_empty() const noexcept
Checks if the container is empty.
Definition tpl_array.H:359
T & base()
Return a reference to the first element of array.
Definition tpl_array.H:326
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:250
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:320
Lattice that adds boundary-aware access on top of a storage.
typename Storage::state_type state_type
typename Storage::coord_type coord_type
static constexpr std::size_t rank
Path-pattern sink that writes one PNG file per accepted frame.
Definition ca-png.H:241
Png_Frame_Sink(std::filesystem::path path_pattern, Mapper mapper, const std::size_t zero_pad=6)
Build a PNG frame sink.
Definition ca-png.H:252
void accept(const std::size_t step, const Lattice &frame)
Write one PNG frame.
Definition ca-png.H:262
static void flush()
PNG frames are written eagerly; this is a no-op.
Definition ca-png.H:273
std::size_t zero_pad_
Definition ca-png.H:244
std::filesystem::path pattern_
Definition ca-png.H:242
constexpr size_t size() const noexcept
Returns the number of entries in the table.
Definition hashDry.H:619
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
void append_be32(Array< std::uint8_t > &out, const std::uint32_t value)
Definition ca-png.H:66
Array< std::uint8_t > zlib_store(const Array< std::uint8_t > &raw)
Definition ca-png.H:107
std::uint32_t crc32(const std::uint8_t *data, const std::size_t n)
Definition ca-png.H:82
void write_chunk(std::ostream &out, const char type[4], const Array< std::uint8_t > &payload)
Definition ca-png.H:135
std::uint32_t adler32(const Array< std::uint8_t > &data)
Definition ca-png.H:94
void write_be32(std::ostream &out, const std::uint32_t value)
Definition ca-png.H:74
std::filesystem::path format_step_path(const std::filesystem::path &pattern, const std::size_t step, const std::size_t zero_pad=6)
Format a step-indexed file path.
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Definition ca-traits.H:63
void write_png(std::ostream &out, const Lattice &frame, Mapper &&mapper)
Write a rank-2 frame as an 8-bit RGB PNG image.
Definition ca-png.H:171
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
STL namespace.
Default binary RGB mapper.
Definition ca-io.H:245
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
static int * k
gsl_rng * r
Dynamic array container with automatic resizing.
C++20 concepts for the Cellular Automata module.