⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ximagif.cpp

📁 信息隐藏中用于数字隐写的常用算法:LSB替换LSB匹配,包括随机的和排序的,以及对文件和文件夹进行操作,用CxImage类能快速读取各种格式的图象
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
 * File:	ximagif.cpp
 * Purpose:	Platform Independent GIF Image Class Loader and Writer
 * 07/Aug/2001 Davide Pizzolato - www.xdp.it
 * CxImage version 5.99a 08/Feb/2004
 */

#include "ximagif.h"

#if CXIMAGE_SUPPORT_GIF

#include "ximaiter.h"

#if CXIMAGE_SUPPORT_WINCE
	#define assert(s)
#else
	#include <assert.h>
#endif

////////////////////////////////////////////////////////////////////////////////
bool CxImageGIF::Decode(CxFile *fp)
{
	/* AD - for transparency */
	struct_dscgif dscgif;
	struct_image image;
	struct_TabCol TabCol;

	if (fp == NULL) return false;

	fp->Read(&dscgif,/*sizeof(dscgif)*/13,1);
	//if (strncmp(dscgif.header,"GIF8",3)!=0) {
	if (strncmp(dscgif.header,"GIF8",4)!=0) return FALSE;

	/* AD - for interlace */
	TabCol.sogct = (short)(1 << ((dscgif.pflds & 0x07)+1));
	TabCol.colres = (short)(((dscgif.pflds & 0x70) >> 3) + 1);

	// assume that the image is a truecolor-gif if
	// 1) no global color map found
	// 2) (image.w, image.h) of the 1st image != (dscgif.scrwidth, dscgif.scrheight)
	long bTrueColor=0;
	CxImage* imaRGB=NULL;

	// Global colour map?
	if (dscgif.pflds & 0x80)
		fp->Read(TabCol.paleta,sizeof(struct rgb_color)*TabCol.sogct,1);
	else 
		bTrueColor++;	//first chance for a truecolor gif

	long first_transparent_index;

	int iImage = 0;
	info.nNumFrames=get_num_frames(fp,&TabCol);

	if ((info.nFrame<0)||(info.nFrame>=info.nNumFrames)) return false;

	char ch;
	for (BOOL bContinue = TRUE; bContinue; ) {
		if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;}

		if (info.nEscape > 0) return false; // <vho> - cancel decoding

		switch (ch)
		{
		case '!': // extension
			{
			bContinue = DecodeExtension(fp);
			break;
			}
		case ',': // image
			{
			assert(sizeof(image) == 9);
			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;

			if (info.nEscape == -1) {
				// Return output dimensions only
				head.biWidth = image.w;
				head.biHeight = image.h;
				return true;
			}

			if (((image.l + image.w) > dscgif.scrwidth)||((image.t + image.h) > dscgif.scrheight))
				break;

			// check if it could be a truecolor gif
			if ((iImage==0) && (image.w != dscgif.scrwidth) && (image.h != dscgif.scrheight))
				bTrueColor++;

			// Local colour map?
			if (image.pf & 0x80) {
				TabCol.sogct = (short)(1 << ((image.pf & 0x07) +1));
				assert(3 == sizeof(struct rgb_color));
				fp->Read(TabCol.paleta,sizeof(struct rgb_color)*TabCol.sogct,1);
				//log << "Local colour map" << endl;
			}

			int bpp; //<DP> select the correct bit per pixel value
			if		(TabCol.sogct <= 2)  bpp = 1;
			else if (TabCol.sogct <= 16) bpp = 4;
			else						 bpp = 8;

			//handle Disposal Method
			CxImageGIF previmage;
			if (iImage>0 && (gifgce.dispmeth==1 || gifgce.dispmeth==2)) previmage.Copy(*this);
			if (iImage==0)	first_transparent_index = info.nBkgndIndex;

			Create(image.w, image.h, bpp, CXIMAGE_FORMAT_GIF);

			if ((image.pf & 0x80) || (dscgif.pflds & 0x80)) {
				unsigned char r[256], g[256], b[256];
				int i, has_white = 0;

				for (i=0; i < TabCol.sogct; i++) {
					r[i] = TabCol.paleta[i].r;
					g[i] = TabCol.paleta[i].g;
					b[i] = TabCol.paleta[i].b;

					if (RGB(r[i],g[i],b[i]) == 0xFFFFFF) has_white = 1;
				}

				// Force transparency colour white...
				//if (0) if (info.nBkgndIndex != -1)
				//	r[info.nBkgndIndex] = g[info.nBkgndIndex] = b[info.nBkgndIndex] = 255;
				// Fill in with white // AD
				if (info.nBkgndIndex != -1) {
					while (i < 256)	{
						has_white = 1;
						r[i] = g[i] = b[i] = 255;
						i++;
					}
				}

				// Force last colour to white...   // AD
				//if ((info.nBkgndIndex != -1) && !has_white) {
				//	r[255] = g[255] = b[255] = 255;
				//}

				SetPalette((info.nBkgndIndex != -1 ? 256 : TabCol.sogct), r, g, b);
			}

			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;

			if (info.nEscape) return false; // <vho> - cancel decoding

			//handle Disposal Method
            /*Values :  0 -   No disposal specified. The decoder is
                              not required to take any action.
                        1 -   Do not dispose. The graphic is to be left
                              in place.
                        2 -   Restore to background color. The area used by the
                              graphic must be restored to the background color.
                        3 -   Restore to previous. The decoder is required to
                              restore the area overwritten by the graphic with
                              what was there prior to rendering the graphic.
			*/
			if (iImage>0 && (gifgce.dispmeth==1 || gifgce.dispmeth==2) && bTrueColor<2 && (!(image.pf & 0x80))){
				previmage.GifMix(*this,-image.l,-(int)previmage.GetHeight()+image.t+image.h);
				previmage.SetTransIndex(first_transparent_index);
				Transfer(previmage);
			}

			//restore the correct position in the file for the next image
			fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR);

			if (bTrueColor>=2){ //it's a truecolor gif!
				//force full image decoding
				info.nFrame=info.nNumFrames-1;
				//build the RGB image
				if (imaRGB==NULL) imaRGB = new CxImage(dscgif.scrwidth,dscgif.scrheight,24,CXIMAGE_FORMAT_GIF);
				//copy the partial image into the full RGB image
				for(long y=0;y<image.h;y++){
					for (long x=0;x<image.w;x++){
						imaRGB->SetPixelColor(x+image.l,dscgif.scrheight-1-image.t-y,GetPixelColor(x,image.h-y-1));
					}
				}
			}

			if (info.nFrame==iImage) bContinue=false; else iImage++;

			break;
			}
		case ';': //terminator
			bContinue=false;
			break;
		default:
			break;
		}
   }

	if (bTrueColor>=2 && imaRGB){
		if (gifgce.transpcolflag){
			imaRGB->SetTransColor(GetPaletteColor((BYTE)info.nBkgndIndex));
			imaRGB->SetTransIndex(0);
		}
		Transfer(*imaRGB);
	}
	delete imaRGB;

	return true;

}
////////////////////////////////////////////////////////////////////////////////
bool CxImageGIF::DecodeExtension(CxFile *fp)
{
	bool bContinue;
	unsigned char count;
	unsigned char fc;

	bContinue = (1 == fp->Read(&fc, sizeof(fc), 1));
	if (bContinue) {
		/* AD - for transparency */
		if (fc == 0xF9)	{
			bContinue = (1 == fp->Read(&count, sizeof(count), 1));
			if (bContinue) {
				assert(sizeof(gifgce) == 4);
				bContinue = (count == fp->Read(&gifgce, 1, sizeof(gifgce)));
				if (bContinue) {
					if (gifgce.transpcolflag) info.nBkgndIndex  = gifgce.transpcolindex;
					info.dwFrameDelay = gifgce.delaytime;
					m_dispmeth = gifgce.dispmeth;
		}	}	}

		if (fc == 0xFE) { //<DP> Comment block
			bContinue = (1 == fp->Read(&count, sizeof(count), 1));
			if (bContinue) {
				bContinue = (1 == fp->Read(m_comment, count, 1));
				m_comment[count]='\0';
		}	}

		if (fc == 0xFF) { //<DP> Application Extension block
			bContinue = (1 == fp->Read(&count, sizeof(count), 1));
			if (bContinue) {
				bContinue = (count==11);
				if (bContinue){
					char AppID[11];
					bContinue = (1 == fp->Read(AppID, count, 1));
					if (bContinue) {
						bContinue = (1 == fp->Read(&count, sizeof(count), 1));
						if (bContinue) {
							BYTE* dati = (BYTE*)malloc(count);
							bContinue = (dati!=NULL);
							if (bContinue){
								bContinue = (1 == fp->Read(dati, count, 1));
								if (count>2){
									m_loops = dati[1]+256*dati[2];
								}
							}
							free(dati);
		}	}	}	}	}

		while (bContinue && fp->Read(&count, sizeof(count), 1) && count) {
			//log << "Skipping " << count << " bytes" << endl;
			fp->Seek(count, SEEK_CUR);
		}
	}
	return bContinue;

}


//   - This external (machine specific) function is expected to return
// either the next BYTE from the GIF file, or a negative error number.
int CxImageGIF::get_byte(CxFile* file)
{
	if (ibf>=GIFBUFTAM){
		// FW 06/02/98 >>>
		ibfmax = file->Read( buf , 1 , GIFBUFTAM) ;
		if( ibfmax < GIFBUFTAM ) buf[ ibfmax ] = 255 ;
		// FW 06/02/98 <<<
		ibf = 0;
	}
	if (ibf>=ibfmax) return -1; //<DP> avoid overflows
	return buf[ibf++];
}
////////////////////////////////////////////////////////////////////////////////
/*   - This function takes a full line of pixels (one BYTE per pixel) and
 * displays them (or does whatever your program wants with them...).  It
 * should return zero, or negative if an error or some other event occurs
 * which would require aborting the decode process...  Note that the length
 * passed will almost always be equal to the line length passed to the
 * decoder function, with the sole exception occurring when an ending code
 * occurs in an odd place in the GIF file...  In any case, linelen will be
 * equal to the number of pixels passed...
*/
int CxImageGIF::out_line(CImageIterator* iter, unsigned char *pixels, int linelen)
{
	//<DP> for 1 & 4 bpp images, the pixels are compressed
	if (head.biBitCount < 8){
		for(long x=0;x<head.biWidth;x++){
			BYTE pos;
			BYTE* iDst= pixels + (x*head.biBitCount >> 3);
			if (head.biBitCount==4){
				pos = (BYTE)(4*(1-x%2));
				*iDst &= ~(0x0F<<pos);
				*iDst |= ((pixels[x] & 0x0F)<<pos);
			} else if (head.biBitCount==1){
				pos = (BYTE)(7-x%8);
				*iDst &= ~(0x01<<pos);
				*iDst |= ((pixels[x] & 0x01)<<pos);
			}
		}
	}

	/* AD - for interlace */
	if (interlaced) {
		iter->SetY(iheight-iypos-1);
		iter->SetRow(pixels, linelen);

		if ((iypos += istep) >= iheight) {
			do {
				if (ipass++ > 0) istep /= 2;
				iypos = istep / 2;
			}
			while (iypos > iheight);
		}
		return 0;
	} else {
		if (iter->ItOK()) {
			iter->SetRow(pixels, linelen);
			(void)iter->PrevRow();
			return 0;
		} else {
			//	 puts("chafeo");
			return -1;
		}
	}
}
////////////////////////////////////////////////////////////////////////////////
#if CXIMAGE_SUPPORT_ENCODE
////////////////////////////////////////////////////////////////////////////////
// SaveFile - writes GIF87a gif file
// Randy Spann 6/15/97
// R.Spann@ConnRiver.net
bool CxImageGIF::Encode(CxFile * fp)
{
	if (EncodeSafeCheck(fp)) return false;

	if(head.biBitCount > 8)	{
		//strcpy(info.szLastError,"GIF Images must be 8 bit or less");
		//return FALSE;
		return EncodeRGB(fp);
	}

	EncodeHeader(fp);

	EncodeExtension(fp);

	EncodeComment(fp);

	EncodeBody(fp);

	fp->PutC(';'); // Write the GIF file terminator

	return true; // done!
}
////////////////////////////////////////////////////////////////////////////////
bool CxImageGIF::Encode(CxFile * fp, CxImage ** pImages, int pagecount, bool bLocalColorMap)
{
  try{
	if (fp==NULL) throw "invalid file pointer";
	if (pImages==NULL || pagecount==0 || pImages[0]==NULL) throw "multipage GIF, no images!";

	CxImageGIF ghost;

	//write the first image
	ghost.Ghost(pImages[0]);
	ghost.EncodeHeader(fp);

	if (m_loops!=1){
		ghost.SetLoops(max(0,m_loops-1));
		ghost.EncodeLoopExtension(fp);
	}

	ghost.SetDisposalMethod(GetDisposalMethod());
	ghost.EncodeExtension(fp);

	EncodeComment(fp);

	ghost.EncodeBody(fp);
	
	for (int i=2; i<=pagecount; i++){
		if (pImages[i-1]==NULL) throw "Bad image pointer";
		ghost.Ghost(pImages[i-1]);

		ghost.SetDisposalMethod(GetDisposalMethod());
		ghost.EncodeExtension(fp);

		ghost.EncodeBody(fp,bLocalColorMap);
	}

	fp->PutC(';'); // Write the GIF file terminator

  } catch (char *message) {
	  strncpy(info.szLastError,message,255);
	  return false;
  }
	return true;
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::EncodeHeader(CxFile *fp)
{
	fp->Write("GIF89a",1,6);	   //GIF Header

	Putword(head.biWidth,fp);			   //Logical screen descriptor
	Putword(head.biHeight,fp);

	BYTE Flags;
	if (head.biClrUsed==0){
		Flags=0x11;
	} else {
		Flags = 0x80;
		Flags |=(head.biBitCount - 1) << 5;
		Flags |=(head.biBitCount - 1);
	}

	fp->PutC(Flags); //GIF "packed fields"
	fp->PutC(0);	 //GIF "BackGround"
	fp->PutC(0);	 //GIF "pixel aspect ratio"

	if (head.biClrUsed!=0){
		RGBQUAD* pPal = GetPalette();
		for(DWORD i=0; i<head.biClrUsed; ++i) 
		{
			fp->PutC(pPal[i].rgbRed);
			fp->PutC(pPal[i].rgbGreen);
			fp->PutC(pPal[i].rgbBlue);
		}
	}
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::EncodeExtension(CxFile *fp)
{
	// TRK BEGIN : transparency
	fp->PutC('!');
	fp->PutC(TRANSPARENCY_CODE);

	gifgce.transpcolflag = (info.nBkgndIndex != -1) ? 1 : 0;
	gifgce.userinputflag = 0;
	gifgce.dispmeth = m_dispmeth;
	gifgce.res = 0;
	gifgce.delaytime = (WORD)info.dwFrameDelay;
	gifgce.transpcolindex = (BYTE)info.nBkgndIndex;	   
	fp->PutC(sizeof(gifgce));
	fp->Write(&gifgce, sizeof(gifgce), 1);
	fp->PutC(0);
	// TRK END
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::EncodeLoopExtension(CxFile *fp)
{
	fp->PutC('!');		//byte  1  : 33 (hex 0x21) GIF Extension code
	fp->PutC(255);		//byte  2  : 255 (hex 0xFF) Application Extension Label
	fp->PutC(11);		//byte  3  : 11 (hex (0x0B) Length of Application Block (eleven bytes of data to follow)
	fp->Write("NETSCAPE2.0",11,1);
	fp->PutC(3);			//byte 15  : 3 (hex 0x03) Length of Data Sub-Block (three bytes of data to follow)
	fp->PutC(1);			//byte 16  : 1 (hex 0x01)
	Putword(m_loops,fp); //bytes 17 to 18 : 0 to 65535, an unsigned integer in lo-hi byte format. 
						//This indicate the number of iterations the loop should be executed.
	fp->PutC(0);			//bytes 19       : 0 (hex 0x00) a Data Sub-block Terminator. 
}
////////////////////////////////////////////////////////////////////////////////
void CxImageGIF::EncodeBody(CxFile *fp, bool bLocalColorMap)
{
	curx = 0;
	cury = head.biHeight - 1;	//because we read the image bottom to top
	CountDown = (long)head.biWidth * (long)head.biHeight;

	fp->PutC(',');

	Putword(info.xOffset,fp);
	Putword(info.yOffset,fp);
	Putword(head.biWidth,fp);
	Putword(head.biHeight,fp);

	BYTE Flags=0x00; //non-interlaced (0x40 = interlaced) (0x80 = LocalColorMap)
	if (bLocalColorMap)	{ Flags|=0x80; Flags|=head.biBitCount-1; }
	fp->PutC(Flags);

	if (bLocalColorMap){
		Flags|=0x87;
		RGBQUAD* pPal = GetPalette();
		for(DWORD i=0; i<head.biClrUsed; ++i) 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -