//接上文
/******************************************************************************
* 字节压缩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;
}