📄 save_gif.c
字号:
// GIF Saver
// by Paul Bartrum
#include <allegro.h>
typedef struct
{
short base;
unsigned char new;
} LZW_STRING;
typedef struct
{
int pos;
int bit_pos;
unsigned char data[255];
} BUFFER;
void clear_speed_buffer(short *speed_buffer)
{
// clear speed buffer to -1
__asm__("csb_loop:\n"
"movl %%ecx, (%%eax)\n"
"addl %%edx, %%eax\n"
"decl %%ebx\n"
"jne csb_loop\n"
:
: "a" (speed_buffer), "b" (256 * 4096 / 2), "c" (-1), "d" (4)
: "memory");
}
void dump_buffer(BUFFER *b, PACKFILE *f)
{
int size;
size = b->pos;
if(b->bit_pos != 0)
size ++;
pack_putc(size, f);
pack_fwrite(b->data, size, f);
}
void output(BUFFER *b, int bit_size, int code, PACKFILE *f)
{
int shift;
// pack the code into the buffer
shift = b->bit_pos;
do {
if(shift >= 0) {
if(b->bit_pos != 0)
b->data[b->pos] = (unsigned char)((code << shift) | b->data[b->pos]);
else
b->data[b->pos] = (unsigned char)(code << shift);
}
else {
if(b->bit_pos != 0)
b->data[b->pos] = (unsigned char)((code >> -shift) | b->data[b->pos]);
else
b->data[b->pos] = (unsigned char)(code >> -shift);
}
if(bit_size + shift > 7) {
b->bit_pos = 0;
b->pos ++;
shift -= 8;
if(b->pos == 255) {
dump_buffer(b, f);
b->pos = 0;
b->bit_pos = 0;
}
if(bit_size + shift <= 0)
break;
}
else {
b->bit_pos = bit_size + shift;
break;
}
} while(TRUE);
}
int save_gif(char *filename, BITMAP *bmp, RGB *pal)
{
PACKFILE *f;
int i, bpp, bit_size;
LZW_STRING string_table[4096];
int prefix;
int input_pos = 0;
int c; // current character
int empty_string;
BUFFER buffer;
short *speed_buffer;
f = pack_fopen(filename, F_WRITE);
if (!f)
return errno;
pack_mputl(0x47494638, f); // GIF8
pack_mputw(0x3761, f); // 7a
pack_iputw(bmp->w, f); // width
pack_iputw(bmp->h, f); // height
pack_putc(215, f); // packed fields
pack_putc(0, f); // background colour
pack_putc(0, f); // pixel aspect ratio
// global colour table
for(i = 0; i < 256; i ++) {
pack_putc(pal[i].r << 2, f);
pack_putc(pal[i].g << 2, f);
pack_putc(pal[i].b << 2, f);
}
pack_putc(0x2c, f); // image separator
pack_iputw(0, f); // x offset
pack_iputw(0, f); // y offset
pack_iputw(bmp->w, f); // width
pack_iputw(bmp->h, f); // height
pack_putc(0, f); // packed fields
// Image data starts here
bpp = 8;
pack_putc(bpp, f); // initial code size
// initialize string table
for(i = 0; i < 1 << bpp; i ++) {
string_table[i].base = -1;
string_table[i].new = i;
}
for(; i < (1 << bpp) + 2; i ++) {
string_table[i].base = -1;
string_table[i].new = -1;
}
empty_string = (1 << bpp) + 2;
prefix = -1;
bit_size = bpp + 1;
buffer.pos = 0;
buffer.bit_pos = 0;
output(&buffer, bit_size, 1 << bpp, f); // clear code
speed_buffer = malloc(256 * 4096 * 2);
clear_speed_buffer(speed_buffer);
while(TRUE) {
if((c = getpixel(bmp, input_pos % bmp->w, input_pos / bmp->w)) == EOF) {
output(&buffer, bit_size, prefix, f);
output(&buffer, bit_size, (1 << bpp) + 1, f); // end of information
dump_buffer(&buffer, f);
pack_putc(0, f); // no more data blocks
break;
}
input_pos ++;
//i = search_table(string_table, prefix, c, empty_string);
//i = quick_search_table(string_table, prefix, c, empty_string, speed_buffer);
if(prefix == -1)
i = c;
else
i = speed_buffer[prefix * 256 + c];
if(i != -1) {
prefix = i;
}
else {
// add prefix + c to string table
string_table[empty_string].base = prefix;
string_table[empty_string].new = c;
//if(prefix < 512)
speed_buffer[prefix * 256 + c] = empty_string;
empty_string ++;
// output code for prefix
output(&buffer, bit_size, prefix, f);
if(empty_string == (1 << bit_size) + 1)
bit_size ++;
// make sure string table doesn't overflow
if(empty_string == 4095) {
output(&buffer, bit_size, 1 << bpp, f); // clear code
empty_string = (1 << bpp) + 2;
bit_size = bpp + 1;
clear_speed_buffer(speed_buffer);
}
// set prefix to c
prefix = c;
}
}
free(speed_buffer);
pack_putc(0x3b, f); // trailer (end of gif)
pack_fclose(f);
return errno;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -