srctree

Robin Linden parent 0e0741c1 5d2bb9a9
img/qoi: Handle the end-of-stream marker

inlinesplit
img/qoi.cpp added: 33, removed: 11, total 22
@@ -163,6 +163,17 @@ tl::expected<Qoi, QoiError> Qoi::from(std::istream &is) {
seen_pixels[seen_pixels_index(previous_pixel)] = previous_pixel;
}
 
// The byte stream's end is marked with 7 0x00 bytes followed by a single
// 0x01 byte.
std::array<std::uint8_t, 8> footer{};
if (!is.read(reinterpret_cast<char *>(footer.data()), footer.size())) {
return tl::unexpected{QoiError::AbruptEof};
}
 
if (footer != decltype(footer){0, 0, 0, 0, 0, 0, 0, 1}) {
return tl::unexpected{QoiError::InvalidEndMarker};
}
 
return Qoi{
.width = width,
.height = height,
 
img/qoi.h added: 33, removed: 11, total 22
@@ -18,6 +18,7 @@ enum class QoiError {
InvalidMagic,
InvalidChannels,
InvalidColorspace,
InvalidEndMarker,
};
 
class Qoi {
 
img/qoi_test.cpp added: 33, removed: 11, total 22
@@ -60,35 +60,35 @@ int main() {
});
 
etest::test("QOI_OP_RGBA", [] {
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\1\0\0\0\1\3\1\xff\1\2\3\4"s}),
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\1\0\0\0\1\3\1\xff\1\2\3\4\0\0\0\0\0\0\0\1"s}),
img::Qoi{.width = 1, .height = 1, .bytes{1, 2, 3, 4}}); //
});
 
etest::test("QOI_OP_INDEX w/o any pixel values seen", [] {
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\1\0\0\0\1\3\1\0"s}),
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\1\0\0\0\1\3\1\0\0\0\0\0\0\0\0\1"s}),
Qoi{.width = 1, .height = 1, .bytes{0, 0, 0, 0}}); //
});
 
etest::test("QOI_OP_INDEX, write a pixel and read it back", [] {
// Carefully crafted pixel to have it end up in slot 0 in the seen pixels array.
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\2\0\0\0\1\3\1\xfe\1\x28\0\0"s}),
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\2\0\0\0\1\3\1\xfe\1\x28\0\0\0\0\0\0\0\0\0\1"s}),
Qoi{.width = 2, .height = 1, .bytes{1, 40, 0, 255, 1, 40, 0, 255}}); //
});
 
etest::test("QOI_OP_RUN", [] {
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\3\0\0\0\1\3\1\xc2"s}),
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\3\0\0\0\1\3\1\xc2\0\0\0\0\0\0\0\1"s}),
Qoi{.width = 3, .height = 1, .bytes{0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255}});
});
 
etest::test("QOI_OP_DIFF", [] {
// diff of {-2, -1, 1}, {1, 1, 1}
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\1\0\0\0\2\3\1\x47\x7f"s}),
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\1\0\0\0\2\3\1\x47\x7f\0\0\0\0\0\0\0\1"s}),
Qoi{.width = 1, .height = 2, .bytes{254, 255, 1, 255, 255, 0, 2, 255}});
});
 
etest::test("QOI_OP_LUMA", [] {
// diff of {-24, -16, -9}, {25, 18, 22}
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\2\0\0\0\1\3\1\x90\x0f\xb2\xfc"s}),
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\2\0\0\0\1\3\1\x90\x0f\xb2\xfc\0\0\0\0\0\0\0\1"s}),
Qoi{.width = 2, .height = 1, .bytes{232, 240, 247, 255, 1, 2, 13, 255}});
});
 
@@ -99,11 +99,21 @@ int main() {
});
 
etest::test("0x0 image", [] {
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\0\0\0\0\0\3\1"s}), Qoi{}); //
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\1"s}), Qoi{}); //
});
 
etest::test("missing footer", [] {
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\0\0\0\0\0\3\1"s}), //
tl::unexpected{QoiError::AbruptEof});
});
 
etest::test("invalid footer", [] {
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\2"s}),
tl::unexpected{QoiError::InvalidEndMarker});
});
 
etest::test("it works", [] {
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\1\0\0\0\2\3\1\xfe\1\2\3\xfe\6\5\4"s}),
expect_eq(Qoi::from(std::stringstream{"qoif\0\0\0\1\0\0\0\2\3\1\xfe\1\2\3\xfe\6\5\4\0\0\0\0\0\0\0\1"s}),
Qoi{.width = 1, .height = 2, .bytes{1, 2, 3, 255, 6, 5, 4, 255}});
});