blob: 0cd87fa7698b1db71fc48bd9c0b8f2413418e788 [file] [log] [blame] [edit]
/**
* Copyright 2022 Rive Inc.
*/
#ifdef TESTING
#else
#include "imagediff_arguments.hpp"
#include "image_cmp.hpp"
#include "SkImage.h"
#include "SkData.h"
#include "SkPixmap.h"
#include "common/write_png_file.hpp"
#include <assert.h>
#include <string>
#include <stdio.h>
class WFile
{
FILE* m_File = nullptr;
bool m_DoClose;
public:
WFile(FILE* existingFile) : m_File(existingFile) { m_DoClose = false; }
WFile(const char path[], const char mode[]) : m_File(fopen(path, mode))
{
m_DoClose = true;
}
~WFile() { this->close(); }
bool isOpen() const { return m_File != nullptr; }
bool open(const char path[], const char mode[])
{
this->close();
m_File = fopen(path, mode);
return m_File != nullptr;
}
void close()
{
if (m_DoClose && m_File)
{
fclose(m_File);
}
m_File = nullptr;
}
void write(const void* data, size_t length)
{
assert(m_File);
fwrite(data, 1, length, m_File);
}
void write(const std::string& str) { this->write(str.c_str(), str.size()); }
void writeln(const std::string& str)
{
this->write(str);
this->write("\n");
}
};
static sk_sp<SkImage> file_to_image(const char path[])
{
auto data = SkData::MakeFromFileName(path);
if (!data)
{
return nullptr;
}
auto img = SkImage::MakeFromEncoded(data);
if (img)
{
img = img->makeRasterImage();
}
return img;
}
static void write_file(const char dir[],
const char name[],
const char suffix[],
sk_sp<SkImage> img)
{
auto path = std::string(dir) + std::string("/") + std::string(name) +
std::string(suffix);
SkColorInfo colorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
std::vector<uint8_t> pixels(img->height() * img->width() * 4);
img->readPixels(
nullptr,
SkPixmap(SkImageInfo::Make({img->width(), img->height()}, colorInfo),
pixels.data(),
img->width() * 4),
0,
0);
// printf("creating %s\n", path.c_str());
WritePNGFile(pixels.data(),
img->width(),
img->height(),
false,
path.c_str(),
PNGCompression::fast_rle);
}
void image_diff(const char name[],
const char pathA[],
const char pathB[],
const char statusPath[],
const char diffDir[])
{
WFile status =
statusPath && statusPath[0] ? WFile(statusPath, "a") : WFile(stdout);
if (!status.isOpen())
{
throw "failed to open status file";
}
status.write(std::string(name) + "\t");
auto imgA = file_to_image(pathA);
auto imgB = file_to_image(pathB);
if (!imgA || !imgB)
{
status.writeln("failed");
return;
}
const auto cmp = image_cmp(imgA, imgB);
if (!cmp.images_loaded)
{
status.writeln("failed");
return;
}
if (cmp.identical())
{
status.writeln("identical");
return;
}
if (!cmp.dimensions_equal)
{
status.writeln("sizemismatch");
return;
}
status.writeln(std::to_string(cmp.max_component_diff) + '\t' +
std::to_string(cmp.ave_component_diff) + '\t' +
std::to_string(cmp.pixel_diffcount) + '\t' +
std::to_string(imgA->height() * imgA->width()));
if (diffDir && diffDir[0])
{
auto diff0 = make_diff_image(imgA, imgB, compute_diff0);
auto diff1 = make_diff_image(imgA, imgB, compute_diff1);
write_file(diffDir, name, ".diff0.png", diff0);
write_file(diffDir, name, ".diff1.png", diff1);
}
}
int main(int argc, const char* argv[])
{
try
{
ImageDiffArguments args(argc, argv);
image_diff(args.name().c_str(),
args.golden().c_str(),
args.candidate().c_str(),
args.status().c_str(),
args.output().c_str());
}
catch (const args::Completion& e)
{
return 0;
}
catch (const args::Help&)
{
return 0;
}
catch (const args::ParseError& e)
{
return 1;
}
catch (args::ValidationError e)
{
return 1;
}
return 0;
}
#endif