利用 libdmtx 解码 DataMatrix

Posted liyuanbhu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用 libdmtx 解码 DataMatrix相关的知识,希望对你有一定的参考价值。

上面两篇博客简单的介绍了如何编译 libdmtx 和如何利用 libdmtx 生成 Data matrix 码。这篇博客讲讲如何解码。程序同样还是用到了Qt。图像都是先加载到 QImage 中,然后传给 libdmtx 来解码。
libdmtx 功能挺好,性能也还不错,但是文档有点差。网上也很少有对它的 API 的详细介绍。这些 API 的用法基本是靠 阅读 dmtx-utils 中的 dmtxread.c 来学习的。

解码功能封装到了一个类中:DataMatrixDecoder

这个类的声明如下:

class DataMatrixDecoder

public:
    struct UserOptions
       int edgeMin;         /* -e, --minimum-edge, pixel length of smallest expected edge in image */
       int edgeMax;         /* -E, --maximum-edge, pixel length of largest expected edge in image */
       int scanGap;         /* -g, --gap */
       int timeoutMS;       /* -m, --milliseconds, 每幅画的解码时间,超过时间就直接退出 */
       int squareDevn;      /* -q, --square-deviation, allow non-squareness of corners in degrees (0-90) */
       int sizeIdxExpected; /* -s, --symbol-size,DmtxSymbolShapeAuto, DmtxSymbolSquareAuto, DmtxSymbolRectAuto */
       int edgeThresh;      /* -t, --threshold,ignore weak edges below threshold N (1-100) */
       int xMin;          /* -x, --x-range-min 舍弃前面 xMin 列不处理 */
       int xMax;          /* -X, --x-range-max 舍弃 xMax 后的列不处理 */
       int yMin;          /* -y, --y-range-min 舍弃前面 yMin 行不处理 */
       int yMax;          /* -Y, --y-range-max 舍弃 yMax 后的列不处理 */
       int correctionsMax;  /* -C, --corrections-max ,correct at most N errors (0 = correction disabled)*/
       int mosaic;          /* -M, --mosaic , DmtxTrue, DmtxFalse*/
       int stopAfter;       /* -N, --stop-after, 获得 N 个码后退出 */
       int shrinkMin;       /* -S, --shrink (if range specified), internally shrink image by a factor of N */
       int gs1;             /* -G, --gs1 ,0-255 中间的一个字符,用来作为 FNC1 */
    ;
    DataMatrixDecoder();
    QStringList decodeMulti(QImage &image);
    QString decode(QImage &image);
    static void restoreDefaultOption(UserOptions &opt);
    void setOptions(UserOptions &opt);
    UserOptions options() const;
private:
    DmtxPassFail setDecodeOptions(DmtxDecode *dec, UserOptions &opt);
    DmtxDecode *m_dec = nullptr;
    DmtxImage *m_img = nullptr;
    UserOptions m_opt;
;

其中 UserOptions 用来控制解码时的各种参数,多数情况我们都用默认值就行了。

真正用来解码的有两个函数:

    QStringList decodeMulti(QImage &image);
    QString decode(QImage &image);

这里的 image 可以是8bit灰度图像,也可以是 RGB888 或者 RGB32 图像。

实现代码如下:

#include <string>
#include <cassert>
#include <QDebug>
#include "DataMatrixDecoder.h"

static DmtxImage* createDmtxImageFormQImage(QImage &image)

    DmtxImage* img = nullptr;
    switch (image.format())
    
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32:
    case QImage::Format_ARGB32_Premultiplied:
        img = dmtxImageCreate(image.bits(), image.width(), image.height(), DmtxPack32bppXRGB);
        img->rowSizeBytes = image.bytesPerLine();
        break;
    case QImage::Format_RGB888:
        img = dmtxImageCreate(image.bits(), image.width(), image.height(), DmtxPack24bppRGB);
        img->rowSizeBytes = image.bytesPerLine();
        break;
    case QImage::Format_Grayscale8:
        img = dmtxImageCreate(image.bits(), image.width(), image.height(), DmtxPack8bppK);
        img->rowSizeBytes = image.bytesPerLine();
        break;
    default:
        break;
    
    return img;


QString DataMatrixDecoder::decode(QImage &image)

    QString str;
    DmtxImage* img = createDmtxImageFormQImage(image);
    DmtxDecode* dec = dmtxDecodeCreate(img, 1);
    DmtxRegion* reg = dmtxRegionFindNext(dec, NULL);
    if (reg != NULL)
    
        DmtxMessage* msg = dmtxDecodeMatrixRegion(dec, reg, m_opt.correctionsMax);
        if (msg != NULL)
        
            str = QString::fromLatin1((const char *)msg->output);
            dmtxMessageDestroy(&msg);
        
        else
            qDebug() << "Not valid data type.";
        dmtxRegionDestroy(&reg);
    
    return str;


QStringList DataMatrixDecoder::decodeMulti(QImage &image)

    QStringList list;
    DmtxTime timeout;

    /* Reset timeout for each new page */
    if(m_opt.timeoutMS != DmtxUndefined)
    
        timeout = dmtxTimeAdd(dmtxTimeNow(), m_opt.timeoutMS);
    
    /* Initialize libdmtx image */
    DmtxImage* img = createDmtxImageFormQImage(image);
    if(img == nullptr)
    
        qFatal("dmtxImageCreate() error");
    

    dmtxImageSetProp(img, DmtxPropImageFlip, DmtxFlipNone);

    /* Initialize scan */
    DmtxDecode* dec = dmtxDecodeCreate(img, m_opt.shrinkMin);
    if(dec == nullptr)
    
        qFatal("dmtxDecodeCreate() error");
    
    DmtxPassFail err = setDecodeOptions(dec, m_opt);
    if(err != DmtxPass)
    
        qFatal("decode option error");
    
    int imgScanCount = 0;
    for(;;)
    
        DmtxRegion* reg = nullptr;
        /* Find next barcode region within image, but do not decode yet */
        if(m_opt.timeoutMS == DmtxUndefined)
           reg = dmtxRegionFindNext(dec, nullptr);
        else
           reg = dmtxRegionFindNext(dec, &timeout);

        /* Finished file or ran out of time before finding another region */
        if(reg == nullptr)
           break;

        /* Decode region based on requested barcode mode */
        DmtxMessage* msg = nullptr;
        if(m_opt.mosaic == DmtxTrue)
        
           msg = dmtxDecodeMosaicRegion(dec, reg, m_opt.correctionsMax);
        
        else
        
           msg = dmtxDecodeMatrixRegion(dec, reg, m_opt.correctionsMax);
        

        if(msg != nullptr)
        
            list << QString::fromLatin1((const char *)msg->output);
            imgScanCount++;
            dmtxMessageDestroy(&msg);
        
        dmtxRegionDestroy(&reg);
        if(m_opt.stopAfter != DmtxUndefined && imgScanCount >= m_opt.stopAfter)
        
            break;
        
    
    dmtxDecodeDestroy(&dec);
    dmtxImageDestroy(&img);
    return list;


void DataMatrixDecoder::setOptions(UserOptions &opt)

    m_opt = opt;


DataMatrixDecoder::UserOptions DataMatrixDecoder::options() const

    return m_opt;


DmtxPassFail DataMatrixDecoder::setDecodeOptions(DmtxDecode *dec, UserOptions &opt)

    int err;

 #define RETURN_IF_FAILED(e) if(e != DmtxPass)  return DmtxFail; 

    err = dmtxDecodeSetProp(dec, DmtxPropScanGap, opt.scanGap);
    RETURN_IF_FAILED(err)

    if(opt.gs1 != DmtxUndefined) 
       err = dmtxDecodeSetProp(dec, DmtxPropFnc1, opt.gs1);
       RETURN_IF_FAILED(err)
    

    if(opt.edgeMin != DmtxUndefined) 
       err = dmtxDecodeSetProp(dec, DmtxPropEdgeMin, opt.edgeMin);
       RETURN_IF_FAILED(err)
    

    if(opt.edgeMax != DmtxUndefined) 
       err = dmtxDecodeSetProp(dec, DmtxPropEdgeMax, opt.edgeMax);
       RETURN_IF_FAILED(err)
    

    if(opt.squareDevn != DmtxUndefined) 
       err = dmtxDecodeSetProp(dec, DmtxPropSquareDevn, opt.squareDevn);
       RETURN_IF_FAILED(err)
    

    err = dmtxDecodeSetProp(dec, DmtxPropSymbolSize, opt.sizeIdxExpected);
    RETURN_IF_FAILED(err)

    err = dmtxDecodeSetProp(dec, DmtxPropEdgeThresh, opt.edgeThresh);
    RETURN_IF_FAILED(err)

    if(opt.xMin) 
       err = dmtxDecodeSetProp(dec, DmtxPropXmin, opt.xMin);
       RETURN_IF_FAILED(err)
    

    if(opt.xMax) 
       err = dmtxDecodeSetProp(dec, DmtxPropXmax, opt.xMax);
       RETURN_IF_FAILED(err)
    

    if(opt.yMin) 
       err = dmtxDecodeSetProp(dec, DmtxPropYmin, opt.yMin);
       RETURN_IF_FAILED(err)
    

    if(opt.yMax) 
       err = dmtxDecodeSetProp(dec, DmtxPropYmax, opt.yMax);
       RETURN_IF_FAILED(err)
    

 #undef RETURN_IF_FAILED

    return DmtxPass;



void DataMatrixDecoder::restoreDefaultOption(UserOptions &opt)

    memset(&opt, 0x00, sizeof(UserOptions));

    /* Default options */
    opt.edgeMin = DmtxUndefined;
    opt.edgeMax = DmtxUndefined;
    opt.scanGap = 2;
    opt.timeoutMS = DmtxUndefined;
    opt.squareDevn = DmtxUndefined;
    opt.sizeIdxExpected = DmtxSymbolShapeAuto;
    opt.edgeThresh = 5;
    opt.xMin = 0;
    opt.xMax = 0;
    opt.yMin = 0;
    opt.yMax = 0;
    opt.correctionsMax = DmtxUndefined;
    opt.mosaic = DmtxFalse;
    opt.stopAfter = DmtxUndefined;
    opt.shrinkMin = 1;
    opt.gs1 = DmtxUndefined;


DataMatrixDecoder::DataMatrixDecoder()

    restoreDefaultOption(m_opt);


代码基本就这样。还有些需要进一步完善的地方。比如除了解码的字符串之外,还应该获得DM 码所在的位置。这一块用什么样的数据结构来返回还没想好。等后面有空了再完善一下。

以上是关于利用 libdmtx 解码 DataMatrix的主要内容,如果未能解决你的问题,请参考以下文章

利用libdmtx 生成 DataMatrix 码

利用libdmtx 生成 DataMatrix 码

Data Matrix 二维码解码库 libdmtx 编译方法

Data Matrix 二维码解码库 libdmtx 编译方法

J2me,我需要一个不是 Zxing 的 datamatrix 解码器库

C# 生成 DataMatrix 格式的二维码