📄 ximagif.cpp
字号:
/* Continue reading codes until we get a non-clear code
* (Another unlikely, but possible case...)
*/
while ((c = get_next_code(file)) == clear);
/* If we get an ending code immediately after a clear code
* (Yet another unlikely case), then break out of the loop.
*/
if (c == ending) break;
/* Finally, if the code is beyond the range of already set codes,
* (This one had better NOT happen... I have no idea what will
* result from this, but I doubt it will look good...) then set it
* to color zero.
*/
if (c >= slot) c = 0;
oc = fc = c;
/* And let us not forget to put the char into the buffer... And
* if, on the off chance, we were exactly one pixel from the end
* of the line, we have to send the buffer to the out_line()
* routine...
*/
*bufptr++ = (BYTE)c;
if (--bufcnt == 0) {
if ((ret = (short)out_line(iter, buf, linewidth)) < 0) {
delete[] buf;
return(ret);
}
bufptr = buf;
bufcnt = linewidth;
}
} else {
/* In this case, it's not a clear code or an ending code, so
* it must be a code code... So we can now decode the code into
* a stack of character codes. (Clear as mud, right?)
*/
code = c;
/* Here we go again with one of those off chances... If, on the
* off chance, the code we got is beyond the range of those already
* set up (Another thing which had better NOT happen...) we trick
* the decoder into thinking it actually got the last code read.
* (Hmmn... I'm not sure why this works... But it does...)
*/
if (code >= slot) {
if (code > slot) ++bad_code_count;
code = oc;
*sp++ = (BYTE)fc;
}
/* Here we scan back along the linked list of prefixes, pushing
* helpless characters (ie. suffixes) onto the stack as we do so.
*/
while (code >= newcodes) {
*sp++ = suffix[code];
code = prefix[code];
}
/* Push the last character on the stack, and set up the new
* prefix and suffix, and if the required slot number is greater
* than that allowed by the current bit size, increase the bit
* size. (NOTE - If we are all full, we *don't* save the new
* suffix and prefix... I'm not certain if this is correct...
* it might be more proper to overwrite the last code...
*/
*sp++ = (BYTE)code;
if (slot < top_slot){
suffix[slot] = (BYTE)(fc = (BYTE)code);
prefix[slot++] = oc;
oc = c;
}
if (slot >= top_slot){
if (curr_size < 12) {
top_slot <<= 1;
++curr_size;
}
}
/* Now that we've pushed the decoded string (in reverse order)
* onto the stack, lets pop it off and put it into our decode
* buffer... And when the decode buffer is full, write another
* line...
*/
while (sp > stack) {
*bufptr++ = *(--sp);
if (--bufcnt == 0) {
if ((ret = (short)out_line(iter, buf, linewidth)) < 0) {
delete[] buf;
return(ret);
}
bufptr = buf;
bufcnt = linewidth;
}
}
}
}
ret = 0;
if (bufcnt != linewidth)
ret = (short)out_line(iter, buf, (linewidth - bufcnt));
delete[] buf;
return(ret);
}
////////////////////////////////////////////////////////////////////////////////
int CxImageGIF::get_num_frames(CxFile *fp,struct_TabCol* TabColSrc)
{
struct_image image;
long pos=fp->Tell();
int nframes=0;
struct_TabCol TempTabCol;
memcpy(&TempTabCol,TabColSrc,sizeof(struct_TabCol));
char ch;
for (BOOL bContinue = TRUE; bContinue; ) {
if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;}
switch (ch)
{
case '!': // extension
{
DecodeExtension(fp);
break;
}
case ',': // image
{
nframes++;
assert(sizeof(image) == 9);
//log << "Image header" << endl;
fp->Read(&image,sizeof(image),1);
//avoid byte order problems with Solaris <candan>
BYTE *byteData = (BYTE *) & image;
image.l = byteData[0]+byteData[1]*256;
image.t = byteData[2]+byteData[3]*256;
image.w = byteData[4]+byteData[5]*256;
image.h = byteData[6]+byteData[7]*256;
// 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 bpp; //<DP> select the correct bit per pixel value
if (TempTabCol.sogct <= 2) bpp = 1;
else if (TempTabCol.sogct <= 16) bpp = 4;
else bpp = 8;
Create(image.w, image.h, bpp, CXIMAGE_FORMAT_GIF);
CImageIterator* iter = new CImageIterator(this);
iter->Upset();
int badcode;
ibf = GIFBUFTAM+1;
interlaced = image.pf & 0x40;
iheight = image.h;
istep = 8;
iypos = 0;
ipass = 0;
//if (interlaced) log << "Interlaced" << endl;
decoder(fp, iter, image.w, badcode);
delete iter;
fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR);
break;
}
case ';': //terminator
bContinue=false;
break;
default:
break;
}
}
fp->Seek(pos,SEEK_SET);
return nframes;
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::SetDisposalMethod(int dm)
{ m_dispmeth=dm; }
////////////////////////////////////////////////////////////////////////////////
long CxImageGIF::GetDisposalMethod()
{ return m_dispmeth; }
////////////////////////////////////////////////////////////////////////////////
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, long lxOffset, long lyOffset)
{
long lWide = min(GetWidth(),imgsrc2.GetWidth()-lxOffset);
long lHeight = min(GetHeight(),imgsrc2.GetHeight()-lyOffset);
BYTE ibg2= (BYTE)imgsrc2.GetTransIndex();
BYTE i2;
for(long y=0;y<lHeight;y++){
for(long x=0;x<lWide;x++){
i2 = imgsrc2.GetPixelIndex(x+lxOffset,y+lyOffset);
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) ;
while (1){
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(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(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;
while (1){
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 + -