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

📄 jpegdecode.pas

📁 用于jpeg文件解码的delphi源代码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
unit JpegDecode;

interface
 uses   Windows,SysUtils,Classes,WinTypes;
const
  FUNC_OK= 0;
  FUNC_MEMORY_ERROR = 1;
  FUNC_FILE_ERROR = 2 ;
  FUNC_FORMAT_ERROR = 3;
  M_SOF0 = $c0;
  M_DHT = $c4;
  M_EOI = $d9;
  M_SOS = $da;
  M_DQT = $db;
  M_DRI = $dd;
  M_APP0 = $e0;
  W1 = 2841; // 2048*sqrt(2)*cos(1*pi/16)
  W2 = 2676; // 2048*sqrt(2)*cos(2*pi/16)
  W3 = 2408; // 2048*sqrt(2)*cos(3*pi/16)
  W5 = 1609; // 2048*sqrt(2)*cos(5*pi/16)
  W6 = 1108; // 2048*sqrt(2)*cos(6*pi/16)
  W7 = 565;  // 2048*sqrt(2)*cos(7*pi/16)

  Zig_Zag:array[0..7,0..7] of integer =
          ((0,1,5,6,14,15,27,28),
  	   (2,4,7,13,16,26,29,42),
  	   (3,8,12,17,25,30,41,43),
  	   (9,11,18,24,31,40,44,53),
  	   (10,19,23,32,39,45,52,54),
  	   (20,22,33,38,46,51,55,60),
  	   (21,34,37,47,50,56,59,61),
  	   (35,36,48,49,57,58,62,63));

type
      PShortInt = ^ShortInt;
      PSmallInt = ^SmallInt;
      PLongInt = ^LongInt;
      PByte = ^Byte;
      PInt = ^integer;
      MyInt = array[0..7,0..7] of integer;

function  LoadJpegFile(JpegFileName:string;var pImg:Pointer):Boolean;
function  InitTag:integer;
procedure InitTable;
function  Decode:integer;
function  DecodeMCUBlock:integer;
function  HufBlock(dchufindex:Byte;achufindex:Byte):integer;
function  DecodeElement:integer;
procedure IQtIZzMCUComponent(flag:SmallInt);
procedure IQtIZzBlock(s:PSmallInt;d:PInt;flag:SmallInt);
procedure GetYUV(flag:SmallInt);
procedure StoreBuffer;
function  ReadByte:Byte;
procedure Initialize_Fast_IDCT;
procedure Fast_IDCT(var block:MyInt);
procedure idctrow(var blk:MyInt);
procedure idctcol(var blk:MyInt);

implementation
var
//////////////////////////////////////////////////
  ImgWidth :DWORD =0;
  ImgHeight:DWORD = 0;
  lpImgData:PChar;
  bf:BITMAPFILEHEADER;
  bi:BITMAPINFOHEADER;
//////////////////////////////////////////////////////////
  SampRate_Y_H,SampRate_Y_V:SmallInt;
  SampRate_U_H,SampRate_U_V:SmallInt;
  SampRate_V_H,SampRate_V_V:SmallInt;
  H_YtoU,V_YtoU,H_YtoV,V_YtoV:SmallInt;
  Y_in_MCU,U_in_MCU,V_in_MCU:SmallInt;
  lpJpegBuf:PChar;
  lp,lpPtr:PChar;
  qt_table:array[0..2,0..63] of SmallInt;
  comp_num:SmallInt;
  comp_index:array[0..3] of BYTE;
  YDcIndex,YAcIndex,UVDcIndex,UVAcIndex:BYTE;
  HufTabIndex:BYTE;
  YQtTable,UQtTable,VQtTable:PSmallInt;
  MyAnd:array[0..8] of BYTE =(0,1,3,7,$0f,$1f,$3f,$7f,$ff);
  code_pos_table,code_len_table:array[0..3,0..15] of SmallInt;
  code_value_table:array[0..3,0..255] of Word;
  huf_max_value,huf_min_value:array [0..3,0..15] of Word;
  BitPos,CurByte:SmallInt;
  rrun,vvalue:SmallInt;
  MCUBuffer:array[0..10*64-1] of SmallInt;
  QtZzMCUBuffer:array[0..10*64-1] of integer;
  BlockBuffer:array[0..63] of SmallInt;
  ycoef,ucoef,vcoef:SmallInt;
  IntervalFlag:Boolean;
  interval:SmallInt=0;
  Y,U,V:array[0..4*64-1] of integer;
  sizei,sizej:DWORD;
  restart:SmallInt;
  iclip:array[0..1023] of longint;
  LineBytes,NumColors:DWORD;

////////////////////////////////////////////////////////////////
function LoadJpegFile (JpegFileName:string;var pImg:Pointer):Boolean;
var
     fjpg:TFileStream;
     ImgSize:DWORD;
     JpegBufSize:DWORD;
     funcret:integer;
     lpImgDataTemp:PChar;
begin
        fjpg:=TFileStream.Create(JpegFileName,fmOpenRead); //将Jpeg文件读入内存
        JpegBufSize:=fjpg.Size;
        GetMem(lpJpegBuf,JpegBufSize);
        fjpg.Read(lpJpegBuf^,JpegBufSize);
        fjpg.Free;

	InitTable;
        funcret:=InitTag;
	if(funcret<>FUNC_OK) then        //初始化表头不成功
        begin
          FreeMem(lpJpegBuf,JpegBufSize);
          Result:=False;
	  Exit;
	end;
	bi.biSize:=sizeof(BITMAPINFOHEADER);  //定义BMP头
	bi.biWidth:=ImgWidth;
	bi.biHeight:=ImgHeight;
	bi.biPlanes:=1;
	bi.biBitCount:=24;
	bi.biClrUsed:=0;
	bi.biClrImportant:=0;
	bi.biCompression:=BI_RGB;
	NumColors:=0;
	LineBytes:=DWORD((bi.biWidth*bi.biBitCount+31) div 32 * 4);
	ImgSize:=LineBytes*DWORD(bi.biHeight); //变化后的图象空间
	bf.bfType:=$4d42;                     //'BM'
	bf.bfSize:=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+
                           NumColors*sizeof(RGBQUAD)+ImgSize;
	bf.bfOffBits:=DWORD(NumColors*sizeof(RGBQUAD)+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER));

        GetMem(lpImgData,bf.bfSize);  //分配变换后的存储空间
        lpImgDataTemp:=lpImgData;
        CopyMemory(lpImgDataTemp,@bf,sizeof(BITMAPFILEHEADER));
        lpImgDataTemp:=lpImgDataTemp+sizeof(BITMAPFILEHEADER);
        CopyMemory(lpImgDataTemp,@bi,sizeof(BITMAPINFOHEADER));
        lpPtr:=lpImgData+bf.bfOffBits;              //实际图象数据位置

	if((SampRate_Y_H=0) or (SampRate_Y_V=0)) then
        begin
                FreeMem(lpJpegBuf);
                FreeMem(lpImgData);
                Result:=False;
		Exit;
	end;

	funcret:=Decode;
	if(funcret=FUNC_OK) then        //解码成功
        begin
                Result:=True;
                pImg:=lpImgData;
                FreeMem(lpJpegBuf);
                Exit;
	end
	else
        begin
                FreeMem(lpImgData);
                FreeMem(lpJpegBuf);
                Result:=False;Exit;
	end;
end;
////////////////////////////////////////////////////////////////////////////////
function InitTag:integer;
var
	finish:Boolean;
	id:Byte;
	llength:SmallInt;
        i,j,k:SmallInt;
        huftab1,huftab2:SmallInt;
        huftabindex:SmallInt;
        hf_table_index:BYTE;
        qt_table_index:BYTE;
        comnum:BYTE;
	lptemp:PChar;
        ccount:SmallInt;

begin
        finish:=False;
        lp:=lpJpegBuf+2;//跳过两个字节SOI(0xFF,0xD8 Start of Image)

	while ( not finish) do
        begin

		id:=Byte((lp+1)^);  //取出低位字节(高位在前,低位在后)
		lp:=lp+2;       //跳过取出的字节
		case id  of
		M_APP0:   //JFIF APP0 segment marker (0xE0)
                begin
                       llength:=MAKEWORD(Byte((lp+1)^),Byte(lp^));//MAKEWORD 转换Motorlora 与 intel 数据格式
		       lp:=lp+llength;//Skip JFIF segment marker
                end;
		M_DQT:   //定义量化表(0xFF,0xDB)
                begin
			llength:=MAKEWORD(Byte((lp+1)^),Byte(lp^));//(量化表长度)
			qt_table_index:=(Byte((lp+2)^) and $0f);//量化表信息bit 0..3: QT 号(0..3, 否则错误)
                                          //bit 4..7: QT 精度, 0 = 8 bit, 否则 16 bit
                        lptemp:=lp+3;                  //n 字节的 QT, n = 64*(精度+1)
			if(llength<80)  then               //精度为 8 bit
                        begin
				for i:=0 to 63 do
                                begin
					qt_table[qt_table_index,i]:=SmallInt(lptemp^);
                                        inc(lptemp);
                                end;
			end
			else                         //精度为 16 bit
                        begin
				for i:=0 to 63 do
                                begin
                                	qt_table[qt_table_index,i]:=SmallInt(lptemp^);
                                        inc(lptemp);
                                end;
                                qt_table_index:=Byte(lptemp^) and $0f;
                                inc(lptemp);
  	         	      	for i:=0 to 63 do
                                begin
		      		        qt_table[qt_table_index,i]:=SmallInt(lptemp^);
                                        inc(lptemp);
                                end;
                        end;
  			lp:=lp+llength; //跳过量化表
                end;
		M_SOF0:   //帧开始 (baseline JPEG 0xFF,0xC0)
                begin
	 		llength:=MAKEWORD(Byte((lp+1)^),Byte(lp^));         //长度 (高字节, 低字节), 8+components*3
	 		ImgHeight:=MAKEWORD(Byte((lp+4)^),Byte((lp+3)^));//图片高度 (高字节, 低字节), 如果不支持 DNL 就必须 >0
	 		ImgWidth:=MAKEWORD(Byte((lp+6)^),Byte((lp+5)^)); //图片宽度 (高字节, 低字节), 如果不支持 DNL 就必须 >0
                        comp_num:=Byte((lp+7)^);                   //components 数量(1 byte), 灰度图是 1, YCbCr/YIQ 彩色图是 3, CMYK 彩色图是 4
	                if((comp_num<>1) and (comp_num<>3)) then
                        begin
	  			Result:=FUNC_FORMAT_ERROR;
                                Exit;
                        end;
			if(comp_num = 3)  then                  //YCbCr/YIQ 彩色图
                        begin
				comp_index[0]:=Byte((lp+8)^);          //component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q)
	  			SampRate_Y_H:=Byte((lp+9)^) shr 4;      //水平采样系数
				SampRate_Y_V:=Byte((lp+9)^) and $0f;    //水平采样系数
	  			YQtTable:=PSmallInt(@qt_table[Byte((lp+10)^)]); //通过量化表号取得量化表地址
                              ///  ShowMessage(IntToStr(YQtTable^));
				comp_index[1]:=Byte((lp+11)^);         //component id
				SampRate_U_H:=Byte((lp+12)^) shr 4;     //水平采样系数
	  			SampRate_U_V:=Byte((lp+12)^) and $0f;   //水平采样系数
	  			UQtTable:=PSmallInt(@qt_table[Byte((lp+13)^)]);  //通过量化表号取得量化表地址
	  			comp_index[2]:=Byte((lp+14)^);         //component id
	  			SampRate_V_H:=Byte((lp+15)^) shr 4;     //水平采样系数
	  			SampRate_V_V:=Byte((lp+15)^) and $0f;   //水平采样系数
				VQtTable:=PSmallInt(@qt_table[Byte((lp+16)^)]);   //通过量化表号取得量化表地址
	  		end
			else                                       //灰度图
                        begin
	  			comp_index[0]:=Byte((lp+8)^);
				SampRate_Y_H:=Byte((lp+9)^) shr 4;
	  			SampRate_Y_V:=Byte((lp+9)^) and $0f;
	  			YQtTable:=PSmallInt(@qt_table[Byte((lp+10)^)]);  //灰度图的量化表都一样

				comp_index[1]:=Byte((lp+8)^);
	  			SampRate_U_H:=1;
	  			SampRate_U_V:=1;
	  			UQtTable:=PSmallInt(@qt_table[Byte((lp+10)^)]);

				comp_index[2]:=Byte((lp+8)^);
				SampRate_V_H:=1;
	  			SampRate_V_V:=1;
	  			VQtTable:=PSmallInt(@qt_table[Byte((lp+10)^)]);
			end;
  			lp:=lp+llength;
                end;
		M_DHT:   //定义 Huffman Table(0xFF,0xC4)
                begin
			llength:=MAKEWORD(Byte((lp+1)^),Byte(lp^));       //长度 (高字节, 低字节)
			if (llength< $d0)    then               // Huffman Table信息 (1 byte)
                        begin
				huftab1:=SmallInt(Byte((lp+2)^) shr 4);     //huftab1=0,1(HT 类型,0 = DC 1 = AC)
		 		huftab2:=SmallInt(Byte((lp+2)^) and $0f);   //huftab2=0,1(HT 号  ,0 = Y  1 = UV)
				huftabindex:=huftab1*2+huftab2;           //0 = YDC 1 = UVDC 2 = YAC 3 = UVAC
		 		lptemp:=lp+3;
				for i:=0 to 15 do                     //16 bytes: 长度是 1..16 代码的符号数
                                begin
					code_len_table[huftabindex,i]:=SmallInt(lptemp^);//码长为
                                        inc(lptemp);                                //i的码字个数
                                end;
				j:=0;
				for i:=0 to 15 do             //得出HT的所有码字的对应值
                                begin
					if(code_len_table[huftabindex,i] <> 0)  then
                                        begin
						k:=0;
						while(k<code_len_table[huftabindex,i]) do
                                                begin
							code_value_table[huftabindex,k+j]:=SmallInt(lptemp^);
                                                        lptemp:=lptemp+1;
							k:=k+1;
						end;
						j:=j+k;
					end;
                                end;
				i:=0;
				while (code_len_table[huftabindex,i]=0) do //去掉代码的符号数为零
		 			i:=i+1;
				for j:=0 to i-1 do
                                begin
					huf_min_value[huftabindex,j]:=0;            //码长为j的最小码字
					huf_max_value[huftabindex,j]:=0;            //码长为j的最大码字
				end;
				huf_min_value[huftabindex,i]:=0;
				huf_max_value[huftabindex,i]:=code_len_table[huftabindex,i]-1;
				for j:=i+1 to 15 do
                                begin                                              //码长为j的最小码字与最大码字
					huf_min_value[huftabindex,j]:=(huf_max_value[huftabindex,j-1]+1) shl 1;
					huf_max_value[huftabindex,j]:=huf_min_value[huftabindex,j]+code_len_table[huftabindex,j]-1;
				end;
				code_pos_table[huftabindex,0]:=0; //码起始位置
				for j:=1 to 15 do
		  			code_pos_table[huftabindex,j]:=code_len_table[huftabindex,j-1]+code_pos_table[huftabindex,j-1];
		  		lp:=lp+llength;
			end  //if
			else
                        begin
	 			hf_table_index:=Byte((lp+2)^);
				lp:=lp+2;
				while (hf_table_index<> $ff) do
                                begin
					huftab1:=SmallInt(hf_table_index shr 4);     //huftab1=0,1
			 		huftab2:=SmallInt(hf_table_index and $0f);   //huftab2=0,1
					huftabindex:=huftab1*2+huftab2;
					lptemp:=lp;inc(lptemp);
					ccount:=0;
					for i:=0 to 15 do
                                        begin
                                        	code_len_table[huftabindex,i]:=SmallInt(lptemp^);
                                                inc(lptemp);
						ccount:=ccount+code_len_table[huftabindex,i];
					end;
					ccount:=ccount+17;
					j:=0;
					for i:=0 to 15 do
						if(code_len_table[huftabindex,i]<>0)   then
                                                begin
							k:=0;
							while(k<code_len_table[huftabindex,i]) do
							begin
								code_value_table[huftabindex,k+j]:=SmallInt(lptemp^);
                                                                inc(lptemp);
								inc(k);
							end;
							j:=j+k;
						end;
					i:=0;
					while (code_len_table[huftabindex,i]=0) do
						inc(i);
					for j:=0 to i-1 do
                                        begin
						huf_min_value[huftabindex,j]:=0;
						huf_max_value[huftabindex,j]:=0;
					end;
					huf_min_value[huftabindex,i]:=0;
					huf_max_value[huftabindex,i]:=code_len_table[huftabindex,i]-1;
					for j:=i+1 to 15 do
                                        begin
						huf_min_value[huftabindex,j]:=(huf_max_value[huftabindex,j-1]+1) shl 1;
						huf_max_value[huftabindex,j]:=huf_min_value[huftabindex,j]+code_len_table[huftabindex,j]-1;
					end;
					code_pos_table[huftabindex,0]:=0;
					for j:=1 to 15 do
						code_pos_table[huftabindex,j]:=code_len_table[huftabindex,j-1]+code_pos_table[huftabindex,j-1];
					lp:=lp+ccount;
					hf_table_index:=Byte(lp^);
				end;  //while
			end;  //else
                end;
		M_DRI: //定义重新开始间隔, 细节附后
                begin
			llength:=MAKEWORD(Byte((lp+1)^),Byte(lp^));
			restart:=MAKEWORD(Byte((lp+3)^),Byte((lp+2)^));
			lp:=lp+llength;
                end;
		M_SOS: //扫描行开始0xff, 0xda (SOS)
                begin
			llength:=MAKEWORD(Byte((lp+1)^),Byte(lp^));//长度 (高字节, 低字节),
			comnum:=Byte((lp+2)^);               //扫描行内组件的数量 (1 byte), 必须 >:= 1 , <:=4 (否则是错的) 通常是 3
		       	if(comnum<>comp_num)  then        //必须是 6+2*(扫描行内组件的数量)
                        begin
			     Result:=FUNC_FORMAT_ERROR;
                             Exit;
                        end;
                        lptemp:=lp+3;
			for i:=0 to comp_num-1 do
                        begin                   //每组件的信息
				if(Byte(lptemp^)=comp_index[0]) then
                                begin  //1 byte :Component id
					YDcIndex:=Byte((lptemp+1)^) shr 4;   //Y 使用的 Huffman 表
					YAcIndex:=(Byte((lptemp+1)^) and $0f) +2;
				end
				else
                                begin
					UVDcIndex:=Byte((lptemp+1)^) shr 4;   //U,V
					UVAcIndex:=(Byte((lptemp+1)^) and $0f) +2;
				end;
                                lptemp:=lptemp+2;
			end;  // for
			lp:=lp+llength;
			finish:=TRUE;
                end;

⌨️ 快捷键说明

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