C++Builder下利用TImage制作二维条码PDF417打印控件(五)

来源:互联网 发布:软件评测师招聘 编辑:程序博客网 时间:2024/06/07 09:45

//接上文

 /******************************************************************************
 * 字节压缩6
******************************************************************************/
void TPDF417::byteCompaction6(pPdf417class p, int start)
{
    int length = 6;
    char* text = p->param->text;
    int* ret = p->param->codewords + p->cwPtr;
    int retLast = 4;
    int ni, k;
    p->cwPtr += retLast + 1;
    memset(ret, 0, (retLast + 1) * sizeof(int));
    length += start;
   
 for (ni = start; ni < length; ++ni)
 {
        // 乘以256
        for (k = retLast; k >= 0; --k)
            ret[k] *= 256;
        // 加上该数字
        ret[retLast] += (int)text[ni] & 0xff;
        // 传播
        for (k = retLast; k > 0; --k)
  {
            ret[k - 1] += ret[k] / 900;
            ret[k] %= 900;
        }
    }
}

/******************************************************************************
 * 字节压缩
******************************************************************************/
void TPDF417::byteCompaction(pPdf417class p, int start, int length)
{
    int k, j;
    int size = (length / 6) * 5 + (length % 6);
   
 if (size + p->cwPtr > MAX_DATA_CODEWORDS)
 {
        p->param->error = PDF417_ERROR_TEXT_TOO_BIG;
        return;
    }
   
 length += start;
    for (k = start; k < length; k += 6)
 {
        size = length - k < 44 ? length - k : 6;
        if (size < 6)
  {
            for (j = 0; j < size; ++j)
                p->param->codewords[p->cwPtr++] = (int)p->param->text[k + j] & 0xff;
        }
        else
  {
            byteCompaction6(p, k);
        }
    }
}

/******************************************************************************
 * 中断文本
******************************************************************************/
void TPDF417::breakString(pPdf417class p, pArrayList list)
{
    char* text = p->param->text;
    int textLength = p->param->lenText;
    int lastP = 0;
    int startN = 0;
    int nd = 0;
    char c = 0;
    int k, lastTxt, j, txt;
    //int ptrS;
    pListElement v;
    pListElement vp;
    pListElement vn;
    list->size = 0;
   
 for (k = 0; k < textLength; ++k)
 {
        c = text[k];
       
  if (c >= '0' && c <= '9')
  {
            if (nd == 0)
                startN = k;
            ++nd;
            continue;
        }
       
  if (nd >= 13)
  {
            if (lastP != startN)
   {
                c = text[lastP];
                //ptrS = lastP;
                lastTxt = (c >= ' ' && c < 127) || c == '/r'
     || c == '/n' || c == '/t';
              
    for (j = lastP; j < startN; ++j)
    {
                    c = text[j];
                    txt = (c >= ' ' && c < 127) || c == '/r'
      || c == '/n' || c == '/t';
                   
     if (txt != lastTxt)
     {
                        listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, j);
                        lastP = j;
                        lastTxt = txt;
                    }
                }
                listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, startN);
            }
           
   listAdd(list, 'N', startN, k);
            lastP = k;
        }
        nd = 0;
    }
  
 if (nd < 13)
        startN = textLength;
   
 if (lastP != startN)
 {
        c = text[lastP];
        //ptrS = lastP;
        lastTxt = (c >= ' ' && c < 127) || c == '/r' || c == '/n' || c == '/t';
       
  for (j = lastP; j < startN; ++j)
  {
            c = text[j];
            txt = (c >= ' ' && c < 127) || c == '/r' || c == '/n' || c == '/t';
           
   if (txt != lastTxt)
   {
                listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, j);
                lastP = j;
                lastTxt = txt;
            }
        }
        listAdd(list, (char)(lastTxt ? 'T' : 'B'), lastP, startN);
    }
   
 if (nd >= 13)
        listAdd(list, 'N', startN, textLength);
  
 // 优化,合并短的字节
    for (k = 0; k < list->size; ++k)
 {
        v = listGet(list, k);
        vp = listGet(list, k - 1);
        vn = listGet(list, k + 1);;
       
  if (checkElementType(v, 'B') && getElementLength(v) == 1)
  {
            if (checkElementType(vp, 'T') && checkElementType(vn, 'T')
                && getElementLength(vp) + getElementLength(vn) >= 3)
   {
                vp->end = vn->end;
                listRemove(list, k);
                listRemove(list, k);
                k = -1;
                continue;
            }
        }
    }
   
 // 合并文本区段
    for (k = 0; k < list->size; ++k)
 {
        v = listGet(list, k);
        vp = listGet(list, k - 1);
        vn = listGet(list, k + 1);;
       
  if (checkElementType(v, 'T') && getElementLength(v) >= 5)
  {
            int redo = 0;
           
   if ((checkElementType(vp, 'B') && getElementLength(vp) == 1)
    || checkElementType(vp, 'T'))
   {
                redo = 1;
                v->start = vp->start;
                listRemove(list, k - 1);
                --k;
            }
           
   if ((checkElementType(vn, 'B') && getElementLength(vn) == 1)
    || checkElementType(vn, 'T'))
   {
                redo = 1;
                v->end = vn->end;
                listRemove(list, k + 1);
            }
           
   if (redo)
   {
                k = -1;
                continue;
            }
        }
    }
   
 // 合并二值区段
    for (k = 0; k < list->size; ++k)
 {
        v = listGet(list, k);
        vp = listGet(list, k - 1);
        vn = listGet(list, k + 1);;
       
  if (checkElementType(v, 'B'))
  {
            int redo = 0;
           
   if ((checkElementType(vp, 'T') && getElementLength(vp) < 5)
    || checkElementType(vp, 'B'))
   {
                redo = 1;
                v->start = vp->start;
                listRemove(list, k - 1);
                --k;
            }
           
   if ((checkElementType(vn, 'T') && getElementLength(vn) < 5)
    || checkElementType(vn, 'B'))
   {
                redo = 1;
                v->end = vn->end;
                listRemove(list, k + 1);
            }
           
   if (redo)
   {
                k = -1;
                continue;
            }
        }
    }
   
 // 检查所有数字
    if (list->size == 1 && (v = listGet(list, 0))->type == 'T'
  && getElementLength(v) >= 8)
 {
        for (k = v->start; k < v->end; ++k)
  {
            c = text[k];
            if (c < '0' || c > '9')
                break;
        }
        if (k == v->end)
            v->type = 'N';
    }
}

/******************************************************************************
 * 汇编
******************************************************************************/
void TPDF417::assemble(pPdf417class p, pArrayList list)
{
    int k;
    if (list->size == 0)
        return;
    p->cwPtr = 1;
   
 for (k = 0; k < list->size; ++k)
 {
        pListElement v = listGet(list, k);
        switch (v->type)
  {
        case 'T':
            if (k != 0)
                p->param->codewords[p->cwPtr++] = TEXT_MODE;
            textCompaction(p, v->start, v->end - v->start);
            break;
        case 'N':
            p->param->codewords[p->cwPtr++] = NUMERIC_MODE;
            numberCompaction(p, v->start, v->end - v->start);
            break;
        case 'B':
            p->param->codewords[p->cwPtr++]
    = (v->end - v->start) % 6 ? BYTE_MODE : BYTE_MODE_6;
            byteCompaction(p, v->start, v->end - v->start);
            break;
        }
        if (p->param->error)
            return;
    }
}
 
/******************************************************************************
 * 最大可能的纠错级别
******************************************************************************/
int TPDF417::maxPossibleErrorLevel(int remain)
{
    int level = 8;
    int size = 512;
   
 while (level > 0)
 {
        if (remain >= size)
            return level;
        --level;
        size >>= 1;
    }
   
 return 0;
}

/******************************************************************************
 * 废弃链表
******************************************************************************/
void TPDF417::dumpList(pPdf417class p, pArrayList list)
{
    int k;
   
 if (list->size == 0)
        return;
   
 for (k = 0; k < list->size; ++k)
 {
        pListElement v = listGet(list, k);
        printf("%c%.*s/n", v->type, v->end - v->start, p->param->text + v->start);
    }
}
/******************************************************************************
 * 转换整数为二进制数
******************************************************************************/
AnsiString TPDF417::GetBinStr(int n)
{
          AnsiString   str;

          for(UINT   d=n;   d!=0;   d>>=1)
                  str.Insert((d&1)?'1':'0',   1);
          if(str.IsEmpty())str='0';

          while(str.Length()%8!=0)
          {
              str="0"+str;
          }
          return   str;
}
/******************************************************************************
 * 获得最大平方
******************************************************************************/
int TPDF417::getMaxSquare(pPdf417param p)
{
    if (p->codeColumns > 21)
 {
        p->codeColumns = 29;
        p->codeRows = 32;
    }
    else
 {
        p->codeColumns = 16;
        p->codeRows = 58;
    }
    return MAX_DATA_CODEWORDS + 2;
}

