有一个16X16的bmp图片,用工具 convert.exe转换后,数据是:
{
0,80,80,80,80,80,80,80,80,80,80,80,78,80,80,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}发现用16*2个值就能保存该图片。
但我不知道区中的编码是怎莫来的。
请教!!!。
算法怎莫学的???分不够可加。
{
0,80,80,80,80,80,80,80,80,80,80,80,78,80,80,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
}发现用16*2个值就能保存该图片。
但我不知道区中的编码是怎莫来的。
请教!!!。
算法怎莫学的???分不够可加。
这个数据是保存下来是什么格式啊?保存下来txt可以打开吗?
然后把txt另存为*.bmp能回复到图片么?学习
0a xx xx xx
a 个单独的颜色点1a bb xx xx xx
abb 个单独的颜色点Da bb
abb 个透明色Ca
a 个透明色8a xx
a 个颜色是XX的点9a xx bb
abb 个颜色为xx的点Aa xx bb cc
abbcc 个颜色为xx的点其他情况,没有压缩基本上超过3个点一样就用8a xx 了这个是我自己写的压缩bmp的算法,传奇3的图象资源的处理代码,很烂;处理的是565格式;var
STM: TMemorystream;
i,fwidth,fheight: Integer;
offset: dword;
ilen: dword;
DTM: TMemoryStream;
Buffer: array of WORD;
DnyArray: Array of WORD;
abyte: array[0..8] of Byte;
function CompressToWil: Integer;
var
Count : Integer;
i, J, Idx, bakIdx: integer;
begin
I := 0;
Idx := 0; // Count := 0;// bakIdx := 0;
Setlength(DnyArray, High(Buffer) * 2);
while i <= High(Buffer) do
begin
if buffer[i] = 63519 then
begin
DnyArray[Idx] := $C0;
Inc(Idx, 1);
Count := 0;
for j := i to High(Buffer) do
begin
if buffer[j] = 63519 then
begin
Inc(Count);
end
else
break;
end;
DnyArray[Idx] := count;
i := j;
Inc(Idx, 1);
end
else
begin
DnyArray[Idx] := $C1;
Inc(Idx, 1);
bakIdx := Idx;
Count := 0;
for j := i to High(Buffer) do
begin
if buffer[j] <> 63519 then
begin
Inc(Count);
Inc(Idx);
DnyArray[Idx] := buffer[j];
end
else
break;
end;
DnyArray[bakIdx] := Count;
i := j;
Inc(Idx);
end;
end;
setLength(DnyArray, Idx);
result := Idx;
end;
procedure makeByte(streamSize:DWORD);
var
HexStr : string;
iC : Integer;
a, b, c, d : string;
begin
HexStr := Format('%8x', [streamSize]);
for iC := 1 to Length(HexStr) do
if HexStr[iC] = #32 then
HexStr[iC] := '0';
a := HexStr[1] + HexStr[2]; //12
b := HexStr[3] + HexStr[4]; //34
c := HexStr[5] + HexStr[6]; //56
d := HexStr[7] + HexStr[8]; //78
abyte[0] := FImageHandle.X[0];
abyte[1] := FImageHandle.X[1];
abyte[2] := FImageHandle.X[2];
abyte[3] := FImageHandle.X[3];
abyte[4] := FImageHandle.X[4];
abyte[5] := StrToInt('$' + d);
abyte[6] := StrToInt('$' + c);
abyte[7] := StrToInt('$' + b);
abyte[8] := StrToInt('$' + a);
end;
begin
if (FbitMap.Empty) then Exit; //如果为空数据则退出过程
if not FImageChange then Exit;
FRLTStream.Clear;
STM := TMemoryStream.Create; //压缩前
DTM := TMemoryStream.Create; //压缩后
try
FlipImg(FBitmap); //反转
FbitMap.SaveToStream(STM);
FlipImg(FBitmap); //还原
fwidth := Fbitmap.Width;
fheight := FBitmap.Height;
offset := 66;
stm.Seek(offset, 0);
setLength(Buffer, fwidth); //设置 本次的缓冲区尺寸
FImageHandle.Px := FOffsetX;
FImageHandle.Py := FOffsetY;
ilen:=0;
DTM.seek(0,0);
DTM.Write(FImageHandle,12);
DTM.Write(iLen,1);
DTM.write(FImageSize,4);
DTM.Write(iLen,1);
DTM.Seek(17,0);
for i := 0 to fheight - 1 do
begin
stm.Read(Buffer[0], fwidth * 2); //取出 数据到 图像缓冲区
iLen := CompressToWil;
DTM.Write(iLen, 2);
DTM.write(DnyArray[0], iLen*2);
end;
iLen :=((DTM.Size-17) div 2);
dtm.seek(offset + 8,0);
makeByte(iLen);
dtm.Write(abyte[0],9);
dtm.seek(0,0);
FRLTStream.CopyFrom(dtm,dtm.size);
FRLTStream.Seek(0,0);
FImageChange :=false;
finally
stm.Free;
dtm.Free;
end;
end;这个是解压算法
//计算数据偏移地址
offset := offset + headlen;
for i := 0 to FImageHandle.height - 1 do
begin
f.Seek(offset, 0); //定位当前位置
f.Read(tmpWord, 2); //读出本行数据长度 00C1,00C0
fw := Tmpword; //得到宽度
setlength(imgbuff, fw + 1); //设置 本次的缓冲区尺寸
f.Read(imgbuff[0], fw * 2); //取出 数据到 图像缓冲区
j := 0;
while j < fw do //定位到开始
begin
case imgbuff[j] of //
$C0: //192
begin
j := J + 1;
tmpWord := 63519; //0;
for n := 0 to imgbuff[j] - 1 do
imageStream.Write(tmpword, sizeOf(word));
j := J + 1;
end;
$C1, $C2: //193, 194:
begin
j := j + 2;
imageStream.Write(imgBuff[j], imgbuff[j - 1] * sizeof(word));
j := j + imgbuff[j - 1];
end;
end;
end;
offset := offset + fw * 2 + 2;
end;
bmp的压缩编码我也看了一下,没看出跟楼主给出的东东有啥联系……
他那里面咋全是80?
这样转化成exe后不知道打开图片质量会不会变差
至于压缩后怎么来的这样格式
楼主要看看bmp的形成机理和内在构成
---------------------------------------
http://purec.binghua.com/Article/SoftAndHardResourse/FileFormat/200410/280.html
----------------------------------------------------------
目前出现很多别具特色的图像显示程序, 其中一种特
殊的处理功能就是把图像文件如BMP、GIF等文件直接转换
为.EXE可执行文件, 实际上如果了解了图像显示的一般原
理, 即可以轻松的完成这种文件转换功能。下面以显示16
色BMP 图像为例, 编制一个BMP2EXE转换程序。
一、基本原理:完成此操作的基本过程, 就是在图形
文件的头部加上一段具有图像显示能力的程序段, 当运行
合并后的程序时,打开此文件本身,并移动文件指针到图像
数据段,依次读出内容显示即可。所以一个完整的BMP2COM
程序内部, 应该同时具有显示图像功能及合并文件的功能,
其中的合并文件功能负责把其中的显示图像程序段与图像
文件进行合并处理, 而显示图像功能只有在合并后的 EXE
文件运行时才能得到执行。
二、文件指针的调整问题: 当进行图像显示时, 必须
把文件指针移到正确位置,即跳过显示程序段部分,但由于
程序调试时显示程序段长度是不定的, 无法确定具体的数
值,此时可以采取一种动态记录显示程序段的方法,即合并
显程序与图像文件时, 把显示程序长度记录在合并后程序
的未尾, 运行转换后的可执行文件时, 首先从文件尾部读
出显示程序长度, 即可移到正确位置。另外程序的显示模
式号,及屏幕起始坐标等均采用此方法进行保存和读取。
三、程序使用方法:此程序运行时需要携带两个或二
个以上参数, 段如程序名为BMP2EXE.EXE,则命令格式:
BMP2EXE Source Target Mode Row Col
其中Source为原图像文件内容, Target为转换后的目
标文件名, 后缀必须为EXE, MODE为所使用的显示模式,可
为系统支持的任意16色以上图像模式, 用16进制表示,ROW
及COL 为图像在屏幕上的起始坐标值, 以象素为单位, 可
为256 以内的10进制数值, 主要用于调整图像在屏幕上的
具体位置, 其中显示模式及坐标均可省略, 省略时使用系
统的12H 图像模式, 并从屏幕的始端开始显示图像。转换
之后所产生的EXE 文件即可以单独运行, 运行之后即可以
把当前屏幕置为相应的显示模式, 并在指定的位置显示图
像。本文仅演示了16色BMP 图像的显示过程, 可扩充其
中的图像显示过程, 使之可处理真彩色图像或其它格式的
图像文件。
//BMP图像转换为可执行文件
//适用于16色BMP图像文件
#include <dos.h>
#include <dir.h>
#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
void setmod(int videomode);
void putp(int x,int y,int color);
union REGS r;
void main(int argc,char * argv[])
{
struct ffblk f;
register int done;
int gd,gm,cl,wl,ll,kuan,il,iw,row,col;
long prglen;
char cc,vmode,*end;
FILE *exe,*me,*bmp,*fp;
static int color[16]={0,4,2,6,1,5,3,8,7,12,10,14,9,13,11,15};
if(argc>1){ //合并文件段
findfirst(argv[0],&f,55); //取文件长度值
prglen=f.ff_fsize;
me=fopen(argv[0],"rb"); //打开相关文件
exe=fopen(argv[2],"wb");
if(exe==NULL){
printf("Target File Open Error!");exit(0);}
bmp=fopen(argv[1],"rb");
if(bmp==NULL){
printf("Source File Open Error!");exit(0);}
while(1){ //读写显示程序
cc=fgetc(me);
if(!feof(me))
fputc(cc,exe);else break; }
while(1){ //读写图像文件
cc=fgetc(bmp);
if(!feof(bmp))
fputc(cc,exe);else break; }
if(argc>3){
cc=strtol(argv[3],&end,16); //写显示模式号
fputc(cc,exe);}else{
cc=0x12;
fputc(cc,exe);}
if(argc>4){ //写起始横坐标
cc=atoi(argv[4]);
fputc(cc,exe); }else{
cc=0;
fputc(cc,exe); }
if(argc>5){ //写起始纵坐标
cc=atoi(argv[5]);
fputc(cc,exe); }else{
cc=0;
fputc(cc,exe); }
r.x.ax=prglen; //写原始文件长度
cc=r.h.ah;
fputc(cc,exe);
cc=r.h.al;
fputc(cc,exe);
cc=0x55; //写文件识别标志
fputc(cc,exe);
fclose(me);
fclose(exe);
fclose(bmp); //关闭相关文件
printf("Please Disp <%s>",argv[2]);
exit(0);}
else //显示文件段
fp=fopen(argv[0],"rb");
findfirst(argv[0],&f,55); //取文件长度值
prglen=f.ff_fsize;
fseek(fp,prglen-1,SEEK_SET);//移文件指针
cc=fgetc(fp);
if(cc!=0x55){ //判断文件标志
printf("\\nHELP:\\7"); //提示信息
printf("\\nBMP2EXE Source Target Mode Row Col.");
exit(0);}else
fseek(fp,prglen-6,SEEK_SET);
vmode=fgetc(fp); //取显示模式
row=fgetc(fp); //取起始横坐标
col=fgetc(fp); //取起始纵坐标
r.h.ah=fgetc(fp); //取文件长度
r.h.al=fgetc(fp);
prglen=r.x.ax; //移到图形数据段
fseek(fp,prglen+18,SEEK_SET);
fread(&kuan,4,1,fp);
wl=kuan; //图像宽度
fread(&kuan,4,1,fp);
ll=kuan; //图像高度
fseek(fp,prglen+118,SEEK_SET);
setmod(vmode); //置显示模式
for(il=0;il<ll;il++) //显示第一遍
for(iw=0;iw<wl;iw++){
fread(&kuan,1,1,fp);
cl=(kuan&0xf0)>>4;
putp(row+iw,col+ll-il,color[cl]);
iw=iw+1;}
fseek(fp,prglen+118,SEEK_SET);
for(il=0;il<ll;il++) //显示第二遍
for(iw=0;iw<wl;iw++){
fread(&kuan,1,1,fp);
iw=iw+1;
cl=kuan&0x0f;
putp(row+iw,col+ll-il,color[cl]);}
getch(); //程序暂停
fclose(fp); //关闭文件
setmod(0x3); } //恢复文本模式
void setmod(int videomode)
{ //置显示模式函数
r.h.ah=0;
r.h.al=videomode;
int86(0x10,&r,&r);}
void putp(int x,int y,int color)
{r.h.al=color; //写点函数
r.h.ah=0x0c;
r.h.bh=0;
r.x.cx=x;
r.x.dx=y;
int86(0x10,&r,&r);}