diff --git a/meson.build b/meson.build index 98d36ca..939045b 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,7 @@ ptprnt_hpps = [ 'src/PtouchPrint.hpp', 'src/graphics/Bitmap.hpp', 'src/graphics/Image.hpp', + 'src/graphics/Monochrome.hpp' ] ptprnt_srcs = [ @@ -29,6 +30,7 @@ ptprnt_srcs = [ 'src/P700Printer.cpp', 'src/graphics/Image.cpp', 'src/graphics/Bitmap.cpp', + 'src/graphics/Monochrome.cpp', 'src/libusbwrap/UsbDeviceFactory.cpp', 'src/libusbwrap/UsbDevice.cpp', ] diff --git a/src/graphics/Monochrome.cpp b/src/graphics/Monochrome.cpp new file mode 100644 index 0000000..d8cae2c --- /dev/null +++ b/src/graphics/Monochrome.cpp @@ -0,0 +1,40 @@ +#include "graphics/Monochrome.hpp" + +#include + +#include +#include + +namespace ptprnt::graphics { +Monochrome::Monochrome(const std::vector& grayscale) : mPixels(std::move(grayscale)) {} + +void Monochrome::setThreshold(uint8_t threshhold) { + mThreshhold = threshhold; +} + +void Monochrome::invert(bool shouldInvert) { + mShouldInvert = shouldInvert; +} + +std::vector Monochrome::get() { + std::vector outPixels( + (static_cast((mPixels.size() / 8)) + (std::floor(mPixels.size() % 8 + 0.9)))); + + unsigned int outIndex = 0; + + for (unsigned int byteNum = 0; byteNum < mPixels.size(); byteNum += 8) { + for (unsigned int bitNo = 0; bitNo < 8; bitNo++) { + if (mPixels[byteNum + bitNo] > mThreshhold) { + outPixels[outIndex] |= (1 << (7 - bitNo)); + } else { + outPixels[outIndex] &= ~(1 << (7 - bitNo)); + } + } + if (mShouldInvert) { + outPixels[outIndex] = ~outPixels[outIndex]; + } + outIndex++; + } + return outPixels; +} +} // namespace ptprnt::graphics \ No newline at end of file diff --git a/src/graphics/Monochrome.hpp b/src/graphics/Monochrome.hpp new file mode 100644 index 0000000..8186abc --- /dev/null +++ b/src/graphics/Monochrome.hpp @@ -0,0 +1,20 @@ +#include + +#include "graphics/Bitmap.hpp" + +namespace ptprnt::graphics { +class Monochrome { + public: + Monochrome(const std::vector& grayscale); + ~Monochrome() = default; + + void setThreshold(uint8_t); + void invert(bool shouldInvert); + std::vector get(); + + private: + const std::vector& mPixels; + uint8_t mThreshhold = 127; + bool mShouldInvert = false; +}; +} // namespace ptprnt::graphics \ No newline at end of file diff --git a/tests/meson.build b/tests/meson.build index 43857e3..5bfd7a6 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,5 +1,6 @@ tests = [['bitmap_test', 'bitmap_test_exe', ['bitmap_test/bitmap_test.cpp']], - ['image_test', 'image_test_exe', ['image_test/image_test.cpp']] + ['image_test', 'image_test_exe', ['image_test/image_test.cpp']], + ['monochrome_test', 'monochrome_test_exe', ['monochrome_test/monochrome_test.cpp']] ] foreach test : tests diff --git a/tests/monochrome_test/monochrome_test.cpp b/tests/monochrome_test/monochrome_test.cpp new file mode 100644 index 0000000..e266aaf --- /dev/null +++ b/tests/monochrome_test/monochrome_test.cpp @@ -0,0 +1,49 @@ +#include "graphics/Monochrome.hpp" + +#include + +TEST(basic_test, Monochrome_convertGrayscale_yieldsMonochrome) { + const std::vector pixels({0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00}); + + const std::vector expected({0b10101010, 0b10101010}); + auto mono = ptprnt::graphics::Monochrome(pixels); + auto out = mono.get(); + + EXPECT_EQ(out, expected); +} + +TEST(basic_test, Monochrome_convertInvertedGrayscale_yieldsInvertedMonochrome) { + const std::vector pixels({0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00}); + + const std::vector expected({0b01010101, 0b01010101}); + auto mono = ptprnt::graphics::Monochrome(pixels); + mono.invert(true); + auto out = mono.get(); + + EXPECT_EQ(out, expected); +} + +TEST(basic_test, Monochrome_convertWithCustomThreshhold_yieldsMonochromeRespectingThreshhold) { + const std::vector pixels({0x0F, 0x11, 0x0F, 0x11, 0x0F, 0x11, 0x0F, 0x11, 0x0F, 0x11, + 0x0F, 0x11, 0x0F, 0x11, 0x0F, 0x11}); + + const std::vector expected({0b01010101, 0b01010101}); + auto mono = ptprnt::graphics::Monochrome(pixels); + mono.setThreshold(16); + auto out = mono.get(); + + EXPECT_EQ(out, expected); +} + +TEST(basic_test, Monochrome_convertNonAlignedPixels_spillsOverIntoNewByte) { + const std::vector pixels({0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF}); + + const std::vector expected({0b10101010, 0b10101010, 0b10000000}); + auto mono = ptprnt::graphics::Monochrome(pixels); + auto out = mono.get(); + + EXPECT_EQ(out, expected); +} \ No newline at end of file