/**
 * @file barcode_bindings_pybind.cpp
 * @brief pybind11 bindings for Barcode library
 *
 * This file provides Python bindings for the C++ barcode library using pybind11.
 * Supports 19 barcode types including 1D, 2D, and special barcodes.
 */

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

// 1D barcodes (12 types)
#include "code39.h"
#include "code93.h"
#include "code128.h"
#include "gs1_128.h"
#include "nw7.h"
#include "itf.h"
#include "Matrix2of5.h"
#include "NEC2of5.h"
#include "jan8.h"
#include "jan13.h"
#include "upc_a.h"
#include "upc_e.h"

// GS1 DataBar (3 types)
#include "gs1_databar_14.h"
#include "gs1_databar_limited.h"
#include "gs1_databar_expanded.h"

// Yubin Customer Barcode
#include "YubinCustomer.h"

// 2D barcodes (3 types)
#include "DataMatrix.h"
#include "QR.h"
#include "PDF417.h"

// License info
#include "ProductInfo.h"
#include "barcode_base.h"

#include <string>
#include <vector>

namespace py = pybind11;

// =============================================================================
// Code39
// =============================================================================
class Code39Wrapper {
private:
    Code39* barcode;

public:
    Code39Wrapper() {
        barcode = new Code39("png");
    }

    ~Code39Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    void setShowStartStop(bool show) {
        barcode->ShowStartStop = show;
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// Code93
// =============================================================================
class Code93Wrapper {
private:
    Code93* barcode;

public:
    Code93Wrapper() {
        barcode = new Code93("png");
    }

    ~Code93Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// Code128
// =============================================================================
class Code128Wrapper {
private:
    Code128* barcode;

public:
    Code128Wrapper() {
        barcode = new Code128("png");
    }

    ~Code128Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    void setCodeMode(const std::string& mode) {
        if (mode == "AUTO") {
            barcode->CodeMode = CodeSet128::AUTO;
        }
        else if (mode == "A") {
            barcode->CodeMode = CodeSet128::CODE_A;
        }
        else if (mode == "B") {
            barcode->CodeMode = CodeSet128::CODE_B;
        }
        else if (mode == "C") {
            barcode->CodeMode = CodeSet128::CODE_C;
        }
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// GS1_128
// =============================================================================
class GS1_128Wrapper {
private:
    GS1_128* barcode;

public:
    GS1_128Wrapper() {
        barcode = new GS1_128("png");
    }

    ~GS1_128Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }

    std::string drawConvenience(const std::string& code, int width, int height) {
        if (barcode->DrawConvenience(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawConvenienceBytes(const std::string& code, int width, int height) {
        if (barcode->DrawConvenience(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }
};

// =============================================================================
// NW7
// =============================================================================
class NW7Wrapper {
private:
    NW7* barcode;

public:
    NW7Wrapper() {
        barcode = new NW7("png");
    }

    ~NW7Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    void setShowStartStop(bool show) {
        barcode->ShowStartStop = show;
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// ITF
// =============================================================================
class ITFWrapper {
private:
    ITF* barcode;

public:
    ITFWrapper() {
        barcode = new ITF("png");
    }

    ~ITFWrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// Matrix2of5
// =============================================================================
class Matrix2of5Wrapper {
private:
    Matrix2of5* barcode;

public:
    Matrix2of5Wrapper() {
        barcode = new Matrix2of5("png");
    }

    ~Matrix2of5Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// NEC2of5
// =============================================================================
class NEC2of5Wrapper {
private:
    NEC2of5* barcode;

public:
    NEC2of5Wrapper() {
        barcode = new NEC2of5("png");
    }

    ~NEC2of5Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// Jan8
// =============================================================================
class Jan8Wrapper {
private:
    Jan8* barcode;

public:
    Jan8Wrapper() {
        barcode = new Jan8("png");
    }

    ~Jan8Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    void setExtendedGuard(bool extended) {
        barcode->SetExtendedGuard(extended);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// Jan13
// =============================================================================
class Jan13Wrapper {
private:
    Jan13* barcode;

public:
    Jan13Wrapper() {
        barcode = new Jan13("png");
    }

    ~Jan13Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    void setExtendedGuard(bool extended) {
        barcode->SetExtendedGuard(extended);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// UPC_A
// =============================================================================
class UpcAWrapper {
private:
    UpcA* barcode;

public:
    UpcAWrapper() {
        barcode = new UpcA("png");
    }

    ~UpcAWrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    void setExtendedGuard(bool extended) {
        barcode->SetExtendedGuard(extended);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// UPC_E
// =============================================================================
class UpcEWrapper {
private:
    UpcE* barcode;

public:
    UpcEWrapper() {
        barcode = new UpcE("png");
    }

    ~UpcEWrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(float scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(float scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    void setExtendedGuard(bool extended) {
        barcode->SetExtendedGuard(extended);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// GS1 DataBar 14
// =============================================================================
class GS1DataBar14Wrapper {
private:
    GS1DataBar14* barcode;

public:
    GS1DataBar14Wrapper() {
        barcode = new GS1DataBar14("png");
    }

    ~GS1DataBar14Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(double scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(double scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    void setSymbolType(const std::string& type) {
        if (type == "OMNIDIRECTIONAL") {
            barcode->setSymbolType(GS1DataBar14::SymbolType::OMNIDIRECTIONAL);
        }
        else if (type == "STACKED") {
            barcode->setSymbolType(GS1DataBar14::SymbolType::STACKED);
        }
        else if (type == "STACKED_OMNIDIRECTIONAL") {
            barcode->setSymbolType(GS1DataBar14::SymbolType::STACKED_OMNIDIRECTIONAL);
        }
    }

    std::string getSymbolType() const {
        switch (barcode->getSymbolType()) {
        case GS1DataBar14::SymbolType::OMNIDIRECTIONAL:
            return "OMNIDIRECTIONAL";
        case GS1DataBar14::SymbolType::STACKED:
            return "STACKED";
        case GS1DataBar14::SymbolType::STACKED_OMNIDIRECTIONAL:
            return "STACKED_OMNIDIRECTIONAL";
        default:
            return "OMNIDIRECTIONAL";
        }
    }

    bool encode(const std::string& content) {
        return barcode->encode(content);
    }

    static std::string calculateCheckDigit(const std::string& src) {
        return GS1DataBar14::CalculateCheckDigit(src);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// GS1 DataBar Limited
// =============================================================================
class GS1DataBarLimitedWrapper {
private:
    GS1DataBarLimited* barcode;

public:
    GS1DataBarLimitedWrapper() {
        barcode = new GS1DataBarLimited("png");
    }

    ~GS1DataBarLimitedWrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(double scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(double scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// GS1 DataBar Expanded
// =============================================================================
class GS1DataBarExpandedWrapper {
private:
    GS1DataBarExpanded* barcode;

public:
    GS1DataBarExpandedWrapper() {
        barcode = new GS1DataBarExpanded("png");
    }

    ~GS1DataBarExpandedWrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    void setShowText(bool show) {
        barcode->SetShowText(show);
    }

    void setTextGap(double scale) {
        barcode->SetTextVerticalOffsetScale(scale);
    }

    void setTextFontScale(double scale) {
        barcode->SetTextFontScale(scale);
    }

    void setTextEvenSpacing(bool even) {
        barcode->SetTextEvenSpacing(even);
    }

    void setSymbolType(const std::string& type) {
        if (type == "UNSTACKED") {
            barcode->setSymbolType(GS1DataBarExpanded::SymbolType::UNSTACKED);
        }
        else if (type == "STACKED") {
            barcode->setSymbolType(GS1DataBarExpanded::SymbolType::STACKED);
        }
    }

    void setNoOfColumns(int columns) {
        barcode->setNoOfColumns(columns);
    }

    std::string draw(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int width, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }

    std::string drawStacked(const std::string& code, int width, int height) {
        if (barcode->DrawStacked(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }
};

// =============================================================================
// YubinCustomer
// =============================================================================
class YubinCustomerWrapper {
private:
    YubinCustomer* barcode;

public:
    YubinCustomerWrapper() {
        barcode = new YubinCustomer("png");
    }

    ~YubinCustomerWrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setPxAdjustBlack(int adjust) {
        barcode->SetPxAdjustBlack(adjust);
    }

    void setPxAdjustWhite(int adjust) {
        barcode->SetPxAdjustWhite(adjust);
    }

    std::string draw(const std::string& code, int height) {
        if (barcode->Draw(code, 0, 0, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int height) {
        if (barcode->Draw(code, 0, 0, height)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int height, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, height)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }

    std::string drawWithWidth(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }
};

// =============================================================================
// DataMatrix
// =============================================================================
class DataMatrixWrapper {
private:
    DataMatrix* barcode;

public:
    DataMatrixWrapper() {
        barcode = new DataMatrix("png");
    }

    ~DataMatrixWrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setStringEncoding(const std::string& encoding) {
        barcode->SetStringEncoding(encoding);
    }

    void setCodeSize(const std::string& size) {
        DxCodeSize codeSize = DxCodeSize::DxSzAuto;
        if (size == "AUTO") codeSize = DxCodeSize::DxSzAuto;
        else if (size == "10x10") codeSize = DxCodeSize::DxSz10x10;
        else if (size == "12x12") codeSize = DxCodeSize::DxSz12x12;
        else if (size == "14x14") codeSize = DxCodeSize::DxSz14x14;
        else if (size == "16x16") codeSize = DxCodeSize::DxSz16x16;
        else if (size == "18x18") codeSize = DxCodeSize::DxSz18x18;
        else if (size == "20x20") codeSize = DxCodeSize::DxSz20x20;
        else if (size == "22x22") codeSize = DxCodeSize::DxSz22x22;
        else if (size == "24x24") codeSize = DxCodeSize::DxSz24x24;
        else if (size == "26x26") codeSize = DxCodeSize::DxSz26x26;
        else if (size == "32x32") codeSize = DxCodeSize::DxSz32x32;
        else if (size == "36x36") codeSize = DxCodeSize::DxSz36x36;
        else if (size == "40x40") codeSize = DxCodeSize::DxSz40x40;
        else if (size == "44x44") codeSize = DxCodeSize::DxSz44x44;
        else if (size == "48x48") codeSize = DxCodeSize::DxSz48x48;
        else if (size == "52x52") codeSize = DxCodeSize::DxSz52x52;
        else if (size == "64x64") codeSize = DxCodeSize::DxSz64x64;
        else if (size == "72x72") codeSize = DxCodeSize::DxSz72x72;
        else if (size == "80x80") codeSize = DxCodeSize::DxSz80x80;
        else if (size == "88x88") codeSize = DxCodeSize::DxSz88x88;
        else if (size == "96x96") codeSize = DxCodeSize::DxSz96x96;
        else if (size == "104x104") codeSize = DxCodeSize::DxSz104x104;
        else if (size == "120x120") codeSize = DxCodeSize::DxSz120x120;
        else if (size == "132x132") codeSize = DxCodeSize::DxSz132x132;
        else if (size == "144x144") codeSize = DxCodeSize::DxSz144x144;
        else if (size == "8x18") codeSize = DxCodeSize::DxSz8x18;
        else if (size == "8x32") codeSize = DxCodeSize::DxSz8x32;
        else if (size == "12x26") codeSize = DxCodeSize::DxSz12x26;
        else if (size == "12x36") codeSize = DxCodeSize::DxSz12x36;
        else if (size == "16x36") codeSize = DxCodeSize::DxSz16x36;
        else if (size == "16x48") codeSize = DxCodeSize::DxSz16x48;
        barcode->SetCodeSize(codeSize);
    }

    void setEncodeScheme(const std::string& scheme) {
        DxScheme encScheme = DxScheme::DxSchemeAutoBest;
        if (scheme == "AUTO") encScheme = DxScheme::DxSchemeAutoBest;
        else if (scheme == "ASCII") encScheme = DxScheme::DxSchemeAscii;
        else if (scheme == "C40") encScheme = DxScheme::DxSchemeC40;
        else if (scheme == "TEXT") encScheme = DxScheme::DxSchemeText;
        else if (scheme == "X12") encScheme = DxScheme::DxSchemeX12;
        else if (scheme == "EDIFACT") encScheme = DxScheme::DxSchemeEdifact;
        else if (scheme == "BASE256") encScheme = DxScheme::DxSchemeBase256;
        barcode->SetEncodeScheme(encScheme);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    std::string draw(const std::string& code, int size) {
        if (barcode->Draw(code, 0, 0, size)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    std::string drawRect(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int size) {
        if (barcode->Draw(code, 0, 0, size)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int size, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, size)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// QR
// =============================================================================
class QRWrapper {
private:
    QR* barcode;

public:
    QRWrapper() {
        barcode = new QR("png");
    }

    ~QRWrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setStringEncoding(const std::string& encoding) {
        barcode->SetStringEncoding(encoding);
    }

    void setErrorCorrectionLevel(const std::string& level) {
        QRErrorCorrectionLevel ecLevel = QRErrorCorrectionLevel::M;
        if (level == "L") ecLevel = QRErrorCorrectionLevel::L;
        else if (level == "M") ecLevel = QRErrorCorrectionLevel::M;
        else if (level == "Q") ecLevel = QRErrorCorrectionLevel::Q;
        else if (level == "H") ecLevel = QRErrorCorrectionLevel::H;
        barcode->SetErrorCorrectionLevel(ecLevel);
    }

    void setVersion(int version) {
        barcode->SetVersion(version);
    }

    void setEncodeMode(const std::string& mode) {
        std::string internalMode = "B";
        if (mode == "AUTO" || mode == "BYTE") internalMode = "B";
        else if (mode == "NUMERIC") internalMode = "N";
        else if (mode == "ALPHANUMERIC") internalMode = "A";
        else if (mode == "KANJI") internalMode = "K";
        barcode->SetEncodeMode(internalMode);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    std::string draw(const std::string& code, int size) {
        if (barcode->Draw(code, 0, 0, size)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    std::string drawRect(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int size) {
        if (barcode->Draw(code, 0, 0, size)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int size, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, size)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// PDF417
// =============================================================================
class PDF417Wrapper {
private:
    PDF417* barcode;

public:
    PDF417Wrapper() {
        barcode = new PDF417("png");
    }

    ~PDF417Wrapper() {
        delete barcode;
    }

    void setOutputFormat(const std::string& format) {
        barcode->SetOutputFormat(format);
    }

    void setForegroundColor(int r, int g, int b, int a = 255) {
        barcode->SetForegroundColor(r, g, b, a);
    }

    void setBackgroundColor(int r, int g, int b, int a = 255) {
        barcode->SetBackgroundColor(r, g, b, a);
    }

    void setStringEncoding(const std::string& encoding) {
        barcode->SetStringEncoding(encoding);
    }

    void setErrorLevel(int level) {
        barcode->SetErrorLevel(static_cast<PDF417ErrorLevel>(level));
    }

    void setColumns(int columns) {
        barcode->SetColumns(columns);
    }

    void setRows(int rows) {
        barcode->SetRows(rows);
    }

    void setAspectRatio(double ratio) {
        barcode->SetAspectRatio(ratio);
    }

    void setYHeight(int yHeight) {
        barcode->SetYHeight(yHeight);
    }

    void setFitWidth(bool fit) {
        barcode->SetFitWidth(fit);
    }

    std::string draw(const std::string& code, int size) {
        if (barcode->Draw(code, 0, 0, size)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    std::string drawRect(const std::string& code, int width, int height) {
        if (barcode->Draw(code, 0, 0, width, height)) {
            if (barcode->IsSvgOutput()) {
                return barcode->GetSvg();
            }
            return barcode->GetImageBase64();
        }
        return "";
    }

    py::bytes drawBytes(const std::string& code, int size) {
        if (barcode->Draw(code, 0, 0, size)) {
            auto data = barcode->GetImageMemory();
            return py::bytes(reinterpret_cast<const char*>(data.data()), data.size());
        }
        return py::bytes();
    }

    void drawToFile(const std::string& code, int size, const std::string& filepath) {
        if (barcode->Draw(code, 0, 0, size)) {
            auto data = barcode->GetImageMemory();
            FILE* fp = fopen(filepath.c_str(), "wb");
            if (fp) {
                fwrite(data.data(), 1, data.size(), fp);
                fclose(fp);
            }
        }
    }
};

// =============================================================================
// pybind11 Module Definition
// =============================================================================
PYBIND11_MODULE(_barcode_pao_native, m) {
    m.doc() = "Barcode generation library for Python (Native C++ Extension)";

    // Code39
    py::class_<Code39Wrapper>(m, "Code39")
        .def(py::init<>())
        .def("set_output_format", &Code39Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &Code39Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &Code39Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &Code39Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &Code39Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &Code39Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &Code39Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &Code39Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &Code39Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &Code39Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("set_show_start_stop", &Code39Wrapper::setShowStartStop, py::arg("show"))
        .def("draw", &Code39Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &Code39Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &Code39Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // Code93
    py::class_<Code93Wrapper>(m, "Code93")
        .def(py::init<>())
        .def("set_output_format", &Code93Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &Code93Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &Code93Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &Code93Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &Code93Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &Code93Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &Code93Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &Code93Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &Code93Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &Code93Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("draw", &Code93Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &Code93Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &Code93Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // Code128
    py::class_<Code128Wrapper>(m, "Code128")
        .def(py::init<>())
        .def("set_output_format", &Code128Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &Code128Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &Code128Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &Code128Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &Code128Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &Code128Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &Code128Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &Code128Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &Code128Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &Code128Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("set_code_mode", &Code128Wrapper::setCodeMode, py::arg("mode"))
        .def("draw", &Code128Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &Code128Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &Code128Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // GS1_128
    py::class_<GS1_128Wrapper>(m, "GS1_128")
        .def(py::init<>())
        .def("set_output_format", &GS1_128Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &GS1_128Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &GS1_128Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &GS1_128Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &GS1_128Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &GS1_128Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &GS1_128Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &GS1_128Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &GS1_128Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &GS1_128Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("draw", &GS1_128Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &GS1_128Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &GS1_128Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"))
        .def("draw_convenience", &GS1_128Wrapper::drawConvenience, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_convenience_bytes", &GS1_128Wrapper::drawConvenienceBytes, py::arg("code"), py::arg("width"), py::arg("height"));

    // NW7
    py::class_<NW7Wrapper>(m, "NW7")
        .def(py::init<>())
        .def("set_output_format", &NW7Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &NW7Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &NW7Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &NW7Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &NW7Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &NW7Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &NW7Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &NW7Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &NW7Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &NW7Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("set_show_start_stop", &NW7Wrapper::setShowStartStop, py::arg("show"))
        .def("draw", &NW7Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &NW7Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &NW7Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // ITF
    py::class_<ITFWrapper>(m, "ITF")
        .def(py::init<>())
        .def("set_output_format", &ITFWrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &ITFWrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &ITFWrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &ITFWrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &ITFWrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &ITFWrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &ITFWrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &ITFWrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &ITFWrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &ITFWrapper::setTextEvenSpacing, py::arg("even"))
        .def("draw", &ITFWrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &ITFWrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &ITFWrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // Matrix2of5
    py::class_<Matrix2of5Wrapper>(m, "Matrix2of5")
        .def(py::init<>())
        .def("set_output_format", &Matrix2of5Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &Matrix2of5Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &Matrix2of5Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &Matrix2of5Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &Matrix2of5Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &Matrix2of5Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &Matrix2of5Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &Matrix2of5Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &Matrix2of5Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &Matrix2of5Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("draw", &Matrix2of5Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &Matrix2of5Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &Matrix2of5Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // NEC2of5
    py::class_<NEC2of5Wrapper>(m, "NEC2of5")
        .def(py::init<>())
        .def("set_output_format", &NEC2of5Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &NEC2of5Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &NEC2of5Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &NEC2of5Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &NEC2of5Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &NEC2of5Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &NEC2of5Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &NEC2of5Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &NEC2of5Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &NEC2of5Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("draw", &NEC2of5Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &NEC2of5Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &NEC2of5Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // Jan8
    py::class_<Jan8Wrapper>(m, "Jan8")
        .def(py::init<>())
        .def("set_output_format", &Jan8Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &Jan8Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &Jan8Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &Jan8Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &Jan8Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &Jan8Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &Jan8Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &Jan8Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &Jan8Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &Jan8Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("set_extended_guard", &Jan8Wrapper::setExtendedGuard, py::arg("extended"))
        .def("draw", &Jan8Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &Jan8Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &Jan8Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // Jan13
    py::class_<Jan13Wrapper>(m, "Jan13")
        .def(py::init<>())
        .def("set_output_format", &Jan13Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &Jan13Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &Jan13Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &Jan13Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &Jan13Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &Jan13Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &Jan13Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &Jan13Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &Jan13Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &Jan13Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("set_extended_guard", &Jan13Wrapper::setExtendedGuard, py::arg("extended"))
        .def("draw", &Jan13Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &Jan13Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &Jan13Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // UPC_A
    py::class_<UpcAWrapper>(m, "UPC_A")
        .def(py::init<>())
        .def("set_output_format", &UpcAWrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &UpcAWrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &UpcAWrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &UpcAWrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &UpcAWrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &UpcAWrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &UpcAWrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &UpcAWrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &UpcAWrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &UpcAWrapper::setTextEvenSpacing, py::arg("even"))
        .def("set_extended_guard", &UpcAWrapper::setExtendedGuard, py::arg("extended"))
        .def("draw", &UpcAWrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &UpcAWrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &UpcAWrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // UPC_E
    py::class_<UpcEWrapper>(m, "UPC_E")
        .def(py::init<>())
        .def("set_output_format", &UpcEWrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &UpcEWrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &UpcEWrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &UpcEWrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &UpcEWrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &UpcEWrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &UpcEWrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &UpcEWrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &UpcEWrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &UpcEWrapper::setTextEvenSpacing, py::arg("even"))
        .def("set_extended_guard", &UpcEWrapper::setExtendedGuard, py::arg("extended"))
        .def("draw", &UpcEWrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &UpcEWrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &UpcEWrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // GS1DataBar14
    py::class_<GS1DataBar14Wrapper>(m, "GS1DataBar14")
        .def(py::init<>())
        .def("set_output_format", &GS1DataBar14Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &GS1DataBar14Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &GS1DataBar14Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &GS1DataBar14Wrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &GS1DataBar14Wrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &GS1DataBar14Wrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &GS1DataBar14Wrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &GS1DataBar14Wrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &GS1DataBar14Wrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &GS1DataBar14Wrapper::setTextEvenSpacing, py::arg("even"))
        .def("set_symbol_type", &GS1DataBar14Wrapper::setSymbolType, py::arg("type"))
        .def("get_symbol_type", &GS1DataBar14Wrapper::getSymbolType)
        .def("encode", &GS1DataBar14Wrapper::encode, py::arg("content"))
        .def_static("calculate_check_digit", &GS1DataBar14Wrapper::calculateCheckDigit, py::arg("src"))
        .def("draw", &GS1DataBar14Wrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &GS1DataBar14Wrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &GS1DataBar14Wrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // GS1DataBarLimited
    py::class_<GS1DataBarLimitedWrapper>(m, "GS1DataBarLimited")
        .def(py::init<>())
        .def("set_output_format", &GS1DataBarLimitedWrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &GS1DataBarLimitedWrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &GS1DataBarLimitedWrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &GS1DataBarLimitedWrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &GS1DataBarLimitedWrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &GS1DataBarLimitedWrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &GS1DataBarLimitedWrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &GS1DataBarLimitedWrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &GS1DataBarLimitedWrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &GS1DataBarLimitedWrapper::setTextEvenSpacing, py::arg("even"))
        .def("draw", &GS1DataBarLimitedWrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &GS1DataBarLimitedWrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &GS1DataBarLimitedWrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"));

    // GS1DataBarExpanded
    py::class_<GS1DataBarExpandedWrapper>(m, "GS1DataBarExpanded")
        .def(py::init<>())
        .def("set_output_format", &GS1DataBarExpandedWrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &GS1DataBarExpandedWrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &GS1DataBarExpandedWrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &GS1DataBarExpandedWrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &GS1DataBarExpandedWrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("set_fit_width", &GS1DataBarExpandedWrapper::setFitWidth, py::arg("fit"))
        .def("set_show_text", &GS1DataBarExpandedWrapper::setShowText, py::arg("show"))
        .def("set_text_gap", &GS1DataBarExpandedWrapper::setTextGap, py::arg("scale"))
        .def("set_text_font_scale", &GS1DataBarExpandedWrapper::setTextFontScale, py::arg("scale"))
        .def("set_text_even_spacing", &GS1DataBarExpandedWrapper::setTextEvenSpacing, py::arg("even"))
        .def("set_symbol_type", &GS1DataBarExpandedWrapper::setSymbolType, py::arg("type"))
        .def("set_no_of_columns", &GS1DataBarExpandedWrapper::setNoOfColumns, py::arg("columns"))
        .def("draw", &GS1DataBarExpandedWrapper::draw, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &GS1DataBarExpandedWrapper::drawBytes, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_to_file", &GS1DataBarExpandedWrapper::drawToFile, py::arg("code"), py::arg("width"), py::arg("height"), py::arg("filepath"))
        .def("draw_stacked", &GS1DataBarExpandedWrapper::drawStacked, py::arg("code"), py::arg("width"), py::arg("height"));

    // YubinCustomer
    py::class_<YubinCustomerWrapper>(m, "YubinCustomer")
        .def(py::init<>())
        .def("set_output_format", &YubinCustomerWrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &YubinCustomerWrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &YubinCustomerWrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_px_adjust_black", &YubinCustomerWrapper::setPxAdjustBlack, py::arg("adjust"))
        .def("set_px_adjust_white", &YubinCustomerWrapper::setPxAdjustWhite, py::arg("adjust"))
        .def("draw", &YubinCustomerWrapper::draw, py::arg("code"), py::arg("height"))
        .def("draw_bytes", &YubinCustomerWrapper::drawBytes, py::arg("code"), py::arg("height"))
        .def("draw_to_file", &YubinCustomerWrapper::drawToFile, py::arg("code"), py::arg("height"), py::arg("filepath"))
        .def("draw_with_width", &YubinCustomerWrapper::drawWithWidth, py::arg("code"), py::arg("width"), py::arg("height"));

    // DataMatrix
    py::class_<DataMatrixWrapper>(m, "DataMatrix")
        .def(py::init<>())
        .def("set_output_format", &DataMatrixWrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &DataMatrixWrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &DataMatrixWrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_string_encoding", &DataMatrixWrapper::setStringEncoding, py::arg("encoding"))
        .def("set_code_size", &DataMatrixWrapper::setCodeSize, py::arg("size"))
        .def("set_encode_scheme", &DataMatrixWrapper::setEncodeScheme, py::arg("scheme"))
        .def("set_fit_width", &DataMatrixWrapper::setFitWidth, py::arg("fit"))
        .def("draw", &DataMatrixWrapper::draw, py::arg("code"), py::arg("size"))
        .def("draw_rect", &DataMatrixWrapper::drawRect, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &DataMatrixWrapper::drawBytes, py::arg("code"), py::arg("size"))
        .def("draw_to_file", &DataMatrixWrapper::drawToFile, py::arg("code"), py::arg("size"), py::arg("filepath"));

    // QR
    py::class_<QRWrapper>(m, "QR")
        .def(py::init<>())
        .def("set_output_format", &QRWrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &QRWrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &QRWrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_string_encoding", &QRWrapper::setStringEncoding, py::arg("encoding"))
        .def("set_error_correction_level", &QRWrapper::setErrorCorrectionLevel, py::arg("level"))
        .def("set_version", &QRWrapper::setVersion, py::arg("version"))
        .def("set_encode_mode", &QRWrapper::setEncodeMode, py::arg("mode"))
        .def("set_fit_width", &QRWrapper::setFitWidth, py::arg("fit"))
        .def("draw", &QRWrapper::draw, py::arg("code"), py::arg("size"))
        .def("draw_rect", &QRWrapper::drawRect, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &QRWrapper::drawBytes, py::arg("code"), py::arg("size"))
        .def("draw_to_file", &QRWrapper::drawToFile, py::arg("code"), py::arg("size"), py::arg("filepath"));

    // PDF417
    py::class_<PDF417Wrapper>(m, "PDF417")
        .def(py::init<>())
        .def("set_output_format", &PDF417Wrapper::setOutputFormat, py::arg("format"))
        .def("set_foreground_color", &PDF417Wrapper::setForegroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_background_color", &PDF417Wrapper::setBackgroundColor,
             py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255)
        .def("set_string_encoding", &PDF417Wrapper::setStringEncoding, py::arg("encoding"))
        .def("set_error_level", &PDF417Wrapper::setErrorLevel, py::arg("level"))
        .def("set_columns", &PDF417Wrapper::setColumns, py::arg("columns"))
        .def("set_rows", &PDF417Wrapper::setRows, py::arg("rows"))
        .def("set_aspect_ratio", &PDF417Wrapper::setAspectRatio, py::arg("ratio"))
        .def("set_y_height", &PDF417Wrapper::setYHeight, py::arg("y_height"))
        .def("set_fit_width", &PDF417Wrapper::setFitWidth, py::arg("fit"))
        .def("draw", &PDF417Wrapper::draw, py::arg("code"), py::arg("size"))
        .def("draw_rect", &PDF417Wrapper::drawRect, py::arg("code"), py::arg("width"), py::arg("height"))
        .def("draw_bytes", &PDF417Wrapper::drawBytes, py::arg("code"), py::arg("size"))
        .def("draw_to_file", &PDF417Wrapper::drawToFile, py::arg("code"), py::arg("size"), py::arg("filepath"));

    // Module path (for bundled font resolution)
    m.def("_set_module_path", &BarcodeBase::SetModulePath, py::arg("path"),
          "Set the module directory path for bundled font resolution");

    // ProductInfo
    py::class_<ProductInfo>(m, "ProductInfo")
        .def_static("get_license_email_addr", &ProductInfo::getLicenseEmailAddr)
        .def_static("is_licensed", &ProductInfo::isLicensed)
        .def_static("get_product_name", &ProductInfo::getProductName)
        .def_static("get_version", &ProductInfo::getVersion)
        .def_static("get_manufacturer", &ProductInfo::getManufacturer);
}