/******************************************************************************
 * 画出条形码
******************************************************************************/
void TPDF417::paintCode(pPdf417param p)
{
    pdf417class pp;
    arrayList list;
    int maxErr, fixedColumn, lenErr, tot, skipRowColAdjust, pad;
    pp.param = p;
    p->error = 0;
   
 if (p->options & PDF417_USE_RAW_CODEWORDS)
 {
        if (p->lenCodewords > MAX_DATA_CODEWORDS || p->lenCodewords < 1
   || p->lenCodewords != p->codewords[0])
  {
            p->error = PDF417_ERROR_INVALID_PARAMS;
            return;
        }
    }
    else
 {
        if (p->lenText < 0)
            p->lenText = strlen(p->text);
        if (p->lenText > ABSOLUTE_MAX_TEXT_SIZE)
  {
            p->error = PDF417_ERROR_TEXT_TOO_BIG;
            return;
        }
        listInit(&list);
        breakString(&pp, &list);
        dumpList(&pp, &list);
        assemble(&pp, &list);
        listFree(&list);
        if (p->error)
            return;
        p->codewords[0] = p->lenCodewords = pp.cwPtr;
    }
   
 maxErr = maxPossibleErrorLevel(MAX_DATA_CODEWORDS + 2 - p->lenCodewords);
    if (!(p->options & PDF417_USE_ERROR_LEVEL))
 {
        if (p->lenCodewords < 41)
            p->errorLevel = 2;
        else if (p->lenCodewords < 161)
            p->errorLevel = 3;
        else if (p->lenCodewords < 321)
            p->errorLevel = 4;
        else
            p->errorLevel = 5;
    }
   
 if (p->errorLevel < 0)
        p->errorLevel = 0;
    else if (p->errorLevel > maxErr)
        p->errorLevel = maxErr;
    if (p->codeColumns < 1)
        p->codeColumns = 1;
    else if (p->codeColumns > 30)
        p->codeColumns = 30;
    if (p->codeRows < 3)
        p->codeRows = 3;
    else if (p->codeRows > 90)
        p->codeRows = 90;
   
 lenErr = 2 << p->errorLevel;
    fixedColumn = !(p->options & PDF417_FIXED_ROWS);
    skipRowColAdjust = 0;
    tot = p->lenCodewords + lenErr;
   
 if (p->options & PDF417_FIXED_RECTANGLE)
 {
        tot = p->codeColumns * p->codeRows;
        if (tot > MAX_DATA_CODEWORDS + 2)
  {
            tot = getMaxSquare(p);
        }
        if (tot < p->lenCodewords + lenErr)
            tot = p->lenCodewords + lenErr;
        else
            skipRowColAdjust = 1;
    }
    else if (!(p->options & (PDF417_FIXED_COLUMNS | PDF417_FIXED_ROWS)))
 {
        double c, b;
        fixedColumn = 1;
        if (p->aspectRatio < 0.001)
            p->aspectRatio = 0.001f;
        else if (p->aspectRatio > 1000)
            p->aspectRatio = 1000;
        b = 73 * p->aspectRatio - 4;
        c = (-b + sqrt(b * b + 4 * 17 * p->aspectRatio
   * (p->lenCodewords + lenErr) * p->yHeight)) / (2 * 17 * p->aspectRatio);
        p->codeColumns = (int)(c + 0.5);
        if (p->codeColumns < 1)
            p->codeColumns = 1;
        else if (p->codeColumns > 30)
            p->codeColumns = 30;
    }
   
 if (!skipRowColAdjust)
 {
        if (fixedColumn)
  {
            p->codeRows = (tot - 1) / p->codeColumns + 1;
            if (p->codeRows < 3)
                p->codeRows = 3;
            else if (p->codeRows > 90)
   {
                p->codeRows = 90;
                p->codeColumns = (tot - 1) / 90 + 1;
            }
        }
        else
  {
            p->codeColumns = (tot - 1) / p->codeRows + 1;
            if (p->codeColumns > 30)
   {
                p->codeColumns = 30;
                p->codeRows = (tot - 1) / 30 + 1;
            }
        }
        tot = p->codeRows * p->codeColumns;
    }
   
 if (tot > MAX_DATA_CODEWORDS + 2)
 {
        tot = getMaxSquare(p);
    }
   
 p->errorLevel = maxPossibleErrorLevel(tot - p->lenCodewords);
    lenErr = 2 << p->errorLevel;
    pad = tot - lenErr - p->lenCodewords;
    pp.cwPtr = p->lenCodewords;
    while (pad--)
        p->codewords[pp.cwPtr++] = TEXT_MODE;
    p->codewords[0] = p->lenCodewords = pp.cwPtr;
    calculateErrorCorrection(&pp, pp.param->lenCodewords);
    pp.param->lenCodewords = tot;
    outPaintCode(&pp);
}

