📄 jpegdecode.pas
字号:
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 + -