⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stddataobject.cpp

📁 对位图文件中的点阵数据进行模式判别,找出其中的完整PDF417条码,并按照GB/T 17172-1997规范来解释读出对应的数据.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// StdDataObject.cpp: implementation of the CStdDataObject class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "pdf417.h"
#include "StdDataObject.h"
#include "Afx.h"
#include "data.h"
#include "MainFrm.h"
#include <math.h>

#define ERRORLIMIT	10	//错误范围限制
#define EMPTYLIMIT  4
#define JUDGETIMES	10

//条码组合模式
#define TEXTMODE	1	//文本压缩模式
#define BYTEMODE	2	//字节压缩模式
#define NUMBERMODE	3	//数字压缩模式

//文本压缩子模式
#define ALPHA		1	//大写字母子模式
#define LOWERCASE	2	//小写字母子模式
#define MIXED		3	//混合子模式
#define PUNCTUATION 4	//标点子模式

//文本压缩子模式锁定/转移码
#define LL			2	//锁定为小定字母型子模式
#define PS			4	//转移为标点型子模式
#define ML			5	//锁定为混合型子模式
#define AL			6	//锁定为大写字母型子模式
#define PL			7	//锁定为标点型子模式
#define AS			8	//转移为大写字母型子模式

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CStdDataObject::CStdDataObject()
{

}

CStdDataObject::~CStdDataObject()
{

}

//从一个BMP对象中得到数据,并化为标准格式后存入类的pArrayMemory中
//标准化格式为:一个字节存放一个像素点
void CStdDataObject::GetStdData(CBmpObject* pObj)
{
	//设定图像高度,宽度,行长
	dImageWidth = pObj->dImageWidth;
	dImageHeight = pObj->dImageHeight;

	//每行所需要的字节数目
	dBytesPerLine = dImageWidth;	//每个像素对应于一个字节

	//为像素点阵申请内存空间
	pArrayMemory = new UCHAR[dBytesPerLine*dImageHeight];

	//矩阵内存空间初始化为0
	::memset(pArrayMemory,0,dBytesPerLine*dImageHeight);

	//根据点像素来设置矩阵数据
	for(UINT H=0;H < dImageHeight;H++)
	{
		for(UINT W=0;W < dImageWidth;W++)
		{
			if(pObj->IsBlack(W,H))
				pArrayMemory[dBytesPerLine*H+W] = 1;
		}
	}
}

//判断像素点是否为黑色
inline BOOL CStdDataObject::StdIsBlack(UINT x, UINT y)
{
	return pArrayMemory[dBytesPerLine*y+x];
}

//转换像素点为白色
inline void CStdDataObject::Whitten(UINT x, UINT y)
{
	pArrayMemory[dBytesPerLine*y+x] = 0;
}

//得到所有包括Cell的区域,并存入到类的RegionList中
void CStdDataObject::FindAllCell(Cell* pCell,CList<struct _Region,struct _Region &>& RegionList)
{
	UINT dCIAWidth=0,dCIAHeight=0;
	UINT tmp1,i,W,H;
	BOOL bIsOk;
	Region tmp;
	//申请空间以保存原始数据
	UCHAR* tmpbuffer=new UCHAR[dBytesPerLine*dImageHeight];
	memcpy(tmpbuffer,pArrayMemory,dBytesPerLine*dImageHeight);
	//得到Cell数组的高度和宽度于dCIAWidth,dCIAHeight中
	for(i=0;i<pCell->CellItemCount;i++)
	{
		if((tmp1=pCell->CellArray[i].x)>dCIAWidth) 
			dCIAWidth=tmp1;
		if((tmp1=pCell->CellArray[i].y)>dCIAHeight)
			dCIAHeight=tmp1;
	}
	dCIAWidth++;
	dCIAHeight++;

	for(H=0;H<dImageHeight-dCIAHeight;H+=8)
		for(W=0;W<dImageWidth-dCIAWidth;W+=8)
		{
			//如果点为BLACK,则判断由该点开始的一个区域是否满足Cell
			if(StdIsBlack(W,H))
			{
				bIsOk=true;
				for(i=0;i<pCell->CellItemCount;i++)
				{
					if(!StdIsBlack(W+pCell->CellArray[i].x,H+pCell->CellArray[i].y))
					{	bIsOk=false; break;  }
				}
				//如满足,则穷尽此区域,得到区域的上下左右各点坐标,并存入RegionList中
				if(bIsOk)
				{
					tmp.Left.x = W;
					tmp.Left.y = H;
					tmp.Right.x = W;
					tmp.Right.y = H;
					tmp.Top.y = H;
					tmp.Top.x = W;
					tmp.Root.y = H;
					tmp.Root.x = W;
					mleft = mright = W;
					mroot = mtop = H;
					EmptyRegionInXY(W,H,&tmp);
					if(IsRect(tmp))
					{
						if(RegionList.GetCount()==0) RegionList.AddHead(tmp);
						else RegionList.AddTail(tmp);
					}
				}
			}
		}
	//恢复原数据
	memcpy(pArrayMemory,tmpbuffer,dBytesPerLine*dImageHeight);
	delete[] tmpbuffer;
}

//使用递归运算来穷尽整个区域,并返回区域的坐标值
void CStdDataObject::EmptyRegionInXY(UINT x, UINT y, Region* pRegion)
{
	UINT xx,yy,sx,ex;
	BOOL flags;
	xx=x,yy=y;
	//处理点(x,y)左边的数据
	do{
		Whitten(xx,yy);
	}while(xx>=1 && StdIsBlack(--xx,yy));
	sx=xx+1;

	//处理点(x,y)右边的数据
	xx=x;
	while(xx+1<dImageWidth && StdIsBlack(++xx,yy))
		Whitten(xx,yy);
	ex=xx-1;

	if(sx<mleft) mleft=sx;
	if(ex>mright) mright=ex;
	if(yy<mtop) mtop=yy;
	else if(yy>mroot) mroot=yy;

	//判断是否为LEFT点
/*
	if(yy<pRegion->Left.y && abs(sx-pRegion->Left.x)<=2 && pRegion->Left.y-yy>=2)
	{ pRegion->Left.x=sx; pRegion->Left.y=yy; }
	if(yy>pRegion->Left.y && sx<=pRegion->Left.x-2)
	{ pRegion->Left.x=sx; pRegion->Left.y=yy; }
	if(yy==pRegion->Left.y)
	{ pRegion->Left.x=sx; pRegion->Right.x=ex; }
	if(ex==pRegion->Left.x && yy<pRegion->Left.y)
	{ pRegion->Left.x=sx; pRegion->Right.x=ex; }
*/
	if(sx<pRegion->Left.x && (pRegion->Left.x-sx >=2 || pRegion->Left.x-sx>abs(yy-pRegion->Left.y)))
	{ pRegion->Left.x=sx; pRegion->Left.y=yy; }
	if(abs(sx-mleft)<=1 && yy<pRegion->Left.y)
	{ pRegion->Left.x=sx; pRegion->Left.y=yy; }

	//判断是否为TOP点
/*
	if(pRegion->Top.y>=yy+2)
	{ pRegion->Top.y=yy; pRegion->Top.x=ex; }
	if(pRegion->Top.y>=yy && ex>=pRegion->Top.x)
	{ pRegion->Top.y=yy; pRegion->Top.x=ex; }
	else if(yy<pRegion->Top.y && abs(pRegion->Top.x-ex)<=EMPTYLIMIT)
	{ pRegion->Top.y=yy; pRegion->Top.x=ex; };
*/
	if(yy<pRegion->Top.y)
	{ pRegion->Top.y=yy; pRegion->Top.x=ex; }
	if(abs(mtop-yy)<=1 && ex>pRegion->Top.x)
	{ pRegion->Top.y=yy; pRegion->Top.x=ex; }
		

	//判断是否为RIGHT点
	if(ex>pRegion->Right.x)
	{ pRegion->Right.x=ex; pRegion->Right.y=yy; }
	if(yy> pRegion->Right.y && abs(ex-mright)<=1)
	{ pRegion->Right.x=ex; pRegion->Right.y=yy; }

	//判断是否为ROOT点
	if(yy>pRegion->Root.y)
	{ pRegion->Root.y=y; pRegion->Root.x=sx; }
	if(abs(mroot-yy)<=1 && sx<pRegion->Root.x)
	{ pRegion->Root.y=y; pRegion->Root.x=sx; }

	//处理上一行
	if(y>0)
	{
		for(xx=sx;xx<=ex;xx++)
		{
			if(StdIsBlack(xx,yy-1))
			{
				EmptyRegionInXY(xx,yy-1,pRegion);
				flags=false;
			}
		}
	}

	//处理下一行
	if(y+1<dImageHeight)
	{
		for(xx=sx;xx<=ex;xx++)
		{
			if(StdIsBlack(xx,yy+1))
			{
				EmptyRegionInXY(xx,yy+1,pRegion);
				flags=false;
			}
		}
	}
}

