📄 rlebitmap.cpp
字号:
/*
行压缩位图,带有图像轮廓信息
目前仅支持高彩色模式
.......... '.'代表透明像素
..AA......
.A...A....
..........
压缩为:
去掉顶行,末行和最左边一列
0201 0302 0000 代表轮廓
0301 0102 AAAA AAAA 0201 0301 0000
0101 AAAA 0203 0101 AAAA 0000
0301 0203 0301 0000 代表轮廓
源图80字节,压缩后40字节
*/
#include "gl.h"
//#include "gengine.h"
#define RLE_LINEEND 0x0000
#define RLE_PIXELS 0x0100
#define RLE_TRANS 0x0200
#define RLE_OUTLINE 0x0300
#define RLE_SIGNATURE 0x42454c52 //"RLEB"
#define RLE_OUTLINECOLOR 0xffe0ffe0 //轮廓的颜色
#define RLE_SHADOWCOLOR 0x0 //影子的颜色
/*
class RleBitmap{
public:
int colorDepth;
int x, y; //位置矫正
int width, height; //压缩后的大小
DWORD size; //像素数据量
char **line;
RleBitmap();
~RleBitmap();
};
*/
RleBitmap::RleBitmap()
{
width = height = 0;
line = NULL;
}
RleBitmap::~RleBitmap()
{
delete line;
}
void RleBitmap::ConvertFormat( int format )
{
if( format == colorDepth )
return;
short* data = (short*)line[0];
int lines = 0, i;
if( colorDepth == 15 && format == 16 ){
// OutDebugString( "rlebmp coverformat" );
while( lines < height ){
switch( *data & 0xff00 ){
case RLE_LINEEND:
lines ++;
data ++;
break;
case RLE_PIXELS:
i = *data & 0xff;
data ++;
for( ; i>0; i--, data++ )
*data = ((*data & 0x7fe0) << 1) | (*data & 0x1f);
break;
case RLE_TRANS:
case RLE_OUTLINE:
data ++;
break;
}
}
}
else if( colorDepth == 16 && format == 15 ){
}
else
return;
}
//存盘
int SaveRleBitmap( char *filename, RleBitmap *src )
{
FILE *fp = fopen( filename, "wb" );
if( fp == NULL )
return -1;
errno = 0;
DWORD signature = RLE_SIGNATURE;
DWORD temp;
fwrite( &signature, 1, 4, fp );
//写数据头
fwrite( &(src->size), sizeof(src->size), 1, fp );
fwrite( &(src->colorDepth), sizeof(src->colorDepth), 1, fp );
fwrite( &(src->x), sizeof(src->x), 1, fp );
fwrite( &(src->y), sizeof(src->y), 1, fp );
fwrite( &(src->width), sizeof(src->width), 1, fp );
fwrite( &(src->height), sizeof(src->height), 1, fp );
//写入每行像素的首地址相对于line[0]的偏移
for( int i=0; i<src->height; i++ ){
temp = src->line[i] - src->line[0];
fwrite( &temp, sizeof( DWORD ), 1, fp );
}
//写入像素数据
fwrite( src->line[0], 1, src->size, fp );
fclose( fp );
if( errno )
return -1;
return 0;
}
//从文件中读入
RleBitmap* LoadRleBitmap( char *fname )
{
File *fp;
fp = cfile.Open( fname );
if( fp == NULL )
return NULL;
DWORD signature;
RleBitmap* rle;
int i;
signature = fp->Getdw();
if( signature != RLE_SIGNATURE ){
fp->Close();
return NULL;
}
rle = new RleBitmap;
if( rle == NULL )
goto error;
//数据头
fp->Read( &(rle->size), sizeof(rle->size));
fp->Read( &(rle->colorDepth), sizeof(rle->colorDepth) );
fp->Read( &(rle->x), sizeof(rle->x));
fp->Read( &(rle->y), sizeof(rle->y));
fp->Read( &(rle->width), sizeof(rle->width));
fp->Read( &(rle->height), sizeof(rle->height));
//分配空间
rle->line = (char**) new char[ rle->height * sizeof(char*) + rle->size ];
if( rle->line == NULL )
goto error;
rle->line[0] = (char*)rle->line + rle->height * sizeof(char*);
//设置行指针
for( i=0; i<rle->height; i++ )
rle->line[i] = rle->line[0] + fp->Getdw();
//读入像素数据
fp->Read( rle->line[0], rle->size );
fp->Close();
return rle;
error:
delete rle;
fp->Close();
return NULL;
}
//进行压缩的辅助函数
//点(x,y)是否为轮廓上的点
static int IsOutlineEx( Bitmap *src, int x, int y )
{
#define CHECK( a, b ) ( ((WORD*)(src->line[a]))[b] == src->colorKey && \
(( a > 0 && ((WORD*)(src->line[a-1]))[b] != src->colorKey && ((WORD*)(src->line[a-1]))[b] != RLE_SHADOWCOLOR ) \
|| ( a < src->height-1 && ((WORD*)(src->line[a+1]))[b] != src->colorKey && ((WORD*)(src->line[a+1]))[b] != RLE_SHADOWCOLOR )))
if( CHECK( x, y ) && (( y > 0 && CHECK( x, y-1 )) || (y < src->width-1 && CHECK( x, y+1 ))))
return 1;
return 0;
}
static int IsOutline( Bitmap *src, int x, int y )
{
if( CHECK( x, y ) )
return 1;
return 0;
}
#undef CHECK
RleBitmap* CreateRleBitmap( Bitmap* src, int genOl = 1 ) // genOl是否产生轮廓
{
if( src == NULL || BYTES_PER_PIXEL(src->colorDepth) != 2 )
return NULL;
int i, j, counter;
int top, bottom, height, left, right, width;
WORD *data;
RleBitmap* rle = new RleBitmap;
if( rle == NULL )
return NULL;
right = 0;
left = src->width;
//搜索不全透明的最顶行
for( i=0; i<src->height; i++ )
for( j=0; j<src->width; j++ )
if( ((WORD*)(src->line[i]))[j] != src->colorKey )
goto top_found;
top_found:
if( i == src->height ){
return new RleBitmap;
}
top = i;
//搜索不全透明的最末行
for( i=src->height-1; i>=0; i-- )
for( j=0; j<src->width; j++ )
if( ((WORD*)(src->line[i]))[j] != src->colorKey )
goto bottom_found;
bottom_found:
bottom = i;
height = i - top + 3;
//搜索最左不透明像素
for( i=top; i<=bottom; i++ ){
for( j=0; ((WORD*)(src->line[i]))[j] == src->colorKey && j<left; j++ );
if( j < left ) left = j;
}
//创建rleBitmap
rle = new RleBitmap;
if( rle == NULL )
return NULL;
rle->line = (char**)new char[ sizeof( char* ) * height ];
if( rle->line == NULL ){
delete rle;
return NULL;
}
rle->line[0] = new char[ (src->width - left) * height * 4 ];
if( rle->line[0] == NULL ){
delete rle;
return NULL;
}
//压缩
data = (WORD*)(rle->line[0]);
//处理第一行
//搜索行末
if( genOl ){
for( i=src->width-1; (((WORD*)(src->line[top]))[i] == src->colorKey
|| ((WORD*)(src->line[top]))[i] == RLE_SHADOWCOLOR) && !IsOutlineEx( src, top, i ) && i > 0; i-- );
for( j=left; j<=i; ){
if( ((WORD*)(src->line[top]))[j] == src->colorKey || ((WORD*)(src->line[top]))[i] == RLE_SHADOWCOLOR ){
*data = RLE_TRANS;
while( (((WORD*)(src->line[top]))[j] == src->colorKey || ((WORD*)(src->line[top]))[i] == RLE_SHADOWCOLOR) && j<=i && *(char*)data < 255 ){
j ++; (*data) ++;
}
data ++;
}
else{
*data = RLE_OUTLINE;
while( ((WORD*)(src->line[top]))[j] != src->colorKey && j<=i && *(char*)data < 255 ){
j ++; (*data) ++;
}
data ++;
}
}
}
*(data++) = RLE_LINEEND;
i=IsOutline( src, 47, 54 );
//处理从第一行到最后一行的像素,包括第一行和最后一行
for( i=top; i<=bottom; i++ ){
rle->line[i-top+1] = (char*)data;
//搜索行末
for( j=src->width-1; ((WORD*)(src->line[i]))[j] == src->colorKey && (!genOl | !IsOutlineEx( src, i, j )) && j > 0; j-- );
if( j > right ) right = j;
width = j;
for( j=left; j<=width; ){
counter = 0;
if( ((WORD*)(src->line[i]))[j] == src->colorKey ){
if( genOl && IsOutlineEx(src, i, j) ){
*data = RLE_OUTLINE; //标志为轮廓
while( IsOutline( src, i, j ) && j <= width && counter < 255 ){
counter ++;
j++;
}
}
else{
*data = RLE_TRANS; //标志为透明
while( ((WORD*)(src->line[i]))[j] == src->colorKey && (!genOl | !IsOutlineEx( src, i, j )) && j <= width && counter < 255 ){
counter ++;
j ++;
}
}
(*data) += counter;
data ++;
}
else{
*data = RLE_PIXELS;
while( ((WORD*)(src->line[i]))[j] != src->colorKey && j <= width && counter < 255 ){
counter ++;
*(data+counter) = ((WORD*)(src->line[i]))[j];
j ++;
}
*data += counter;
data += counter + 1;
}
} // end of one line
*(data++) = RLE_LINEEND;
}
//处理最后一行
rle->line[ height-1 ] = (char*)data;
//搜索行末
if( genOl ){
for( i=src->width-1; (((WORD*)(src->line[bottom]))[i] == src->colorKey
|| ((WORD*)(src->line[bottom]))[i] == RLE_SHADOWCOLOR) && !IsOutlineEx( src, bottom, i ) && i > 0; i-- );
for( j=left; j<=i; ){
if( ((WORD*)(src->line[bottom]))[j] == src->colorKey || ((WORD*)(src->line[bottom]))[i] == RLE_SHADOWCOLOR ){
*data = RLE_TRANS;
while( (((WORD*)(src->line[bottom]))[j] == src->colorKey || ((WORD*)(src->line[bottom]))[i] == RLE_SHADOWCOLOR) && j<=i && *(char*)data < 255 ){
j ++; (*data) ++;
}
data ++;
}
else{
*data = RLE_OUTLINE;
while( ((WORD*)(src->line[bottom]))[j] != src->colorKey && j<=i && *(char*)data < 255 ){
j ++; (*data) ++;
}
data ++;
}
}
}
*(data++) = RLE_LINEEND;
rle->colorDepth = src->colorDepth;
rle->x = left;
rle->y = top - 1;
rle->width = right - left + 2; //比实际的大1
rle->height = height;
rle->size = (DWORD)data - (DWORD)(rle->line[0]);
rle->line[0] = (char*)realloc( rle->line[0], rle->size );
return rle;
}
#define RLE_CLIP \
int w = src->width; \
int h = src->height; \
int sx, sy; \
x += src->x; \
y += src->y; \
if( x >= dest->cr || y >= dest->cb ) \
return; \
\
if( x < dest->cl ){ \
sx = dest->cl - x; x = dest->cl; w -= sx; \
if( w <= 0 ) return; \
} \
else sx = 0; \
if( y < dest->ct ){ \
sy = dest->ct - y; y = dest->ct; h -= sy; \
if( h <= 0 ) return; \
} \
else sy = 0; \
if( x + w > dest->cr ) \
w = dest->cr - x; \
if( y + h > dest->cb ) \
h = dest->cb - y;
//no outline
void RleBitmapBlit( Bitmap* dest, int x, int y, RleBitmap* src )
{
RLE_CLIP;
int pitch, dptr;
char** sline = &(src->line[sy]);
pitch = dest->pitch;
__asm{
mov ebx, y;
cld;
mov ecx, sline;
mov eax, dest;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -