pdf417lib庫封裝和使用

Linux袁浩發表於2024-03-23

pdf417lib庫封裝和使用

pdf417lib下載連結

https://master.dl.sourceforge.net/project/pdf417lib/pdf417lib/0.91/pdf417lib-c-0.91.zip?viasf=1

CMake檔案

yh@ubuntu:/Test/pdf417lib$ tree
.
├── build
├── CMakeLists.txt
├── include
│   ├── pdf417.h
│   ├── pdf417lib.h
│   └── pdf417libimp.h
├── main.cpp
└── src
    ├── pdf417.cpp
    └── pdf417lib.c

3 directories, 7 files

CMakeLists.txt檔案

cmake_minimum_required(VERSION 3.0.0)
project(barcode)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB LIBRARY_SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/pdf417lib.c")

#設定靜態庫和動態庫所需的中間檔案列表
set(LIBRARY_OBJS_LIST ${PROJECT_NAME}-objs)
add_library(${LIBRARY_OBJS_LIST} OBJECT ${LIBRARY_SRC_LIST})
#開啟靜態庫和動態庫所需的中間檔案的PIC編譯選項
set_target_properties(${LIBRARY_OBJS_LIST} PROPERTIES POSITION_INDEPENDENT_CODE True)

#生成靜態庫
#設定靜態庫檔案臨時名稱
set(TMP_STATIC_LIB_NAME ${PROJECT_NAME}-static)
#生成靜態庫檔案
add_library(${TMP_STATIC_LIB_NAME} STATIC $<TARGET_OBJECTS:${LIBRARY_OBJS_LIST}>)
#設定靜態庫檔案的最終名稱
set_target_properties(${TMP_STATIC_LIB_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME})

#生成動態庫
#設定動態庫檔案臨時名稱
set(TMP_SHARED_LIB_NAME ${PROJECT_NAME}-shared)
#生成動態庫檔案
add_library(${TMP_SHARED_LIB_NAME} SHARED $<TARGET_OBJECTS:${LIBRARY_OBJS_LIST}>)
#設定動態庫檔案的最終名稱
set_target_properties(${TMP_SHARED_LIB_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME})

add_executable(test${PROJECT_NAME} main.cpp)
target_link_libraries(test${PROJECT_NAME} ${TMP_STATIC_LIB_NAME})

pdf417lib.h

#ifndef __PDF417LIB_H__
#define __PDF417LIB_H__

#ifdef __cplusplus
extern "C" {
#endif
//四者取其一,優先判斷PDF417_FIXED_RECTANGLE,若乘積大於(MAX_DATA_CODEWORDS + 2)
//則取最大值(MAX_DATA_CODEWORDS + 2),並且重設資訊塊數的數量和行高。
//接著判斷PDF417_FIXED_COLUMNS和PDF417_FIXED_ROWS若未設定,則採用PDF417_USE_ASPECT_RATIO
//建議不要使用PDF417_USE_ASPECT_RATIO受aspectRatio、yHeight和strlen(text)影響很不穩定
#define PDF417_USE_ASPECT_RATIO     0      //此項為預設值,預設比例為0.5,透過aspectRatio來修改
#define PDF417_FIXED_RECTANGLE      1      //同時指定pdf417條碼的寬度(資料區資訊塊的數量)和高度(最小方塊的數量)
#define PDF417_FIXED_COLUMNS        2      //指定pdf417條碼的寬度(資料區資訊塊的數量)
#define PDF417_FIXED_ROWS           4      //指定pdf417條碼的高度(最小方塊的數量)

//二者取其一
#define PDF417_AUTO_ERROR_LEVEL     0      //此項為預設值,根據內容的位元組數自動設定糾錯等級
#define PDF417_USE_ERROR_LEVEL      16     //指定pdf417條碼的糾錯等級(0到8)

#define PDF417_USE_RAW_CODEWORDS    64     //將text作為二進位制流而非字元流,此時需要設定lenText的大小
#define PDF417_INVERT_BITMAP        128    //反轉pdf417條碼的黑白塊,預設1表示黑塊

//pdf417param中error的值, 表示paintCode()的執行結果
#define PDF417_ERROR_SUCCESS        0      //沒有錯誤
#define PDF417_ERROR_TEXT_TOO_BIG   1      //所需編碼的資訊過大
#define PDF417_ERROR_INVALID_PARAMS 2      //錯在錯誤的條碼引數

typedef struct _pdf417param {
    char *outBits;
    int lenBits;
    int bitColumns;
    int codeRows;        //最大值90,若與codeColumns大於928,則兩個值會被重設
    int codeColumns;     //最大值30,若與codeRows大於928,則兩個值會被重設
    int codewords[928];
    int lenCodewords;
    int errorLevel;
    char *text;
    int lenText;
    int options;
    float aspectRatio;
    float yHeight;
    int error;
} pdf417param, *pPdf417param;

void paintCode(pPdf417param p);
void pdf417init(pPdf417param param);
void pdf417free(pPdf417param param);
#ifdef __cplusplus
}
#endif

#endif

pdf417.h

#ifndef __PDF417__
#define __PDF417__

#include <string>
#include <vector>

class pdf417
{
    public:
    enum class FitPolicy {UseAspectRatio = 0, FixedRectangle = 1, FixedColumns = 2, FixedRows = 4};
public:
    pdf417() = default;
    ~pdf417() = default;
public:
    void setBarCodeProperty(int columnfit = 6, int pixelBitDepth = 1, bool ifInvertPixel = false, int errorLevel = -1, FitPolicy shapefit = FitPolicy::FixedColumns, float ratio = 0.5, float yHeight = 3.0, int rowfit = 0);
    bool printBarCode(const std::string &data);
    bool output2postscript(const std::string &path);
public:
    int m_Width = 0;
    int m_Height = 0;
    int m_BytesPerRow = 0;
    int m_PixelBitsDepth = 1;
    int m_ColumnFit = 0;
    int m_RowFit = 0;
    int m_ShapeFit = 0;
    int m_ErrorLevel = 0;
    float m_YHeight = 3.0;
    float m_AspectRatio = 0.5;
    bool m_IfInvertPixel = false;
    std::vector<unsigned char> m_CacheMap;
    std::string m_ErrorMSG;
};

#endif

pdf417.cpp

#include <pdf417.h>
#include <pdf417lib.h>
#include <iostream>

using namespace std;

void pdf417::setBarCodeProperty(int columnfit, int pixelBitDepth, bool ifInvertPixel, int errorLevel, FitPolicy shapefit, float ratio, float yHeight, int rowfit)
{
    m_AspectRatio = 0.5;
    m_RowFit = 0;
    m_ColumnFit = 0;

    switch(shapefit)
    {
        case FitPolicy::FixedRectangle:
        {
            m_RowFit = rowfit;
            m_ColumnFit = columnfit;
            m_ShapeFit= PDF417_FIXED_RECTANGLE;
            break;
        }
        case FitPolicy::FixedColumns:
        {
            m_ShapeFit= PDF417_FIXED_COLUMNS;
            m_ColumnFit = columnfit;
            break;
        }
        case FitPolicy::FixedRows:
        {
            m_ShapeFit= PDF417_FIXED_ROWS;
            m_RowFit = rowfit;
            break;
        }
        default:
        {
            m_ShapeFit= PDF417_USE_ASPECT_RATIO;
            m_AspectRatio = ratio;
            break;
        }  
    }
    m_PixelBitsDepth = pixelBitDepth;
    m_IfInvertPixel = ifInvertPixel;
    m_ErrorLevel = errorLevel;
    m_YHeight = yHeight;
}

bool pdf417::printBarCode(const std::string &data)
{
    pdf417param property;
    pdf417init(&property);
    property.text = const_cast<char*>(data.c_str());
    property.errorLevel = m_ErrorLevel;
    if(m_IfInvertPixel)
    {
        property.options |= PDF417_INVERT_BITMAP;
    }
    property.options |= m_ShapeFit;
    property.codeRows = m_RowFit;
    property.codeColumns = m_ColumnFit;
    property.aspectRatio =  m_AspectRatio;
    property.yHeight = m_YHeight;
    paintCode(&property);
    switch(property.error)
    {
        case PDF417_ERROR_SUCCESS:
        {
            m_Width = property.bitColumns;
            m_Height = property.codeRows;
            m_BytesPerRow = (property.bitColumns + 7) / 8;
            m_CacheMap = vector<unsigned char>(m_BytesPerRow * m_Height);
            for (int k = 0; k < m_CacheMap.size(); ++k)
            {
                m_CacheMap[k] = property.outBits[k];
            }
            m_ErrorMSG = "";
            return true;
        }
        case PDF417_ERROR_TEXT_TOO_BIG:
        {
            m_ErrorMSG = "輸入資料text過大";
            break;
        }
        case PDF417_ERROR_INVALID_PARAMS:
        {
            m_ErrorMSG = "條款引數設定異常";
            break;
        }
        default:
        {
            m_ErrorMSG = "未知錯誤";
            break;
        }
    }
    pdf417free(&property);
    return false;
}

bool pdf417::output2postscript(const std::string &path)
{
    FILE *fp = fopen(path.c_str(), "wb");
    if(fp)
    {
        int cols = m_BytesPerRow;
        fprintf(fp, "%%!PS1.3\n");
        fprintf(fp, "/Times findfont\n");
        fprintf(fp, "8 scalefont setfont\n");
        fprintf(fp, "100 92 moveto\n");
        switch(m_ShapeFit)
        {
        case PDF417_FIXED_RECTANGLE:
        {
            fprintf(fp, "(FIXED_RECTANGLE row: %d, column: %d)show\n", m_Height, m_Width);
            break;
        }
        case PDF417_FIXED_COLUMNS:
        {
            fprintf(fp, "(FIXED_COLUMNS row: %d, column: %d)show\n", m_Height, m_Width);
            break;
        }
        case PDF417_FIXED_ROWS:
        {
            fprintf(fp, "(FIXED_ROWS row: %d, column: %d)show\n", m_Height, m_Width);
            break;
        }
        case PDF417_USE_ASPECT_RATIO:
        {
            fprintf(fp, "(USE_ASPECT_RATIO ratio: %f, yheight: %f, row: %d, column: %d)show\n", m_AspectRatio, m_YHeight, m_Height, m_Width);
            break;
        } 
        }
        fprintf(fp, "stroke\n100 100 translate\n%g %g scale\n", (double)m_Width, (double)m_Height);
        fprintf(fp, "%d %d 1 [%d 0 0 %d 0 %d]{<", m_Width, m_Height, m_Width, -m_Height, m_Height);
        for (int k = 0; k < m_CacheMap.size(); ++k)
        {
            if (!(k % cols))
            {
                fprintf(fp, "\n");
            }  
            fprintf(fp, "%02X", m_CacheMap[k] & 0xff);
        }
        fprintf(fp, "\n>}image\nshowpage\n");
        fclose(fp);
        return true;
    }
    else
    {
        cerr << "檔案開啟失敗請檢查所在目錄是否擁有訪問和讀寫許可權!" << endl;
    }
    return false;
}

main.cpp

#include <iostream>
#include <pdf417.h>

int main(int argc, const char *argv[])
{
    pdf417 barcode;
    int columnfit = 6;
    int pixelBitDepth = 1;
    bool ifInvertPixel = true;
    int errorLevel = -1;
    float ratio = 0.5;
    float yHeight = 3.0;
    int rowfit = 16;
    barcode.setBarCodeProperty(columnfit, pixelBitDepth, ifInvertPixel, errorLevel, pdf417::FitPolicy::FixedRows, ratio, yHeight, rowfit);
    std::string data = "1234567890abcdefg1234567890abcdefg";
    barcode.printBarCode(data);
    barcode.output2postscript("file.ps");
    return 0;
}

處理pdf417lib往標準輸出裡面輸出除錯資訊的問題

pdf417lib.c第693行

printf("%c%.*s\n", v->type, v->end - v->start, p->param->text + v->start);
修改為
fprintf(stderr, "%c%.*s\n", v->type, v->end - v->start, p->param->text + v->start);

測試

cmake .. && make -j8 && ./testbarcode && ps2pdf12 file.ps file.pdf

相關文章