/******************************************************************************
 * 设置条形码值
******************************************************************************/
void TPDF417::setValue(AnsiString Value)
{
   if(Value.Length()>90&&Value.Length()<150)
   {
        for(int i=0;i<150-Value.Length();i++)
        {
            Value+=" ";
        }
   }

    FValue=Value;
}

void TPDF417::makeDrawCode()
{
    pdf417param  p;
    pdf417init(&p);
/*
    char *outBits;  // 输出的bit位
    int lenBits;  // 长度
    int bitColumns;
    int codeRows;  // 层数
    int codeColumns; // 列数
    int codewords[928]; // 码字
    int lenCodewords; // 码字个数
    int errorLevel;  // 纠错码级别
    char *text;   // 文本
    int lenText;  // 文本长度
    int options;  // 选项
*/
 p.text = FValue.c_str() ;
    p.options = PDF417_INVERT_BITMAP;
    paintCode(&p);

 if (p.error)
 {
        pdf417free(&p);
    }

    int cols = p.bitColumns / 8 + 1;
    int k;
    AnsiString f;
    FDrawColumns=cols;
    FDrawRows=p.codeRows;

    for (k = 0; k < p.lenBits; ++k)
    {

          f+=GetBinStr(((int)p.outBits[k] & 0xff));
    }
    FDrawCode=f;
    pdf417free(&p);
}
/******************************************************************************
 * 设置绘制像素大小单位
******************************************************************************/
void TPDF417::setDrawPix(int pix)
{
    FDrawPix=pix;
}
/******************************************************************************
 * 设置绘制像素高度单位
******************************************************************************/
void TPDF417::setDrawRowHeightPix(int pix)
{
    FDrawRowHeightPix=pix;
}
/******************************************************************************
 * 绘制PDF417条码在Canvas上
******************************************************************************/
void TPDF417::DrawCodeBar(TCanvas *c)
{
    FWidth=FDrawColumns*8*FDrawPix;
    FHeight=FDrawRows*FDrawRowHeightPix;
    TRect r;
    r.Left=0;
    r.Top=0;
    r.Right=FWidth;
    r.Bottom=FHeight;
    c->FillRect(r);
    TPen *p = new TPen();
    p->Color=clWhite;
    p->Width=FDrawPix;
    c->Pen=p;
    int x,y;
    x=0;y=FHeight;
    c->MoveTo(x,y);
    int j=1;
    for(int k=0;k<FDrawRows;k++)
    {

        for(int i=0;i<FDrawColumns*8;i++)
        {

            if(FDrawCode.SubString(j,1)=="0"&&i<FDrawColumns*8)
            {
                p->Color=clBlack;
                p->Width=FDrawPix;
                c->Pen=p;
                c->MoveTo(x,y);
                c->LineTo(x,y-FDrawRowHeightPix);
            }
            if(FDrawCode.SubString(j,1)=="1")
            {
                p->Color=clWhite;
                p->Width=FDrawPix;
                c->Pen=p;
                c->MoveTo(x,y);
                c->LineTo(x,y-FDrawRowHeightPix);
            }
            x=(i*FDrawPix);
            j++;
        }
            p->Color=clWhite;
            p->Width=FDrawPix;
            c->Pen=p;
            c->MoveTo(x,y);
            c->LineTo(x,y-FDrawRowHeightPix);
        y=FHeight-(k*FDrawRowHeightPix);
    }

}

/******************************************************************************
 * 生成PDF417条码在Canvas上
******************************************************************************/

void TPDF417::DoCodeBar(TCanvas *canvas,AnsiString Value,int DrawPix,int RowHeightPix)
{
    setValue(Value);   //设置值
    setDrawPix(DrawPix);//设置绘画像素宽度
    setDrawRowHeightPix(RowHeightPix);//设置绘画像素高度
    makeDrawCode();    //生成绘画代码
    DrawCodeBar(canvas);//绘画条码到canvas中
}
/******************************************************************************
 * 获取PDF417条码在Canvas上的范围
******************************************************************************/

TRect TPDF417::GetCanvasRect()
{
    TRect r;
    r.Left=0;
    r.Top=0;
    r.Right=FWidth;
    r.Bottom=FHeight;
    return r;
}