From 00a1577c532df5bce9339636c8155692049e1237 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sun, 13 Aug 2017 08:44:49 -0700 Subject: [PATCH] Better color typing --- Makefile | 2 +- color.cc | 4 ++++ color.h | 12 +++++++++-- colorchecker.h | 41 +++++++++++++++--------------------- colors.h | 7 +++++-- image.h | 44 +++++++++++++++++++------------------- lut.h | 5 +++-- piraw.h | 57 ++++++++++++++++++++++---------------------------- 8 files changed, 87 insertions(+), 85 deletions(-) create mode 100644 color.cc diff --git a/Makefile b/Makefile index 1554d9c..3df9dc1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ all: piphoto -objects = piphoto.o lut.o util.o +objects = piphoto.o color.o lut.o util.o piphoto: $(objects) Makefile clang-3.9 -O3 -g -Weverything -Werror --std=c++1z --stdlib=libc++ -o piphoto $(objects) -lc++ -lunwind -lpng diff --git a/color.cc b/color.cc new file mode 100644 index 0000000..7d2aea5 --- /dev/null +++ b/color.cc @@ -0,0 +1,4 @@ +#include "color.h" + +RgbColor::RgbColor(const Color<3>& src) + : Color<3>(src) {} diff --git a/color.h b/color.h index 3aa949b..c0d874c 100644 --- a/color.h +++ b/color.h @@ -10,14 +10,22 @@ constexpr int32_t kMinColor = 0; constexpr int32_t kMaxColor = UINT16_MAX; +class ColorBase {}; + template -struct Color : public Array { +struct Color : public Array, public ColorBase { constexpr int32_t AbsDiff(const Color& other) const; constexpr Color Interpolate(const Color& other, int32_t mul, int32_t div) const; constexpr Color Crop() const; }; -struct RgbColor : public Color<3> {}; + +struct RgbColor : public Color<3> { + public: + RgbColor() = default; + RgbColor(const Color<3>& src); +}; + template constexpr int32_t Color::AbsDiff(const Color& other) const { diff --git a/colorchecker.h b/colorchecker.h index 79540e6..eec63ec 100644 --- a/colorchecker.h +++ b/colorchecker.h @@ -14,7 +14,9 @@ // Maximum LUT size that has each point adjacent to at least one ColorChecker color. typedef Lut3d<4, 3, 3> ColorCheckerLut3d; -constexpr Array kColorCheckerSrgb = {{{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wglobal-constructors" +const Array kColorCheckerSrgb = {{{ {{{{{0x7300, 0x5200, 0x4400}}}}}, {{{{{0xc200, 0x9600, 0x8200}}}}}, {{{{{0x6200, 0x7a00, 0x9d00}}}}}, @@ -40,11 +42,10 @@ constexpr Array kColorCheckerSrgb = {{{ {{{{{0x5500, 0x5500, 0x5500}}}}}, {{{{{0x3400, 0x3400, 0x3400}}}}}, }}}; +#pragma clang diagnostic pop -template -Array, kColorCheckerSrgb.size()> FindClosest(const Image& image) { - static_assert(C == 3); - +template +Array, kColorCheckerSrgb.size()> FindClosest(const Image& image) { Array, kColorCheckerSrgb.size()> closest; Array diff; diff.fill(INT32_MAX); @@ -68,10 +69,8 @@ Array, kColorCheckerSrgb.size()> FindClosest(const Image& imag return closest; } -template -int32_t ScoreLut(const Image& image, const LutBase& lut) { - static_assert(C == 3); - +template +int32_t ScoreLut(const Image& image, const LutBase& lut) { Array diff; diff.fill(INT32_MAX); @@ -93,11 +92,9 @@ int32_t ScoreLut(const Image& image, const LutBase& lut) { return std::accumulate(diff.begin(), diff.end(), 0); } -template -std::unique_ptr> HighlightClosest(const Image& image) { - static_assert(C == 3); - - auto out = std::make_unique>(image); +template +std::unique_ptr> HighlightClosest(const Image& image) { + auto out = std::make_unique>(image); auto closest = FindClosest(*out); for (int32_t cc = 0; cc < kColorCheckerSrgb.ssize(); ++cc) { @@ -112,10 +109,8 @@ std::unique_ptr> HighlightClosest(const Image& image) { return out; } -template -int32_t OptimizeLut(const Image& image, Lut3d* lut) { - static_assert(C == 3); - +template +int32_t OptimizeLut(const Image& image, Lut3d* lut) { auto snapshot = *lut; int32_t diff = 0; @@ -130,7 +125,7 @@ int32_t OptimizeLut(const Image& image, Lut3d{{{{x, y, z}}}} << std::endl; - for (int32_t c = 0; c < C; ++c) { + for (int32_t c = 0; c < color.size(); ++c) { auto& channel = color.at(c); auto min = FindPossibleMinimum( @@ -154,10 +149,8 @@ int32_t OptimizeLut(const Image& image, Lut3d -int32_t OptimizeLut(const Image& image, Lut1d* lut) { - static_assert(C == 3); - +template +int32_t OptimizeLut(const Image& image, Lut1d* lut) { auto snapshot = *lut; int32_t diff = 0; @@ -166,7 +159,7 @@ int32_t OptimizeLut(const Image& image, Lut1d* lut) { std::cout << Coord<1>{{{{x}}}} << std::endl; - for (int32_t c = 0; c < C; ++c) { + for (int32_t c = 0; c < color.ssize(); ++c) { auto& channel = color.at(c); auto min = FindPossibleMinimum( diff --git a/colors.h b/colors.h index 3c78ee5..9c77520 100644 --- a/colors.h +++ b/colors.h @@ -2,5 +2,8 @@ #include "color.h" -constexpr RgbColor kBlack = {{{{{0x0000, 0x0000, 0x0000}}}}}; -constexpr RgbColor kWhite = {{{{{0xffff, 0xffff, 0xffff}}}}}; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wglobal-constructors" +const RgbColor kBlack = {{{{{0x0000, 0x0000, 0x0000}}}}}; +const RgbColor kWhite = {{{{{0xffff, 0xffff, 0xffff}}}}}; +#pragma clang diagnostic pop diff --git a/image.h b/image.h index 234f392..cfec073 100644 --- a/image.h +++ b/image.h @@ -9,57 +9,57 @@ #include "color.h" #include "coord.h" -template -class Image : public Array, X>, Y> { +template +class Image : public Array, Y> { public: - constexpr const Color& GetPixel(const Coord<2>& coord) const; + constexpr const C& GetPixel(const Coord<2>& coord) const; - void SetPixel(const Coord<2>& coord, const Color& color); - void DrawXLine(const Coord<2>& start, const Color& color, int32_t length); - void DrawYLine(const Coord<2>& start, const Color& color, int32_t length); - void DrawRectangle(const Coord<2>& start, const Color& color, int32_t x_length, int32_t y_length); - void DrawSquare(const Coord<2>& start, const Color& color, int32_t length); + void SetPixel(const Coord<2>& coord, const C& color); + void DrawXLine(const Coord<2>& start, const C& color, int32_t length); + void DrawYLine(const Coord<2>& start, const C& color, int32_t length); + void DrawRectangle(const Coord<2>& start, const C& color, int32_t x_length, int32_t y_length); + void DrawSquare(const Coord<2>& start, const C& color, int32_t length); std::string ToPng(); }; -template -constexpr const Color& Image::GetPixel(const Coord<2>& coord) const { +template +constexpr const C& Image::GetPixel(const Coord<2>& coord) const { return this->at(coord.at(1)).at(coord.at(0)); } -template -void Image::SetPixel(const Coord<2>& coord, const Color& color) { +template +void Image::SetPixel(const Coord<2>& coord, const C& color) { if (coord.at(0) >= X || coord.at(1) >= Y) { return; } this->at(coord.at(1)).at(coord.at(0)) = color; } -template -void Image::DrawXLine(const Coord<2>& coord, const Color& color, int32_t length) { +template +void Image::DrawXLine(const Coord<2>& coord, const C& color, int32_t length) { for (int32_t x = coord.at(0); x <= coord.at(0) + length; ++x) { SetPixel({{{{x, coord.at(1)}}}}, color); } } -template -void Image::DrawYLine(const Coord<2>& coord, const Color& color, int32_t length) { +template +void Image::DrawYLine(const Coord<2>& coord, const C& color, int32_t length) { for (int32_t y = coord.at(1); y <= coord.at(1) + length; ++y) { SetPixel({{{{coord.at(0), y}}}}, color); } } -template -void Image::DrawRectangle(const Coord<2>& start, const Color& color, int32_t x_length, int32_t y_length) { +template +void Image::DrawRectangle(const Coord<2>& start, const C& color, int32_t x_length, int32_t y_length) { DrawXLine(start, color, x_length); DrawXLine({{{{start.at(0), start.at(1) + y_length}}}}, color, x_length); DrawYLine(start, color, y_length); DrawYLine({{{{start.at(0) + x_length, start.at(1)}}}}, color, y_length); } -template -void Image::DrawSquare(const Coord<2>& start, const Color& color, int32_t length) { +template +void Image::DrawSquare(const Coord<2>& start, const C& color, int32_t length) { DrawRectangle(start, color, length, length); } @@ -68,9 +68,9 @@ static inline void WriteCallback(png_structp png_ptr, png_bytep data, png_size_t dest->append(reinterpret_cast(data), length); } -template +template std::string Image::ToPng() { - static_assert(C == 3); // PNG only supports RGB + // TODO: specialize this to RgbColor std::string ret; diff --git a/lut.h b/lut.h index 7fb49b8..f80a66e 100644 --- a/lut.h +++ b/lut.h @@ -11,9 +11,10 @@ class LutBase { LutBase(const LutBase&) = default; virtual ~LutBase(); + // TODO: Allow other color dimensions virtual Color<3> MapColor(const Color<3>& in) const = 0; - template + template std::unique_ptr> MapImage(const Image& in) const; protected: @@ -21,7 +22,7 @@ class LutBase { static constexpr int32_t BlockSize(int32_t points); }; -template +template std::unique_ptr> LutBase::MapImage(const Image& in) const { auto out = std::make_unique>(); diff --git a/piraw.h b/piraw.h index aa3a353..d3b0ba4 100644 --- a/piraw.h +++ b/piraw.h @@ -10,15 +10,15 @@ namespace std { using string_view = experimental::string_view; } -template +template class PiRaw { public: PiRaw() = delete; PiRaw(const PiRaw&) = delete; PiRaw(PiRaw&&) = delete; - static std::unique_ptr> FromJpeg(const std::string_view& jpeg); - static std::unique_ptr> FromRaw(const std::string_view& raw); + static std::unique_ptr> FromJpeg(const std::string_view& jpeg); + static std::unique_ptr> FromRaw(const std::string_view& raw); private: static constexpr int32_t kJpegHeaderBytes = 32768; @@ -36,30 +36,27 @@ class PiRaw { typedef Array Chunk; static constexpr Chunk GetChunk(const std::string_view& raw, const int32_t x_chunk, const int32_t y); - static constexpr Color CombineRaw(int32_t y0x0, int32_t y0x1, int32_t y1x0, int32_t y1x1); + static constexpr RgbColor CombineRaw(int32_t y0x0, int32_t y0x1, int32_t y1x0, int32_t y1x1); }; -typedef PiRaw<3280, 2464, 3, 10, 16, 2> PiRaw2; - -template -typename std::unique_ptr> PiRaw::FromJpeg(const std::string_view& jpeg) { - static_assert(C == 3); +typedef PiRaw<3280, 2464, 10, 16, 2> PiRaw2; +template +typename std::unique_ptr> PiRaw::FromJpeg(const std::string_view& jpeg) { size_t container_len = GetRawBytes() + kJpegHeaderBytes; assert(jpeg.substr(jpeg.size() - container_len, 4) == kJpegHeaderMagic); return FromRaw(jpeg.substr(jpeg.size() - GetRawBytes(), GetRawBytes())); } -template -typename std::unique_ptr> PiRaw::FromRaw(const std::string_view& raw) { - static_assert(C == 3); +template +typename std::unique_ptr> PiRaw::FromRaw(const std::string_view& raw) { static_assert(X % 2 == 0); static_assert(Y % 2 == 0); static_assert(kPixelsPerChunk == 4); assert(raw.size() == GetRawBytes()); - auto image = std::make_unique>(); + auto image = std::make_unique>(); for (int32_t y = 0, out_y = 0; y < Y; y += 2, ++out_y) { for (int32_t x_chunk = 0, out_x = 0; x_chunk < X / kPixelsPerChunk; ++x_chunk, out_x += kPixelsPerChunk / 2) { @@ -72,35 +69,34 @@ typename std::unique_ptr> PiRaw::FromRa return image; } -template -constexpr int32_t PiRaw::GetRawBytes() { +template +constexpr int32_t PiRaw::GetRawBytes() { return GetRowBytes() * GetNumRows(); } -template -constexpr int32_t PiRaw::GetRowBytes() { +template +constexpr int32_t PiRaw::GetRowBytes() { return Align(Align(X + P) * D / kBitsPerByte); } -template -constexpr int32_t PiRaw::GetNumRows() { +template +constexpr int32_t PiRaw::GetNumRows() { return Align(Y + P); } -template -constexpr int32_t PiRaw::GetChunkBytes() { +template +constexpr int32_t PiRaw::GetChunkBytes() { return D * kPixelsPerChunk / kBitsPerByte; } -template -constexpr int32_t PiRaw::Align(int32_t val) { +template +constexpr int32_t PiRaw::Align(int32_t val) { return (~(A - 1)) & ((val) + (A - 1)); } -template -constexpr typename PiRaw::Chunk PiRaw::GetChunk(const std::string_view& raw, const int32_t x_chunk, const int32_t y) { +template +constexpr typename PiRaw::Chunk PiRaw::GetChunk(const std::string_view& raw, const int32_t x_chunk, const int32_t y) { // Function is bit depth & layout specific - static_assert(C == 3); static_assert(D == 10); size_t start = static_cast(y * GetRowBytes() + x_chunk * GetChunkBytes()); @@ -118,12 +114,9 @@ constexpr typename PiRaw::Chunk PiRaw::GetCh return ret; } -template -constexpr Color PiRaw::CombineRaw(int32_t y0x0, int32_t y0x1, int32_t y1x0, int32_t y1x1) { - // Function is bit layout specific - static_assert(C == 3); - - Color ret; +template +constexpr RgbColor PiRaw::CombineRaw(int32_t y0x0, int32_t y0x1, int32_t y1x0, int32_t y1x1) { + RgbColor ret; ret.at(0) = static_cast(y1x1); ret.at(1) = static_cast((y0x1 + y1x0) / 2); ret.at(2) = static_cast(y0x0);