//判断一个区域是否为矩形
BOOL CStdDataObject::IsRect(Region r)
{
	//判断两直角边是否相等
	if(abs((int)(r.Top.x-r.Left.x-r.Right.x+r.Root.x))>ERRORLIMIT)
		return false;
	if(abs((int)(r.Left.y-r.Top.y-r.Root.y+r.Right.y))>ERRORLIMIT)
		return false;

	//判断两对角线是否相等
	double tmp1=sqrt((r.Top.x-r.Left.x)*(r.Top.x-r.Left.x)+
		(r.Root.y-r.Top.y)*(r.Root.y-r.Top.y));
	double tmp2=sqrt((r.Right.x-r.Left.x)*(r.Right.x-r.Left.x)+
		(r.Right.y-r.Left.y)*(r.Right.y-r.Left.y));
//	if(abs(tmp1-tmp2)> tmp1>1000?10*ERRORLIMIT:ERRORLIMIT)
//		return false;
	return true;
}

BOOL CStdDataObject::IsBarHeader(Region* pReg)
{
	Region tmpreg,reg;
	UCHAR HeaderShape[]={8,1,1,1,1,1,1,3};
	//此变量进行两个方向的判断
	BOOL firstjudge=true;
	UPOINT* PointArray;
	UCHAR BWArray[1000];
	//把原矩形化为可供判断的标准矩形
	reg = *pReg;
	tmpreg = reg;
	if((reg.Top.x-reg.Left.x)*(reg.Top.x-reg.Left.x)+(reg.Left.y-reg.Top.y)*(reg.Left.y-reg.Top.y) > 
		(reg.Right.x-reg.Top.x)*(reg.Right.x-reg.Top.x)+(reg.Right.y-reg.Top.y)*(reg.Right.y-reg.Top.y))
	{
		tmpreg.Left=reg.Top;
		tmpreg.Root=reg.Left;
		tmpreg.Top=reg.Right;
		tmpreg.Right=reg.Root;
	}
loop:
	if(!firstjudge)
	{
		//进行第二次判断时,改变方向
		Region tmpreg1 = tmpreg;
		tmpreg.Top = tmpreg1.Root;
		tmpreg.Left = tmpreg1.Right;
		tmpreg.Right = tmpreg1.Left;
		tmpreg.Root = tmpreg1.Top;
	}
	//计算点的总数
	int _height = (int)(sqrt((tmpreg.Left.x-tmpreg.Root.x)*(tmpreg.Left.x-tmpreg.Root.x)+
		(tmpreg.Left.y-tmpreg.Root.y)*(tmpreg.Left.y-tmpreg.Root.y))+1.5);
	//申请一空间以存入纵向的点(起始点)
	PointArray = new UPOINT[_height];
	int rheight = GetLineDataA(tmpreg.Left.x,tmpreg.Left.y,tmpreg.Root.x,tmpreg.Root.y,PointArray);
	//确定dx,dy值
	int tx=tmpreg.Top.x,ty=tmpreg.Top.y,lx=tmpreg.Left.x,ly=tmpreg.Left.y,z;
	z=(tx>lx)?1:-1;
	int dx=(int)((tx==lx)?0:(18*(tx-lx+z)/7+0.5));
	z=(ty>ly)?1:-1;
	int dy=(int)((ty==ly)?0:(18*(ty-ly+z)/7+0.5));
	//申请空间以存放横向的点(一行数据),宽度为_width
	int _width = (int)(sqrt(dx*dx+dy*dy)+1.5);
	if(_width>1000)	//如一条模宽度大于1000,则认为数据出错
	{
		delete PointArray;
		return false;
	}
	int dj=(int)(rheight/JUDGETIMES+0.5);
	if(dj<1) dj=1;
	for(int i=rheight/(2*JUDGETIMES),rightnum=0;i<rheight;i+=dj)
	{
		//得到一行数据
		UINT tx=PointArray[i].x+dx,ty=PointArray[i].y+dy;
		if(tx<0) tx=0;
		if(tx>dImageWidth-1) tx=dImageWidth-1;
		if(ty<0) ty=0;
		if(ty>dImageHeight-1) ty=dImageHeight-1;
		int rwidth=GetLineDataB(PointArray[i].x,PointArray[i].y,tx,ty,BWArray);
		//得到起始符位置
		for(int k=0;k<rwidth;k++)
			if(BWArray[k]>8) break;
		//得出一个模块宽
		double onewidth = (double)(BWArray[k]+1)/8;
		rwidth=(rwidth>8?8:rwidth);
		for(int j=k;j<rwidth;j++)
		{
			if(abs((int)(((double)BWArray[j]/onewidth)-HeaderShape[j-k]))>=1)
				break;
		}
		if(j==rwidth&&rwidth>=8) rightnum++;	//如果满足要求,则加一
		if(rightnum > JUDGETIMES/2) break;
	}
	delete[] PointArray;
	if(rightnum > JUDGETIMES/2) //如果正确的数据超过总判断数的1/2,则认为正确
	{
		*pReg = tmpreg;
		return true;
	}
	else if(firstjudge)
	{
		firstjudge = false;
		goto loop;
	}
	else
		return false;
}

//BWArray以BWBWBWBW的序列存放,如第一点不为B,则存入0
//所返回的数组中的每一元素均代表B/W的数目
UINT CStdDataObject::GetLineDataB(UINT xa, UINT ya, UINT xb, UINT yb, UCHAR* BWArray)
{
	int num=0;
	int dx=abs(xa-xb),dy=abs(ya-yb);
	int p=2*dy-dx;
	int pp=2*dx-dy; //++
	int twody=2*dy,twody_dx=2*(dy-dx);
	int twodx=2*dx,twodx_dy=2*(dx-dy);	//++
	int x,y,xend,yend;
	int count=0,flags='B',ArrNum=0; //ArrNum指示当前数组中所用元素的位置
									//count指示当前计数的B/W的数目
									//flags指示当前对什么进行计数B/W
	x=xa;y=ya;
	xend=xb;yend=yb;
	if(StdIsBlack(x,y))
		count++;
	else {
		flags='W';
		BWArray[ArrNum++]=count;
		count=1;
	}
	num++;
	if(dy>dx)
	{
		while(y>yend?y>yend:y<yend)
		{
			if(y>yend) y--;
			else y++;
			if(pp<0)
				pp+=twodx;
			else{
				if(xb>xa) x++;
				else x--;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -