• EncodingImage.cpp
  • #define CATCH_CONFIG_MAIN
    
    
    #include <catch.h>
    
    #include <Gorgon/Containers/Image.h>
    #include <Gorgon/Encoding/PNG.h>
    #include "Gorgon/Filesystem.h"
    #include "Gorgon/Encoding/JPEG.h"
    
    using namespace Gorgon;
    
    bool operator ==(const Containers::Image &im1, const Containers::Image &im2) {
    	if(im2.GetSize() != im1.GetSize() || im2.GetMode() != im1.GetMode())
    		return false;
    
    	for(int y=0; y<im1.GetSize().Height; y++) {
    		for(int x=0; x<im1.GetSize().Width; x++) {
    			for(unsigned c=0; c<im1.GetChannelsPerPixel(); c++)
    				if(im1({x,y}, c) != im2({x,y}, c))
    					return false;
    		}
    	}
    
    	return true;
    }
    
    bool similar(const Containers::Image &im1, const Containers::Image &im2, int maxdif=20) {
    	if(im2.GetSize() != im1.GetSize() || im2.GetMode() != im1.GetMode())
    		return false;
    
    	for(int y=0; y<im1.GetSize().Height; y++) {
    		for(int x=0; x<im1.GetSize().Width; x++) {
    			for(unsigned c=0; c<im1.GetChannelsPerPixel(); c++) {
    				auto v1 = im1({x,y}, c);
    				auto v2 = im2({x,y}, c);
    				if(abs(v1-v2)>maxdif)
    					return false;
    			}
    		}
    	}
    
    	return true;
    }
    
    TEST_CASE("PNG compression/decompression") {
    	Containers::Image im1({36, 36}, Graphics::ColorMode::RGBA);
    
    	int diff = 51;
    
    	for(int r=0; r<6; r++) {
    		for(int g=0; g<6; g++) {
    			for(int b=0; b<6; b++) {
    				for(int a=0; a<6; a++) {
    					im1({r + g*6, b + a*6}, 0) = r*diff;
    					im1({r + g*6, b + a*6}, 1) = g*diff;
    					im1({r + g*6, b + a*6}, 2) = b*diff;
    					im1({r + g*6, b + a*6}, 3) = a*diff;
    				}
    			}
    		}
    	}
    
    	Encoding::Png.Encode(im1, "out.png");
    
    	Containers::Image im2;
    
    	REQUIRE(Filesystem::IsFile("out.png"));
    	REQUIRE(Filesystem::Size("out.png") > 8);
    
    	Encoding::Png.Decode("out.png", im2);
    
    	REQUIRE(im2.GetSize() == im1.GetSize());
    	REQUIRE(im2.GetMode() == im1.GetMode());
    
    	REQUIRE(im1 == im2);
    
    	im1.Resize({36, 6}, Graphics::ColorMode::RGB);
    
    	for(int r=0; r<6; r++) {
    		for(int g=0; g<6; g++) {
    			for(int b=0; b<6; b++) {
    				im1({r + g*6, b}, 0) = r*diff;
    				im1({r + g*6, b}, 1) = g*diff;
    				im1({r + g*6, b}, 2) = b*diff;
    			}
    		}
    	}
    
    	std::ofstream outfile("out.png", std::ios::binary);
    	Encoding::Png.Encode(im1, outfile);
    	outfile.close();
    
    	std::ifstream infile("out.png", std::ios::binary);
    	Encoding::Png.Decode(infile, im2);
    
    	REQUIRE(im2.GetSize() == im1.GetSize());
    	REQUIRE(im2.GetMode() == im1.GetMode());
    
    	REQUIRE(im1 == im2);
    
    
    	im1.Resize({6, 6}, Graphics::ColorMode::Grayscale_Alpha);
    
    	for(int g=0; g<6; g++) {
    		for(int a=0; a<6; a++) {
    			im1({g, a}, 0) = g*diff;
    			im1({g, a}, 1) = a*diff;
    		}
    	}
    
    	Encoding::Png.Encode(im1, "outfile.png");
    
    	Encoding::Png.Decode("outfile.png", im2);
    
    	REQUIRE(im2.GetSize() == im1.GetSize());
    	REQUIRE(im2.GetMode() == im1.GetMode());
    
    	REQUIRE(im1 == im2);
    
    
    	im1.Resize({6, 1}, Graphics::ColorMode::Grayscale);
    
    	for(int g=0; g<6; g++) {
    		im1({g, 0}, 0) = g*diff;
    	}
    
    	std::vector<Byte> vec;
    	Encoding::Png.Encode(im1, vec);
    
    	Encoding::Png.Decode(vec, im2);
    
    	REQUIRE(im2.GetSize() == im1.GetSize());
    	REQUIRE(im2.GetMode() == im1.GetMode());
    
    	REQUIRE(im1 == im2);
    }
    
    TEST_CASE("JPEG compression/decompression") {
    	int diff = 5;
    	int mw   = 16;
    
    	Containers::Image im1({mw*mw, mw}, Graphics::ColorMode::RGB);
    
    	for(int r=0; r<mw; r++) {
    		for(int g=0; g<mw; g++) {
    			for(int b=0; b<mw; b++) {
    				im1({r + g*mw, b}, 0) = r*diff;
    				im1({r + g*mw, b}, 1) = g*diff;
    				im1({r + g*mw, b}, 2) = b*diff;
    			}
    		}
    	}
    
    	Encoding::Jpg.Encode(im1, "out.jpg");
    
    	Containers::Image im2;
    
    	REQUIRE(Filesystem::IsFile("out.jpg"));
    	REQUIRE(Filesystem::Size("out.jpg") > 8);
    
    	auto fsize = Filesystem::Size("out.jpg");
    
    	Encoding::Jpg.Decode("out.jpg", im2);
    
    	REQUIRE(im2.GetSize() == im1.GetSize());
    	REQUIRE(im2.GetMode() == im1.GetMode());
    
    	REQUIRE(similar(im1, im2));
    
    	im1.Resize({mw*mw, mw}, Graphics::ColorMode::RGB);
    
    	for(int r=0; r<mw; r++) {
    		for(int g=0; g<mw; g++) {
    			for(int b=0; b<mw; b++) {
    				im1({r + g*mw, b}, 0) = r*diff;
    				im1({r + g*mw, b}, 1) = g*diff;
    				im1({r + g*mw, b}, 2) = b*diff;
    			}
    		}
    	}
    
    	std::ofstream outfile("out.jpg", std::ios::binary);
    	Encoding::Jpg.Encode(im1, outfile, 40);
    	outfile.close();
    
    	REQUIRE(Filesystem::Size("out.jpg") < fsize);
    
    	std::ifstream infile("out.jpg", std::ios::binary);
    	Encoding::Jpg.Decode(infile, im2);
    
    	REQUIRE(im2.GetSize() == im1.GetSize());
    	REQUIRE(im2.GetMode() == im1.GetMode());
    
    	REQUIRE(similar(im1, im2, 30));
    
    
    	im1.Resize({mw, mw}, Graphics::ColorMode::Grayscale);
    
    	for(int y=0; y<mw; y++) {
    		for(int g=0; g<mw; g++) {
    			im1({g, y}, 0) = g*diff;
    		}
    	}
    
    	std::vector<Byte> vec;
    	Encoding::Jpg.Encode(im1, vec);
    
    	Encoding::Jpg.Decode(vec, im2);
    
    	REQUIRE(im2.GetSize() == im1.GetSize());
    	REQUIRE(im2.GetMode() == im1.GetMode());
    
    	REQUIRE(similar(im1, im2, 2));
    }