-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathloadPng.cpp
More file actions
96 lines (84 loc) · 3.22 KB
/
loadPng.cpp
File metadata and controls
96 lines (84 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <ImageIO/loadPng.h>
#include <ImageIO/readBinaryFile.h>
#include <ImageIO/thirdparty/lodepng/lodepng.h>
#include <cstdlib>
#include <stdexcept>
namespace ImageIO_NS
{
namespace
{
using ::imageview::ContinuousImageView;
using ::imageview::PixelFormatGrayscale8;
using ::imageview::PixelFormatRGB24;
class LoadPngDeleter
{
public:
void operator()(unsigned char* pointer) const { std::free(pointer); }
};
struct PngData
{
std::unique_ptr<unsigned char[], LoadPngDeleter> data;
unsigned int height = 0;
unsigned int width = 0;
};
PngData loadPngData(const std::filesystem::path& path,
LodePNGColorType color_type,
unsigned int bit_depth)
{
const Blob compressed_file = readBinaryFile(path);
const std::span<const std::byte> compressed_data = compressed_file.data();
PngData result;
unsigned char* data_raw = nullptr;
const unsigned int status = lodepng_decode_memory(
&data_raw, &result.width, &result.height,
reinterpret_cast<const unsigned char*>(compressed_data.data()),
compressed_data.size(), color_type, bit_depth);
result.data.reset(std::exchange(data_raw, nullptr));
if (status != 0)
{
throw std::runtime_error(lodepng_error_text(status));
}
return result;
}
template <class PixelFormat>
class PngBitmap : public IBitmap<PixelFormat>
{
public:
explicit PngBitmap(unsigned int height,
unsigned int width,
std::unique_ptr<unsigned char[], LoadPngDeleter> data):
data_(std::move(data)),
height_(height),
width_(width)
{}
ContinuousImageView<PixelFormat> getView() const override
{
const std::size_t size_bytes = static_cast<std::size_t>(height_) * width_ *
PixelFormat::kBytesPerPixel;
const std::span<const std::byte> data(
reinterpret_cast<const std::byte*>(data_.get()), size_bytes);
return ContinuousImageView<PixelFormat>(height_, width_, data);
}
private:
std::unique_ptr<unsigned char[], LoadPngDeleter> data_;
unsigned int height_ = 0;
unsigned int width_ = 0;
};
}
std::unique_ptr<IBitmap<PixelFormatGrayscale8>> loadPngGrayscale8(const std::filesystem::path& path)
{
static_assert(PixelFormatGrayscale8::kBytesPerPixel == 1,
"This function loads an 8-bit grayscale image. "
"PixelFormatGrayscale8::kBytesPerPixel should equal 1.");
PngData png = loadPngData(path, LodePNGColorType::LCT_GREY, 8);
return std::make_unique<PngBitmap<PixelFormatGrayscale8>>(png.height, png.width, std::move(png.data));
}
std::unique_ptr<IBitmap<PixelFormatRGB24>> loadPngRGB24(const std::filesystem::path& path)
{
static_assert(PixelFormatRGB24::kBytesPerPixel == 3,
"This function loads a 24-bit RGB image. "
"PixelFormatRGB24::kBytesPerPixel should equal 3.");
PngData png = loadPngData(path, LodePNGColorType::LCT_RGB, 8);
return std::make_unique<PngBitmap<PixelFormatRGB24>>(png.height, png.width, std::move(png.data));
}
}