📄 ximagif.cpp
字号:
if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;}
if (bPreviousWasNull || ch==0)
{
switch (ch)
{
case '!': // extension
{
DecodeExtension(fp);
break;
}
case ',': // image
{
assert(sizeof(image) == 9);
//log << "Image header" << endl;
fp->Read(&image,sizeof(image),1);
//avoid byte order problems with Solaris <candan> <AMSN>
image.l = ntohs(image.l);
image.t = ntohs(image.t);
image.w = ntohs(image.w);
image.h = ntohs(image.h);
// in case of images with empty screen descriptor, give a last chance
if (dscgif->scrwidth==0 && dscgif->scrheight==0){
dscgif->scrwidth = image.w;
dscgif->scrheight = image.h;
}
if (((image.l + image.w) > dscgif->scrwidth)||((image.t + image.h) > dscgif->scrheight))
break;
nframes++;
// Local colour map?
if (image.pf & 0x80) {
TempTabCol.sogct = (short)(1 << ((image.pf & 0x07) +1));
assert(3 == sizeof(struct rgb_color));
fp->Read(TempTabCol.paleta,sizeof(struct rgb_color)*TempTabCol.sogct,1);
//log << "Local colour map" << endl;
}
int badcode=0;
ibf = GIFBUFTAM+1;
interlaced = image.pf & 0x40;
iheight = image.h;
istep = 8;
iypos = 0;
ipass = 0;
long pos_start = fp->Tell();
//if (interlaced) log << "Interlaced" << endl;
decoder(fp, 0, image.w, badcode);
if (badcode){
seek_next_image(fp,pos_start);
} else {
fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR);
}
break;
}
case ';': //terminator
bContinue=false;
break;
default:
bPreviousWasNull = (ch==0);
break;
}
}
}
fp->Seek(pos,SEEK_SET);
return nframes;
}
////////////////////////////////////////////////////////////////////////////////
long CxImageGIF::seek_next_image(CxFile* fp, long position)
{
fp->Seek(position, SEEK_SET);
char ch1,ch2;
ch1=ch2=0;
while(fp->Read(&ch2,sizeof(char),1)>0){
if (ch1 == 0 && ch2 == ','){
fp->Seek(-1,SEEK_CUR);
return fp->Tell();
} else {
ch1 = ch2;
}
}
return -1;
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::SetLoops(int loops)
{ m_loops=loops; }
////////////////////////////////////////////////////////////////////////////////
long CxImageGIF::GetLoops()
{ return m_loops; }
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::SetComment(const char* sz_comment_in)
{ if (sz_comment_in) strncpy(m_comment,sz_comment_in,255); }
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::GetComment(char* sz_comment_out)
{ if (sz_comment_out) strncpy(sz_comment_out,m_comment,255); }
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::GifMix(CxImage & imgsrc2, struct_image & imgdesc)
{
long ymin = max(0,(long)(GetHeight()-imgdesc.t - imgdesc.h));
long ymax = GetHeight()-imgdesc.t;
long xmin = imgdesc.l;
long xmax = min(GetWidth(), (DWORD)(imgdesc.l + imgdesc.w));
long ibg2= imgsrc2.GetTransIndex();
BYTE i2;
for(long y = ymin; y < ymax; y++){
for(long x = xmin; x < xmax; x++){
i2 = imgsrc2.GetPixelIndex(x-xmin,y-ymin);
if(i2!=ibg2) SetPixelIndex(x,y,i2);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/*-----------------------------------------------------------------------
*
* miGIF Compression - mouse and ivo's GIF-compatible compression
*
* -run length encoding compression routines-
*
* Copyright (C) 1998 Hutchison Avenue Software Corporation
* http://www.hasc.com
* info@hasc.com
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. This software is provided "AS IS." The Hutchison Avenue
* Software Corporation disclaims all warranties, either express or implied,
* including but not limited to implied warranties of merchantability and
* fitness for a particular purpose, with respect to this code and accompanying
* documentation.
*
* The miGIF compression routines do not, strictly speaking, generate files
* conforming to the GIF spec, since the image data is not LZW-compressed
* (this is the point: in order to avoid transgression of the Unisys patent
* on the LZW algorithm.) However, miGIF generates data streams that any
* reasonably sane LZW decompresser will decompress to what we want.
*
* miGIF compression uses run length encoding. It compresses horizontal runs
* of pixels of the same color. This type of compression gives good results
* on images with many runs, for example images with lines, text and solid
* shapes on a solid-colored background. It gives little or no compression
* on images with few runs, for example digital or scanned photos.
*
* der Mouse
* mouse@rodents.montreal.qc.ca
* 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
*
* ivo@hasc.com
*
* The Graphics Interchange Format(c) is the Copyright property of
* CompuServe Incorporated. GIF(sm) is a Service Mark property of
* CompuServe Incorporated.
*
*/
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_clear(struct_RLE* rle)
{
rle->out_bits = rle->out_bits_init;
rle->out_bump = rle->out_bump_init;
rle->out_clear = rle->out_clear_init;
rle->out_count = 0;
rle->rl_table_max = 0;
rle->just_cleared = 1;
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_flush(struct_RLE* rle)
{
if (rle->rl_count == 1){
rle_output_plain(rle->rl_pixel,rle);
rle->rl_count = 0;
return;
}
if (rle->just_cleared){
rle_flush_fromclear(rle->rl_count,rle);
} else if ((rle->rl_table_max < 2) || (rle->rl_table_pixel != rle->rl_pixel)) {
rle_flush_clearorrep(rle->rl_count,rle);
} else {
rle_flush_withtable(rle->rl_count,rle);
}
rle->rl_count = 0;
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_output_plain(int c,struct_RLE* rle)
{
rle->just_cleared = 0;
rle_output(c,rle);
rle->out_count++;
if (rle->out_count >= rle->out_bump){
rle->out_bits ++;
rle->out_bump += 1 << (rle->out_bits - 1);
}
if (rle->out_count >= rle->out_clear){
rle_output(rle->code_clear,rle);
rle_clear(rle);
}
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_flush_fromclear(int count,struct_RLE* rle)
{
int n;
rle->out_clear = rle->max_ocodes;
rle->rl_table_pixel = rle->rl_pixel;
n = 1;
while (count > 0){
if (n == 1){
rle->rl_table_max = 1;
rle_output_plain(rle->rl_pixel,rle);
count --;
} else if (count >= n){
rle->rl_table_max = n;
rle_output_plain(rle->rl_basecode+n-2,rle);
count -= n;
} else if (count == 1){
rle->rl_table_max ++;
rle_output_plain(rle->rl_pixel,rle);
count = 0;
} else {
rle->rl_table_max ++;
rle_output_plain(rle->rl_basecode+count-2,rle);
count = 0;
}
if (rle->out_count == 0) n = 1; else n ++;
}
rle_reset_out_clear(rle);
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_reset_out_clear(struct_RLE* rle)
{
rle->out_clear = rle->out_clear_init;
if (rle->out_count >= rle->out_clear){
rle_output(rle->code_clear,rle);
rle_clear(rle);
}
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_flush_withtable(int count, struct_RLE* rle)
{
int repmax;
int repleft;
int leftover;
repmax = count / rle->rl_table_max;
leftover = count % rle->rl_table_max;
repleft = (leftover ? 1 : 0);
if (rle->out_count+repmax+repleft > rle->max_ocodes){
repmax = rle->max_ocodes - rle->out_count;
leftover = count - (repmax * rle->rl_table_max);
repleft = 1 + rle_compute_triangle_count(leftover,rle->max_ocodes);
}
if (1+rle_compute_triangle_count(count,rle->max_ocodes) < (unsigned int)(repmax+repleft)){
rle_output(rle->code_clear,rle);
rle_clear(rle);
rle_flush_fromclear(count,rle);
return;
}
rle->out_clear = rle->max_ocodes;
for (;repmax>0;repmax--) rle_output_plain(rle->rl_basecode+rle->rl_table_max-2,rle);
if (leftover){
if (rle->just_cleared){
rle_flush_fromclear(leftover,rle);
} else if (leftover == 1){
rle_output_plain(rle->rl_pixel,rle);
} else {
rle_output_plain(rle->rl_basecode+leftover-2,rle);
}
}
rle_reset_out_clear(rle);
}
////////////////////////////////////////////////////////////////////////////////
unsigned int CxImageGIF::rle_compute_triangle_count(unsigned int count, unsigned int nrepcodes)
{
unsigned int perrep;
unsigned int cost;
cost = 0;
perrep = (nrepcodes * (nrepcodes+1)) / 2;
while (count >= perrep){
cost += nrepcodes;
count -= perrep;
}
if (count > 0){
unsigned int n;
n = rle_isqrt(count);
while ((n*(n+1)) >= 2*count) n --;
while ((n*(n+1)) < 2*count) n ++;
cost += n;
}
return(cost);
}
////////////////////////////////////////////////////////////////////////////////
unsigned int CxImageGIF::rle_isqrt(unsigned int x)
{
unsigned int r;
unsigned int v;
if (x < 2) return(x);
for (v=x,r=1;v;v>>=2,r<<=1) ;
for( ;; )
{
v = ((x / r) + r) / 2;
if ((v == r) || (v == r+1)) return(r);
r = v;
}
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_flush_clearorrep(int count, struct_RLE* rle)
{
int withclr;
withclr = 1 + rle_compute_triangle_count(count,rle->max_ocodes);
if (withclr < count) {
rle_output(rle->code_clear,rle);
rle_clear(rle);
rle_flush_fromclear(count,rle);
} else {
for (;count>0;count--) rle_output_plain(rle->rl_pixel,rle);
}
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_write_block(struct_RLE* rle)
{
g_outfile->PutC((BYTE)rle->oblen);
g_outfile->Write(rle->oblock,1,rle->oblen);
rle->oblen = 0;
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_block_out(unsigned char c, struct_RLE* rle)
{
rle->oblock[rle->oblen++] = c;
if (rle->oblen >= 255) rle_write_block(rle);
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_block_flush(struct_RLE* rle)
{
if (rle->oblen > 0) rle_write_block(rle);
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_output(int val, struct_RLE* rle)
{
rle->obuf |= val << rle->obits;
rle->obits += rle->out_bits;
while (rle->obits >= 8){
rle_block_out((unsigned char)(rle->obuf&0xff),rle);
rle->obuf >>= 8;
rle->obits -= 8;
}
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::rle_output_flush(struct_RLE* rle)
{
if (rle->obits > 0) rle_block_out((unsigned char)(rle->obuf),rle);
rle_block_flush(rle);
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::compressRLE( int init_bits, CxFile* outfile)
{
g_init_bits = init_bits;
g_outfile = outfile;
struct_RLE rle;
rle.code_clear = 1 << (init_bits - 1);
rle.code_eof = rle.code_clear + 1;
rle.rl_basecode = rle.code_eof + 1;
rle.out_bump_init = (1 << (init_bits - 1)) - 1;
rle.out_clear_init = (init_bits <= 3) ? 9 : (rle.out_bump_init-1);
rle.out_bits_init = init_bits;
rle.max_ocodes = (1 << MAXBITSCODES) - ((1 << (rle.out_bits_init - 1)) + 3);
rle.rl_count = 0;
rle_clear(&rle);
rle.obuf = 0;
rle.obits = 0;
rle.oblen = 0;
rle_output(rle.code_clear,&rle);
int c;
for( ;; )
{
c = GifNextPixel();
if ((rle.rl_count > 0) && (c != rle.rl_pixel)) rle_flush(&rle);
if (c == EOF) break;
if (rle.rl_pixel == c){
rle.rl_count++;
} else {
rle.rl_pixel = c;
rle.rl_count = 1;
}
}
rle_output(rle.code_eof,&rle);
rle_output_flush(&rle);
}
////////////////////////////////////////////////////////////////////////////////
#endif // CXIMAGE_SUPPORT_GIF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -