From 8db95b445b2f1222c6a3f93f682217def650909c Mon Sep 17 00:00:00 2001 From: SirLynix Date: Tue, 26 Apr 2022 13:02:51 +0200 Subject: [PATCH] UnitTests: Add GIF decoding tests --- bin/resources/Tests/GIF/canvas_bgnd.gif | Bin 0 -> 1450 bytes bin/resources/Tests/GIF/canvas_prev.gif | Bin 0 -> 1450 bytes tests/Engine/Utility/ImageStreamLoading.cpp | 165 ++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 bin/resources/Tests/GIF/canvas_bgnd.gif create mode 100644 bin/resources/Tests/GIF/canvas_prev.gif create mode 100644 tests/Engine/Utility/ImageStreamLoading.cpp diff --git a/bin/resources/Tests/GIF/canvas_bgnd.gif b/bin/resources/Tests/GIF/canvas_bgnd.gif new file mode 100644 index 0000000000000000000000000000000000000000..d68504010fe1248b656d15ee84172da4ab402219 GIT binary patch literal 1450 zcmYk*dpOg390%~Drc~ z%-Iz$W>&3$+SY`PXz7U!Q~KtU``ig>i5p6lQFeuJ`lA3cRA6#wv@Ry}Ug$M`1ATit zD~#I=yMKnAT-&ZJ$YspM9QezeH({0VrMhWTk~4r(;`mLbmn?bo;qmVwo`~9zpG-_h zFKf7ius2&!c?XDt*JoVTN`+qabKVPR;>H7qxS>JZ zS{xAPF&dTCfl@IHhs)_=)g4RW!5?+iVYnG2kwPLedNL7qxD@Eh;S16V~VNT4n;G|)uo{&rKD(KfUe z&5lTEg%17+3-@h)ns#0%`3}8W((p5={-9c=B`3GFV=(@*3fXf&&VFT~(QzRP6)fET zh)dCtcQbSLk2NDJxuJ{_A_8rcY$Fq>#ZItzyh3mh9uXgN#UkFYFv5lvinWI+U{j2+ zF&bCT<|k+0tKfF%N-4J%mGwAd^Go`BesQHG5wj**d2fCnwEO!tB zJr0)uTdQAxJrI7$w%fWBHuHR}J~Nhxc%}y#B8v6l%w?%9R=S!9ZPa>3p_kRvNz3wn zwEV@UOA6j7*2yCkcG&?~RT+0GAVo?|Rgk-Fg*hQkjw4Vk&3?X$29tB+@HBLEmWONZ z%`lo4BBC&fUP7hBA_$3DH!JhXC}@WC9d>Cvvw%TpF)WE~z&A0ud94rH^Q$;r{_%IZ z%T*XO-f(?C;Xb9eu5(0_@oxD&v{WMYa+wbIzJ$Uu`8e$iC$@64D(%#%wcMK4$7WC zk>@27kloi$d%v1mH0D#a1;?;ytgSS6m5%8Br*obLI0_2*m|$G+?-w8)>slY^TG-%c zIuH$CW2DK8vFeQL2WtXt@k&!g16ScX` zCD&%;iQ^%nVu>V9n1jVBok%*ItR$R2 z0b&~r284y!lXkXobG5R-+Mo@PVjy8lU(^>31N(M!@@gNi$=xk)o6c^X?cR~2%-a<& zWmc_%+SUb)Xz9sKQ~K7E`<;{05;v48qwEUd^hW_?DBtAJSY1r$z0hmC2KvrUR#;~< z?EV>cQf<33KbJ8dbKoy??xa=xm+Gc1NzNcjiQ_kwUb5`bPawR9cp_>;eljshd0Epr z1bed$m3M$RczwoYtybt&Kj*%HCTyNz2ZcJCma!SbVU(R6Mg4A@%i;JOIIDZ)`P)RW z%5g)d*ZxTlT-gyvUU`rHkbB&`$2&68ikAFwRMu*{QT2pcwC6RKygx49PLZpqymF41 zHU&ayhrl6eiEaF-PsnL_FpgTQqqX1xGq_|Ogh!+u&90_G^k{DHmXDAv^pZM5OV?l{ zc3weR;lU@XpWHG_`1}QGxSY8U5TeQm*#LcUKnhS79l)M6)C96=$th=7QTxndD#SQuf$3dP#P6tKxg*cgqg zXY-S??^Sem=t?QK7M1lnWAjS}dVg`ZzA!TC;*&Kflj!(xvhRW-a(sqmT{$CTN#HNN z=B^5^c!bpmJQl^fmx6wULH~C!2hjgH2>&nK)^7;vEp^}GBDO1ZFbBG!{49460zCnj z09&hHe?1s}$+pM33pV?Fygn08LOj!h43otAaptnr7Asv%gf?m;qtMH0`lMy~09yWH z(@D4 z8h50AfOwzMSJySF$#^)%8{R)QMVQ9-r_CY8mLD(p4H^v1=lQn(#@uw1b((!y=(IA( z^hTyQrusrQbA74OFV-groU8rqnF?%UHyY@>&`1HNzhb5Q6Bm|fzxHu*@{F5D=LQ^p z^wRb(u02ckhD-WXb+C%6%jdl)Q#Fy{X0{ki{MxsyJ7sGrPBXgMAo`bUIP3C#Y z1Z4LQ(B7}57LEH|LL5k0gn6v9wrzU{QCt+$A;Dix)wJ0nGQt5 z*BEK?V!S%z`oWq&TY}PbQNfDqLg|D~Vck*pmx>ad#Tf?&SC)w@WrtP=B$^2oWy;8r YQ$z)6$IY&xF%zBPV@9vOxB`Ib-{1y@KmY&$ literal 0 HcmV?d00001 diff --git a/tests/Engine/Utility/ImageStreamLoading.cpp b/tests/Engine/Utility/ImageStreamLoading.cpp new file mode 100644 index 000000000..e3ab88ba3 --- /dev/null +++ b/tests/Engine/Utility/ImageStreamLoading.cpp @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include + +std::filesystem::path GetResourceDir(); + +void CompareFrames(const Nz::ImageStream& gif, std::vector& frameData, const Nz::Image& referenceImage) +{ + Nz::Vector2ui size = gif.GetSize(); + REQUIRE(referenceImage.GetSize() == Nz::Vector3ui(size, 1)); + REQUIRE(referenceImage.GetFormat() == gif.GetPixelFormat()); //< TODO: Convert? + + REQUIRE(frameData.size() == Nz::PixelFormatInfo::ComputeSize(gif.GetPixelFormat(), size.x, size.y, 1)); + REQUIRE(std::memcmp(frameData.data(), referenceImage.GetConstPixels(), frameData.size()) == 0); +} + +SCENARIO("Streamed images", "[Utility][ImageStream]") +{ + std::vector frameData; + + struct ExpectedFrame + { + std::shared_ptr referenceImage; + Nz::UInt64 time; + }; + + std::filesystem::path resourcePath = GetResourceDir(); + + WHEN("Loading GIF files") + { + GIVEN("canvas_bgnd.gif") + { + std::array expectedFrames = { + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_bgnd/0.png"), + 0 + }, + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_bgnd/1.png"), + 1000 + }, + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_bgnd/2.png"), + 2000 + }, + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_bgnd/3.png"), + 3000 + }, + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_bgnd/4.png"), + 4000 + } + }; + + std::shared_ptr gif = Nz::ImageStream::OpenFromFile(resourcePath / "Tests/GIF/canvas_bgnd.gif"); + REQUIRE(gif); + + Nz::Vector2ui size = gif->GetSize(); + CHECK(size == Nz::Vector2ui(100, 100)); + CHECK(gif->GetFrameCount() == expectedFrames.size()); + CHECK(gif->GetPixelFormat() == Nz::PixelFormat::RGBA8); + + frameData.resize(Nz::PixelFormatInfo::ComputeSize(gif->GetPixelFormat(), size.x, size.y, 1)); + + // Decode all frames in order + Nz::UInt64 frameTime; + for (ExpectedFrame& expectedFrame : expectedFrames) + { + REQUIRE(expectedFrame.referenceImage); + REQUIRE(gif->DecodeNextFrame(frameData.data(), &frameTime)); + + CHECK(frameTime == expectedFrame.time); + + CompareFrames(*gif, frameData, *expectedFrame.referenceImage); + } + + // Decoding the post-the-end frame fails but gives the end frametime + REQUIRE_FALSE(gif->DecodeNextFrame(frameData.data(), &frameTime)); + CHECK(frameTime == 5000); + + // Decode frames in arbitrary order, to ensure results are corrects + for (std::size_t frameIndex : { 2, 0, 3, 1, 4 }) + { + INFO("Decoding frame " << frameIndex); + + ExpectedFrame& expectedFrame = expectedFrames[frameIndex]; + gif->Seek(frameIndex); + + REQUIRE(gif->DecodeNextFrame(frameData.data(), &frameTime)); + CHECK(frameTime == expectedFrame.time); + + CompareFrames(*gif, frameData, *expectedFrame.referenceImage); + } + } + + GIVEN("canvas_prev.gif") + { + std::array expectedFrames = { + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_prev/0.png"), + 0 + }, + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_prev/1.png"), + 100 + }, + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_prev/2.png"), + 1100 + }, + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_prev/3.png"), + 2100 + }, + ExpectedFrame{ + Nz::Image::LoadFromFile(resourcePath / "Tests/GIF/canvas_prev/4.png"), + 3100 + } + }; + + std::shared_ptr gif = Nz::ImageStream::OpenFromFile(resourcePath / "Tests/GIF/canvas_prev.gif"); + REQUIRE(gif); + + Nz::Vector2ui size = gif->GetSize(); + CHECK(size == Nz::Vector2ui(100, 100)); + CHECK(gif->GetFrameCount() == expectedFrames.size()); + CHECK(gif->GetPixelFormat() == Nz::PixelFormat::RGBA8); + + frameData.resize(Nz::PixelFormatInfo::ComputeSize(gif->GetPixelFormat(), size.x, size.y, 1)); + + // Decode all frames in order + Nz::UInt64 frameTime; + for (ExpectedFrame& expectedFrame : expectedFrames) + { + REQUIRE(expectedFrame.referenceImage); + REQUIRE(gif->DecodeNextFrame(frameData.data(), &frameTime)); + + CHECK(frameTime == expectedFrame.time); + + CompareFrames(*gif, frameData, *expectedFrame.referenceImage); + } + + // Decoding the post-the-end frame fails but gives the end frametime + REQUIRE_FALSE(gif->DecodeNextFrame(frameData.data(), &frameTime)); + CHECK(frameTime == 4100); + + // Decode frames in arbitrary order, to ensure results are corrects + for (std::size_t frameIndex : { 2, 0, 3, 1, 4 }) + { + INFO("Decoding frame " << frameIndex); + + ExpectedFrame& expectedFrame = expectedFrames[frameIndex]; + gif->Seek(frameIndex); + + REQUIRE(gif->DecodeNextFrame(frameData.data(), &frameTime)); + CHECK(frameTime == expectedFrame.time); + + CompareFrames(*gif, frameData, *expectedFrame.referenceImage); + } + } + } +}