/* ptrnt - print labels on linux Copyright (C) 2023 Moritz Martinius This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE #define SPDLOG_DEBUG_ON #define SPDLOG_TRACE_ON #include #include #include #include #include #include #include #include #include #include #include #include #include "CLI/Option.hpp" #include "PrinterDriverFactory.hpp" #include "PtouchPrint.hpp" #include "graphics/Bitmap.hpp" #include "graphics/Label.hpp" #include "libusbwrap/UsbDeviceFactory.hpp" namespace ptprnt { PtouchPrint::PtouchPrint(const char* versionString) : mVersionString{versionString} {} int PtouchPrint::init(int argc, char** argv) { setupCliParser(); try { mApp.parse(argc, argv); } catch (const CLI::ParseError& e) { mApp.exit(e); return -1; } if (mVerboseFlag) { setupLogger(spdlog::level::debug); } else { setupLogger(spdlog::level::warn); } if (!mUsbDeviceFactory.init()) { spdlog::error("Could not initialize libusb"); return -1; } return 0; } int PtouchPrint::run() { spdlog::info("ptprnt version {}", mVersionString); SPDLOG_TRACE("testing trace"); mDetectedPrinters = getCompatiblePrinters(); auto numFoundPrinters = mDetectedPrinters.size(); if (numFoundPrinters == 0) { spdlog::error( "No compatible printers found, please make sure that they are turned on and connected"); return -1; } else if (numFoundPrinters > 1) { spdlog::warn("Found more than one compatible printer. Currently not supported."); return -1; } auto printer = mDetectedPrinters[0]; const auto printerUsbId = printer->getUsbId(); auto devices = mUsbDeviceFactory.findDevices(printerUsbId.first, printerUsbId.second); if (devices.size() != 1) { spdlog::warn( "Found more than one device of the same printer on bus. Currently not supported"); return -1; } printer->attachUsbDevice(std::move(devices[0])); auto status = printer->getPrinterStatus(); spdlog::info("Detected tape width is {}mm", status.tapeWidthMm); if (0 == mCommands.size()) { spdlog::warn("No command specified, nothing to do..."); return 0; } for (auto& cmd : mCommands) { switch (cmd.first) { case CliCmdType::Text: spdlog::debug("Setting text to {}", cmd.second); printer->setText(cmd.second); break; case CliCmdType::Font:; spdlog::debug("Setting font to {}", cmd.second); printer->setFont(cmd.second); break; case CliCmdType::FontSize:; spdlog::debug("Setting font size to {}", cmd.second); printer->setFontSize(static_cast(std::atoi(cmd.second.c_str()))); break; case CliCmdType::HAlign:; spdlog::debug("[Not implemented] Setting text horizontal alignment to {}", cmd.second); break; case CliCmdType::VAlign:; spdlog::debug("[Not implemented] Setting text vertical alignment to {}", cmd.second); break; case CliCmdType::None:; [[fallthrough]]; default: spdlog::warn("This command is currently not supported."); break; } } if (!printer->print()) { spdlog::error("An error occured while printing"); return -1; } return 0; } std::vector> PtouchPrint::getCompatiblePrinters() { auto usbDevs = mUsbDeviceFactory.findAllDevices(); auto driverFactory = std::make_unique(); std::vector> foundPrinterDrivers{}; for (auto usbDev : usbDevs) { auto driver = driverFactory->create(usbDev->getUsbId()); if (driver != nullptr) { foundPrinterDrivers.push_back(driver); } } return foundPrinterDrivers; } void PtouchPrint::setupLogger(spdlog::level::level_enum lvl) { auto consoleSink = std::make_shared(); consoleSink->set_level(lvl); if (spdlog::level::level_enum::debug == lvl || spdlog::level::level_enum::trace == lvl) { // This will enable file and line number for debug and trace macros consoleSink->set_pattern("%^%L:%$ %v (%s:%#)"); } else { consoleSink->set_pattern("%^%L:%$ %v"); } auto fileSink = std::make_shared("ptprnt.log", true); fileSink->set_level(spdlog::level::trace); fileSink->set_pattern("%Y-%m-%d %H:%m:%S:%e [pid:%P tid:%t] [%^%l%$] %v (%@)"); std::vector sinks{consoleSink, fileSink}; auto logger = std::make_shared("default_logger", sinks.begin(), sinks.end()); logger->set_level(spdlog::level::trace); spdlog::set_default_logger(logger); } void PtouchPrint::setupCliParser() { auto printVersion = [this](std::size_t) { fmt::print("ptprnt version: {}\n", mVersionString); }; // General options mApp.add_flag("-v,--verbose", mVerboseFlag, "Enable verbose output"); mApp.add_flag("-V,--version", printVersion, "Prints the ptprnt's version"); // Text printing options mApp.add_option("-t,--text", "Text to print (can be used multple times, use formatting options before to " "influence text layout)") ->group("Printing") ->multi_option_policy(CLI::MultiOptionPolicy::TakeAll) ->trigger_on_parse() ->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) ->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) ->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) ->trigger_on_parse() ->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) ->trigger_on_parse() ->each([this](std::string halign) { mCommands.emplace_back(CliCmdType::HAlign, halign); }); // Image options mApp.add_option("-i,--image", "Image to print. Excludes all text printing ") ->group("Image printing"); } } // namespace ptprnt