This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
#include "spdlog/fmt/bin_to_hex.h"
|
||||
|
||||
// as long as DRYRUN is defined, no data is actually send to the printer, we need to save some tape ;)
|
||||
//#define DRYRUN
|
||||
#define DRYRUN
|
||||
|
||||
namespace ptprnt::printer {
|
||||
|
||||
@@ -119,7 +119,7 @@ bool P700Printer::detachUsbDevice() {
|
||||
|
||||
bool P700Printer::printBitmap(const graphics::Bitmap<graphics::ALPHA8>& bitmap) {
|
||||
#ifdef DRYRUN
|
||||
SPDLOG_DEBUG("DRYRUN enabled");
|
||||
spdlog::debug("DRYRUN enabled");
|
||||
for (unsigned int lineNo = 0; lineNo < bitmap.getHeight(); lineNo++) {
|
||||
auto line = bitmap.getLine(lineNo);
|
||||
auto monoLine = graphics::Monochrome(*line);
|
||||
@@ -158,26 +158,6 @@ bool P700Printer::printBitmap(const graphics::Bitmap<graphics::ALPHA8>& bitmap)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool P700Printer::setText(const std::string& text) {
|
||||
return true;
|
||||
};
|
||||
|
||||
bool P700Printer::setFont(const std::string& text) {
|
||||
return true;
|
||||
};
|
||||
|
||||
bool P700Printer::setFontSize(uint8_t fontSize) {
|
||||
return true;
|
||||
};
|
||||
|
||||
bool P700Printer::setHAlign(HAlignPosition hpos) {
|
||||
return true;
|
||||
};
|
||||
|
||||
bool P700Printer::setVAlign(VAlignPosition vpos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool P700Printer::print() {
|
||||
send(p700::commands::LF);
|
||||
send(p700::commands::FF);
|
||||
@@ -201,7 +181,7 @@ bool P700Printer::send(const std::vector<uint8_t>& data) {
|
||||
}
|
||||
#else
|
||||
tx = data.size();
|
||||
spdlog::info("USB raw data(len {}): {}", data.size(), spdlog::to_hex(data));
|
||||
spdlog::trace("USB raw data(len {}): {}", data.size(), spdlog::to_hex(data));
|
||||
#endif
|
||||
|
||||
if (tx != static_cast<int>(data.size())) {
|
||||
|
@@ -44,6 +44,9 @@ const cmd_T PRINTER_INFO{0x81};
|
||||
|
||||
constexpr uint8_t MAX_TRIES_GET_STATUS = 10;
|
||||
|
||||
// TODO:
|
||||
// Remove Text-layout specific parts, add them to label
|
||||
|
||||
class P700Printer : public ::ptprnt::IPrinterDriver {
|
||||
public:
|
||||
P700Printer() = default;
|
||||
@@ -67,11 +70,6 @@ class P700Printer : public ::ptprnt::IPrinterDriver {
|
||||
[[nodiscard]] const PrinterStatus getPrinterStatus() override;
|
||||
bool attachUsbDevice(std::shared_ptr<libusbwrap::IUsbDevice> usbHndl) override;
|
||||
bool detachUsbDevice() override;
|
||||
bool setText(const std::string& text) override;
|
||||
bool setFont(const std::string& text) override;
|
||||
bool setFontSize(uint8_t fontSize) override;
|
||||
bool setHAlign(HAlignPosition hpos) override;
|
||||
bool setVAlign(VAlignPosition vpos) override;
|
||||
bool printBitmap(const graphics::Bitmap<graphics::ALPHA8>& bitmap) override;
|
||||
bool print() override;
|
||||
|
||||
|
@@ -16,12 +16,10 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include <cstdint>
|
||||
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
|
||||
#define SPDLOG_DEBUG_ON
|
||||
#define SPDLOG_TRACE_ON
|
||||
#include "PtouchPrint.hpp"
|
||||
|
||||
#include <CLI/App.hpp>
|
||||
#include <algorithm>
|
||||
#include <fmt/core.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/synchronous_factory.h>
|
||||
@@ -31,15 +29,16 @@
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "CLI/Option.hpp"
|
||||
#include "PrinterDriverFactory.hpp"
|
||||
#include "PtouchPrint.hpp"
|
||||
#include "graphics/Bitmap.hpp"
|
||||
#include "graphics/Label.hpp"
|
||||
#include "graphics/interface/ILabel.hpp"
|
||||
#include "libusbwrap/UsbDeviceFactory.hpp"
|
||||
|
||||
namespace ptprnt {
|
||||
@@ -98,37 +97,64 @@ int PtouchPrint::run() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (auto& cmd : mCommands) {
|
||||
switch (cmd.first) {
|
||||
auto label = graphics::Label();
|
||||
std::string labelText{};
|
||||
|
||||
for (const auto& [cmd, value] : mCommands) {
|
||||
switch (cmd) {
|
||||
case CliCmdType::Text:
|
||||
spdlog::debug("Setting text to {}", cmd.second);
|
||||
printer->setText(cmd.second);
|
||||
if (labelText.empty()) {
|
||||
labelText = value;
|
||||
} else {
|
||||
labelText = labelText + '\n' + value;
|
||||
}
|
||||
break;
|
||||
case CliCmdType::Font:;
|
||||
spdlog::debug("Setting font to {}", cmd.second);
|
||||
printer->setFont(cmd.second);
|
||||
case CliCmdType::Font:
|
||||
spdlog::debug("Setting font to {}", value);
|
||||
label.setFontFamily(value);
|
||||
break;
|
||||
case CliCmdType::FontSize:;
|
||||
spdlog::debug("Setting font size to {}", cmd.second);
|
||||
printer->setFontSize(static_cast<uint8_t>(std::atoi(cmd.second.c_str())));
|
||||
case CliCmdType::FontSize:
|
||||
spdlog::debug("Setting font size to {}", std::stod(value));
|
||||
label.setFontSize(std::stod(value));
|
||||
break;
|
||||
case CliCmdType::HAlign:;
|
||||
spdlog::debug("[Not implemented] Setting text horizontal alignment to {}", cmd.second);
|
||||
case CliCmdType::HAlign:
|
||||
spdlog::debug("Setting text horizontal alignment to {}", value);
|
||||
{
|
||||
auto hPos = HALignPositionMap.find(value);
|
||||
if (hPos == HALignPositionMap.end()) {
|
||||
spdlog::warn("Invalid horizontal alignment specified!");
|
||||
label.setHAlign(HAlignPosition::UNKNOWN);
|
||||
} else {
|
||||
label.setHAlign(hPos->second);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CliCmdType::VAlign:;
|
||||
spdlog::debug("[Not implemented] Setting text vertical alignment to {}", cmd.second);
|
||||
case CliCmdType::VAlign:
|
||||
spdlog::debug("Setting text vertical alignment to {}", value);
|
||||
{
|
||||
auto vPos = VALignPositionMap.find(value);
|
||||
if (vPos == VALignPositionMap.end()) {
|
||||
spdlog::warn("Invalid verical alignment specified!");
|
||||
label.setVAlign(VAlignPosition::UNKNOWN);
|
||||
} else {
|
||||
label.setVAlign(vPos->second);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CliCmdType::None:;
|
||||
case CliCmdType::None:
|
||||
[[fallthrough]];
|
||||
default:
|
||||
spdlog::warn("This command is currently not supported.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*if (!printer->print()) {
|
||||
if (!printer->print()) {
|
||||
spdlog::error("An error occured while printing");
|
||||
return -1;
|
||||
}*/
|
||||
}
|
||||
|
||||
label.create(labelText, 128);
|
||||
label.writeToPng("./testlabel.png");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -185,23 +211,39 @@ void PtouchPrint::setupCliParser() {
|
||||
->each([this](std::string text) { mCommands.emplace_back(CliCmdType::Text, text); });
|
||||
mApp.add_option("-f,--font", "Font used for the following text occurences")
|
||||
->group("Text printing ")
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeAll)
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeFirst)
|
||||
->trigger_on_parse()
|
||||
->each([this](std::string font) { mCommands.emplace_back(CliCmdType::Font, font); });
|
||||
mApp.add_option("-s,--fontsize", "Font size of the following text occurences")
|
||||
->group("Text printing ")
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeAll)
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeFirst)
|
||||
->trigger_on_parse()
|
||||
->each([this](std::string size) { mCommands.emplace_back(CliCmdType::FontSize, size); });
|
||||
mApp.add_option("--valign", "Vertical alignment of the following text occurences")
|
||||
->group("Text printing ")
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeAll)
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeFirst)
|
||||
->trigger_on_parse()
|
||||
->transform([](std::string in) -> std::string {
|
||||
std::unordered_set<std::string> validValignOptions{"top", "middle", "bottom"};
|
||||
std::transform(in.begin(), in.end(), in.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||
if (validValignOptions.find(in) == validValignOptions.end()) {
|
||||
return {""};
|
||||
}
|
||||
return in;
|
||||
})
|
||||
->each([this](std::string valign) { mCommands.emplace_back(CliCmdType::VAlign, valign); });
|
||||
mApp.add_option("--halign", "Vertical alignment of the following text occurences")
|
||||
->group("Text printing ")
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeAll)
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeFirst)
|
||||
->trigger_on_parse()
|
||||
->transform([](std::string in) -> std::string {
|
||||
std::unordered_set<std::string> validValignOptions{"left", "center", "right", "justify"};
|
||||
std::transform(in.begin(), in.end(), in.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||
if (validValignOptions.find(in) == validValignOptions.end()) {
|
||||
return {""};
|
||||
}
|
||||
return in;
|
||||
})
|
||||
->each([this](std::string halign) { mCommands.emplace_back(CliCmdType::HAlign, halign); });
|
||||
|
||||
// Image options
|
||||
|
@@ -24,23 +24,23 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iostream> // remove me
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cairo.h"
|
||||
#include "pango/pango-context.h"
|
||||
#include "graphics/interface/ILabel.hpp"
|
||||
#include "pango/pango-font.h"
|
||||
#include "pango/pango-fontmap.h"
|
||||
#include "pango/pango-layout.h"
|
||||
#include "pango/pango-types.h"
|
||||
#include "pango/pangocairo.h"
|
||||
|
||||
namespace ptprnt::graphics {
|
||||
Label::Label()
|
||||
: mPangoCtx(pango_font_map_create_context(pango_cairo_font_map_get_default())),
|
||||
: mCairoCtx(cairo_create(mSurface)),
|
||||
mPangoCtx(pango_cairo_create_context(mCairoCtx)),
|
||||
mPangoLyt(pango_layout_new(mPangoCtx)),
|
||||
mPangoFontDesc(pango_font_description_from_string("Noto sans 32")) {}
|
||||
mFontMap(pango_cairo_font_map_new()) {}
|
||||
|
||||
std::vector<uint8_t> Label::getRaw() {
|
||||
assert(mSurface != nullptr);
|
||||
@@ -63,29 +63,78 @@ int Label::getLayoutWidth() {
|
||||
return mLayoutWidth;
|
||||
}
|
||||
|
||||
void Label::create(const std::string& labelText, const uint16_t heightPixel) {
|
||||
bool Label::create(PrintableText printableText, const uint16_t heightPixel) {
|
||||
setFontFamily(printableText.fontFamily);
|
||||
setFontSize(printableText.fontSize);
|
||||
|
||||
return create(printableText.text, heightPixel);
|
||||
}
|
||||
|
||||
bool Label::create(const std::string& labelText, const uint16_t heightPixel) {
|
||||
mPrinterHeight = heightPixel;
|
||||
pango_layout_set_single_paragraph_mode(mPangoLyt, true);
|
||||
|
||||
// TODO: we need to create a custom fontconfig here so that Noto Emoji does not load the systems default
|
||||
// fontconfig here. For this, we need to create a PangoFcFontMap and a custom FcConfig
|
||||
// see: https://docs.gtk.org/PangoFc/method.FontMap.set_config.html
|
||||
// see: https://gist.github.com/CallumDev/7c66b3f9cf7a876ef75f
|
||||
PangoFontDescription* regularFont = pango_font_description_new();
|
||||
pango_font_description_set_size(regularFont, static_cast<int>(mFontSize * PANGO_SCALE));
|
||||
pango_font_description_set_family(regularFont, mFontFamily.c_str());
|
||||
//pango_layout_set_single_paragraph_mode(mPangoLyt, true); // this will force a single line in the label width width -1
|
||||
pango_layout_set_height(mPangoLyt, getNumLines(labelText) * -1);
|
||||
pango_layout_set_alignment(mPangoLyt, PANGO_ALIGN_CENTER);
|
||||
pango_layout_set_font_description(mPangoLyt, mPangoFontDesc);
|
||||
pango_context_load_font(mPangoCtx, mPangoFontDesc);
|
||||
pango_layout_set_font_description(mPangoLyt, regularFont);
|
||||
pango_layout_set_text(mPangoLyt, labelText.c_str(), static_cast<int>(labelText.length()));
|
||||
|
||||
pango_layout_get_size(mPangoLyt, &mLayoutWidth, &mLayoutHeight);
|
||||
// Set horizontal alignment
|
||||
switch (mHAlign) {
|
||||
case HAlignPosition::LEFT:
|
||||
pango_layout_set_alignment(mPangoLyt, PANGO_ALIGN_LEFT);
|
||||
break;
|
||||
case HAlignPosition::RIGHT:
|
||||
pango_layout_set_alignment(mPangoLyt, PANGO_ALIGN_RIGHT);
|
||||
break;
|
||||
case HAlignPosition::JUSTIFY:
|
||||
pango_layout_set_alignment(mPangoLyt, PANGO_ALIGN_LEFT); // not sure if needed
|
||||
pango_layout_set_justify(mPangoLyt, true);
|
||||
pango_layout_set_justify_last_line(mPangoLyt, true);
|
||||
break;
|
||||
case HAlignPosition::CENTER:
|
||||
[[fallthrough]];
|
||||
default:
|
||||
pango_layout_set_alignment(mPangoLyt, PANGO_ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
|
||||
// calculate label size for Cairo surface creation
|
||||
pango_layout_get_size(mPangoLyt, &mLayoutWidth, &mLayoutHeight);
|
||||
mLayoutWidth /= PANGO_SCALE;
|
||||
mLayoutHeight /= PANGO_SCALE;
|
||||
|
||||
SPDLOG_DEBUG("Layout width: {}, height: {}", mLayoutWidth, mLayoutHeight);
|
||||
|
||||
spdlog::debug("Layout width: {}, height: {}", mLayoutWidth, mLayoutHeight);
|
||||
mSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, mLayoutWidth, mPrinterHeight);
|
||||
cairo_t* cr = cairo_create(mSurface);
|
||||
|
||||
// Adjust Cairo cursor position to respect the vertical alignment
|
||||
switch (mVAlign) {
|
||||
case VAlignPosition::TOP:
|
||||
break;
|
||||
case VAlignPosition::BOTTOM:
|
||||
cairo_move_to(cr, 0.0, mPrinterHeight - mLayoutHeight);
|
||||
break;
|
||||
case VAlignPosition::MIDDLE:
|
||||
cairo_move_to(cr, 0.0, (mPrinterHeight - mLayoutHeight) / 2);
|
||||
[[fallthrough]];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Finally show the layout on the Cairo surface
|
||||
pango_cairo_show_layout(cr, mPangoLyt);
|
||||
|
||||
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
|
||||
cairo_surface_flush(mSurface);
|
||||
cairo_destroy(cr);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Label::writeToPng(const std::string& file) {
|
||||
@@ -95,11 +144,31 @@ void Label::writeToPng(const std::string& file) {
|
||||
}
|
||||
}
|
||||
|
||||
void Label::setFontSize(const double fontSize) {
|
||||
mFontSize = fontSize;
|
||||
}
|
||||
|
||||
void Label::setFontFamily(const std::string& fontFamily) {
|
||||
mFontFamily = fontFamily;
|
||||
}
|
||||
|
||||
void Label::setHAlign(HAlignPosition hAlign) {
|
||||
mHAlign = hAlign;
|
||||
}
|
||||
|
||||
void Label::setVAlign(VAlignPosition vAlign) {
|
||||
mVAlign = vAlign;
|
||||
}
|
||||
|
||||
void Label::setText(const std::string& text) {
|
||||
mText = text;
|
||||
}
|
||||
|
||||
Label::~Label() {
|
||||
SPDLOG_DEBUG("Image dtor...");
|
||||
pango_font_description_free(mPangoFontDesc);
|
||||
spdlog::debug("Image dtor...");
|
||||
g_object_unref(mPangoCtx);
|
||||
g_object_unref(mPangoLyt);
|
||||
g_object_unref(mFontMap);
|
||||
cairo_surface_destroy(mSurface);
|
||||
}
|
||||
} // namespace ptprnt::graphics
|
@@ -26,15 +26,12 @@
|
||||
#include <vector>
|
||||
|
||||
#include "cairo.h"
|
||||
#include "pango/pango-font.h"
|
||||
#include "graphics/interface/ILabel.hpp"
|
||||
#include "pango/pango-types.h"
|
||||
|
||||
namespace ptprnt::graphics {
|
||||
|
||||
constexpr const char* DEFAULT_FONT_FAMILY = "sans";
|
||||
constexpr const uint8_t DEFAULT_FONT_SIZE = 32;
|
||||
|
||||
class Label {
|
||||
class Label : public ILabel {
|
||||
public:
|
||||
Label();
|
||||
~Label();
|
||||
@@ -44,20 +41,35 @@ class Label {
|
||||
Label(Label&&) = delete;
|
||||
Label& operator=(Label&&) = delete;
|
||||
|
||||
std::vector<uint8_t> getRaw();
|
||||
void create(const std::string& labelText, const uint16_t heightPixel);
|
||||
bool create(PrintableText printableText, const uint16_t heightPixel) override;
|
||||
bool create(const std::string& labelText, const uint16_t heightPixel) override;
|
||||
void writeToPng(const std::string& file);
|
||||
int getLayoutWidth();
|
||||
int getLayoutHeight();
|
||||
[[nodiscard]] int getLayoutWidth() override;
|
||||
[[nodiscard]] int getLayoutHeight() override;
|
||||
[[nodiscard]] std::vector<uint8_t> getRaw() override;
|
||||
void setFontSize(const double fontSize) override;
|
||||
void setFontFamily(const std::string& fontFamily) override;
|
||||
|
||||
void setText(const std::string& text) override;
|
||||
void setHAlign(HAlignPosition hpos) override;
|
||||
void setVAlign(VAlignPosition vpos) override;
|
||||
|
||||
private:
|
||||
// methods
|
||||
uint8_t getNumLines(std::string_view str);
|
||||
[[nodiscard]] uint8_t getNumLines(std::string_view str);
|
||||
[[nodiscard]] PangoFontMap* createCustomFontMap();
|
||||
// members
|
||||
// TODO: convert raw pointers here into std::unique_ptr with custom deleters, calling g_object_unref()
|
||||
cairo_surface_t* mSurface{nullptr};
|
||||
cairo_t* mCairoCtx{nullptr};
|
||||
PangoContext* mPangoCtx{nullptr};
|
||||
PangoLayout* mPangoLyt{nullptr};
|
||||
PangoFontDescription* mPangoFontDesc{nullptr};
|
||||
cairo_surface_t* mSurface{nullptr};
|
||||
PangoFontMap* mFontMap{nullptr};
|
||||
double mFontSize{DEFAULT_FONT_SIZE};
|
||||
std::string mFontFamily{DEFAULT_FONT_FAMILY};
|
||||
HAlignPosition mHAlign = HAlignPosition::LEFT;
|
||||
VAlignPosition mVAlign = VAlignPosition::MIDDLE;
|
||||
std::string mText{""};
|
||||
int mLayoutWidth = 0, mLayoutHeight = 0;
|
||||
int mPrinterHeight = 0;
|
||||
};
|
||||
|
@@ -39,11 +39,6 @@ class IPrinterDriver {
|
||||
[[nodiscard]] virtual const PrinterStatus getPrinterStatus() = 0;
|
||||
virtual bool attachUsbDevice(std::shared_ptr<libusbwrap::IUsbDevice> usbHndl) = 0;
|
||||
virtual bool detachUsbDevice() = 0;
|
||||
virtual bool setText(const std::string& text) = 0;
|
||||
virtual bool setFont(const std::string& text) = 0;
|
||||
virtual bool setFontSize(uint8_t fontSize) = 0;
|
||||
virtual bool setHAlign(HAlignPosition hpos) = 0;
|
||||
virtual bool setVAlign(VAlignPosition vpos) = 0;
|
||||
virtual bool printBitmap(const graphics::Bitmap<graphics::ALPHA8>& bitmap) = 0;
|
||||
virtual bool print() = 0;
|
||||
};
|
||||
|
@@ -43,27 +43,4 @@ struct PrinterStatus {
|
||||
|
||||
using cmd_T = std::vector<uint8_t>;
|
||||
|
||||
enum class HAlignPosition {
|
||||
UNKNOWN = 0,
|
||||
LEFT = 1,
|
||||
CENTER = 2,
|
||||
RIGHT = 3,
|
||||
JUSTIFY = 4,
|
||||
};
|
||||
|
||||
enum class VAlignPosition {
|
||||
UNKNOWN = 0,
|
||||
TOP = 1,
|
||||
MIDDLE = 2,
|
||||
BOTTOM = 3,
|
||||
};
|
||||
|
||||
struct PrintableText {
|
||||
std::string text{""};
|
||||
std::string font{"Noto"};
|
||||
uint8_t fontSize{0};
|
||||
HAlignPosition hAlign{HAlignPosition::LEFT};
|
||||
VAlignPosition vAlign{VAlignPosition::MIDDLE};
|
||||
};
|
||||
|
||||
} // namespace ptprnt
|
Reference in New Issue
Block a user