示例#1
0
// ****************************************************************************
// * LoadGIF                                                                  *
// *   Load a GIF File into the CAnimatedGifSet object                             *
// *                        (c) Nov 2000, Juan Soulie <*****@*****.**> *
// ****************************************************************************
int CAnimatedGifSet::LoadGIF (const char * szFileName)
{
  int n;
  // Global GIF variables:
  int GlobalBPP;       // Bits per Pixel.
  COLOR * GlobalColorMap;     // Global colormap (allocate)

  struct GIFGCEtag
  {                // GRAPHIC CONTROL EXTENSION
    unsigned char BlockSize;   // Block Size: 4 bytes
    unsigned char PackedFields;  // 3.. Packed Fields. Bits detail:
    //    0: Transparent Color Flag
    //    1: User Input Flag
    //  2-4: Disposal Method
    unsigned short Delay;     // 4..5 Delay Time (1/100 seconds)
    unsigned char Transparent;  // 6.. Transparent Color Index
  }
  gifgce;

  struct GIFNetscapeTag
  {
    unsigned char comment[11];  //4...14  NETSCAPE2.0
    unsigned char SubBlockLength; //15      0x3
    unsigned char reserved;       //16      0x1
    unsigned short iIterations ;    //17..18  number of iterations (lo-hi)
  }
  gifnetscape;

  int GraphicExtensionFound = 0;

  // OPEN FILE
  FILE *fd = fopen_utf8(CSpecialProtocol::TranslatePath(szFileName), "rb");
  if (!fd)
  {
    return 0;
  }

  // *1* READ HEADERBLOCK (6bytes) (SIGNATURE + VERSION)
  char szSignature[6];    // First 6 bytes (GIF87a or GIF89a)
  int iRead = fread(szSignature, 1, 6, fd);
  if (iRead != 6)
  {
    fclose(fd);
    return 0;
  }
  if ( memcmp(szSignature, "GIF", 2) != 0)
  {
    fclose(fd);
    return 0;
  }
  // *2* READ LOGICAL SCREEN DESCRIPTOR
  struct GIFLSDtag
  {
    unsigned short ScreenWidth;  // Logical Screen Width
    unsigned short ScreenHeight; // Logical Screen Height
    unsigned char PackedFields;  // Packed Fields. Bits detail:
    //  0-2: Size of Global Color Table
    //    3: Sort Flag
    //  4-6: Color Resolution
    //    7: Global Color Table Flag
    unsigned char Background;  // Background Color Index
    unsigned char PixelAspectRatio; // Pixel Aspect Ratio
  }
  giflsd;

  iRead = fread(&giflsd, 1, sizeof(giflsd), fd);
  if (iRead != sizeof(giflsd))
  {
    fclose(fd);
    return 0;
  }
  // endian swap
  SWAP16(giflsd.ScreenWidth);
  SWAP16(giflsd.ScreenHeight);

  GlobalBPP = (giflsd.PackedFields & 0x07) + 1;

  // fill some animation data:
  FrameWidth = giflsd.ScreenWidth;
  FrameHeight = giflsd.ScreenHeight;
  nLoops = 1; //default=play animation 1 time

  // *3* READ/GENERATE GLOBAL COLOR MAP
  GlobalColorMap = new COLOR [1 << GlobalBPP];
  if (giflsd.PackedFields & 0x80) // File has global color map?
    for (n = 0;n < 1 << GlobalBPP;n++)
    {
      GlobalColorMap[n].r = getbyte(fd);
      GlobalColorMap[n].g = getbyte(fd);
      GlobalColorMap[n].b = getbyte(fd);
      GlobalColorMap[n].x = 0;
    }

  else // GIF standard says to provide an internal default Palette:
    for (n = 0;n < 256;n++)
    {
      GlobalColorMap[n].r = GlobalColorMap[n].g = GlobalColorMap[n].b = n;
      GlobalColorMap[n].x = 0;
    }

  // *4* NOW WE HAVE 3 POSSIBILITIES:
  //  4a) Get and Extension Block (Blocks with additional information)
  //  4b) Get an Image Separator (Introductor to an image)
  //  4c) Get the trailer Char (End of GIF File)
  do
  {
    int charGot = getbyte(fd);

    if (charGot == 0x21)  // *A* EXTENSION BLOCK
    {
      unsigned char extensionType = getbyte(fd);
      switch (extensionType)
      {
      case 0xF9:    // Graphic Control Extension
        {
          if (fread((char*)&gifgce, 1, sizeof(gifgce), fd) == sizeof(gifgce))
            SWAP16(gifgce.Delay);
          GraphicExtensionFound++;
          getbyte(fd); // Block Terminator (always 0)
        }
        break;

      case 0xFE:    // Comment Extension: Ignored
        {
          while (int nBlockLength = getbyte(fd))
            for (n = 0;n < nBlockLength;n++) getbyte(fd);
        }
        break;

      case 0x01:    // PlainText Extension: Ignored
        {
          while (int nBlockLength = getbyte(fd))
            for (n = 0;n < nBlockLength;n++) getbyte(fd);
        }
        break;

      case 0xFF:    // Application Extension: Ignored
        {
          int nBlockLength = getbyte(fd);
          if (nBlockLength == 0x0b)
          {
            struct GIFNetscapeTag tag;
            if (fread((char*)&tag, 1, sizeof(gifnetscape), fd) == sizeof(gifnetscape))
            {
              SWAP16(tag.iIterations);
              nLoops = tag.iIterations;
            }
            else
              nLoops = 0;

            if (nLoops) nLoops++;
            getbyte(fd);
          }
          else
          {
            do
            {
              for (n = 0;n < nBlockLength;n++) getbyte(fd);
            }
            while ((nBlockLength = getbyte(fd)) != 0);
          }
        }
        break;

       default:    // Unknown Extension: Ignored
        {
          // read (and ignore) data sub-blocks
          while (int nBlockLength = getbyte(fd))
            for (n = 0;n < nBlockLength;n++) getbyte(fd);
        }
        break;
      }
    }
    else if (charGot == 0x2c)
    { // *B* IMAGE (0x2c Image Separator)
      // Create a new Image Object:
      CAnimatedGif* NextImage = new CAnimatedGif();

      // Read Image Descriptor
      struct GIFIDtag
      {
        unsigned short xPos;     // Image Left Position
        unsigned short yPos;     // Image Top Position
        unsigned short Width;     // Image Width
        unsigned short Height;    // Image Height
        unsigned char PackedFields;  // Packed Fields. Bits detail:
        //  0-2: Size of Local Color Table
        //  3-4: (Reserved)
        //    5: Sort Flag
        //    6: Interlace Flag
        //    7: Local Color Table Flag
      }
      gifid;

      memset(&gifid, 0, sizeof(gifid));

      int LocalColorMap = 0;
      if (fread((char*)&gifid, 1, sizeof(gifid), fd) == sizeof(gifid))
      {
        SWAP16(gifid.xPos);
        SWAP16(gifid.yPos);
        SWAP16(gifid.Width);
        SWAP16(gifid.Height);

        LocalColorMap = (gifid.PackedFields & 0x08) ? 1 : 0;
      }

      NextImage->Init(gifid.Width, gifid.Height, LocalColorMap ? (gifid.PackedFields&7) + 1 : GlobalBPP);

      // Fill NextImage Data
      NextImage->xPos = gifid.xPos;
      NextImage->yPos = gifid.yPos;
      if (GraphicExtensionFound)
      {
        NextImage->Transparent = (gifgce.PackedFields & 0x01) ? gifgce.Transparent : -1;
        NextImage->Transparency = (gifgce.PackedFields & 0x1c) > 1 ? 1 : 0;
        NextImage->Delay = gifgce.Delay * 10;
      }

      if (NextImage->Transparent != -1)
        memset(NextImage->Raster, NextImage->Transparent, NextImage->BytesPerRow * NextImage->Height);
      else
        memset(NextImage->Raster, giflsd.Background, NextImage->BytesPerRow * NextImage->Height);

      // Read Color Map (if descriptor says so)
      size_t palSize = sizeof(COLOR)*(1 << NextImage->BPP);
      bool isPalRead = false;
      if (LocalColorMap && fread((char*)NextImage->Palette, 1, palSize, fd) == palSize)
        isPalRead = true;

      // Copy global, if no palette
      if (!isPalRead)
        memcpy(NextImage->Palette, GlobalColorMap, palSize);

      short firstbyte = getbyte(fd); // 1st byte of img block (CodeSize)

      // Calculate compressed image block size
      // to fix: this allocates an extra byte per block
      long ImgStart, ImgEnd;
      ImgEnd = ImgStart = ftell(fd);
      while ((n = getbyte(fd)) !=  0) fseek (fd, ImgEnd += n + 1, SEEK_SET );
      fseek (fd, ImgStart, SEEK_SET);

      // Allocate Space for Compressed Image
      char * pCompressedImage = new char [ImgEnd - ImgStart + 4];

      // Read and store Compressed Image
      char * pTemp = pCompressedImage;
      while (int nBlockLength = getbyte(fd))
      {
        if (fread(pTemp, 1, nBlockLength, fd) != (size_t)nBlockLength)
        {
        // Error?
        }
        pTemp += nBlockLength;
      }

      // Call LZW/GIF decompressor
      n = LZWDecoder(
            (char*) pCompressedImage,
            (char*) NextImage->Raster,
            firstbyte, NextImage->BytesPerRow, //NextImage->AlignedWidth,
            gifid.Width, gifid.Height,
            ((gifid.PackedFields & 0x40) ? 1 : 0) //Interlaced?
          );

      if (n)
        AddImage(NextImage);
      else
      {
        delete NextImage;
        ERRORMSG("GIF File Corrupt");
      }

      // Some cleanup
      delete[] pCompressedImage;
      GraphicExtensionFound = 0;
    }
    else if (charGot == 0x3b)
    {
      // *C* TRAILER: End of GIF Info
      break; // Ok. Standard End.
    }

  }
  while ( !feof(fd) );

  delete[] GlobalColorMap;
  fclose(fd);
  if ( GetImageCount() == 0) ERRORMSG("Premature End Of File");
  return GetImageCount();
}
示例#2
0
// ****************************************************************************
// * LoadGIF                                                                  *
// *   Load a GIF File into the C_ImageSet object                             *
// *                        (c) Nov 2000, Juan Soulie <*****@*****.**> *
// ****************************************************************************
int C_ImageSet::LoadGIF (char * szFileName)
{
	int n;

	// Global GIF variables:
	int GlobalBPP;						// Bits per Pixel.
	COLOR * GlobalColorMap;				// Global colormap (allocate)

	struct GIFGCEtag {				// GRAPHIC CONTROL EXTENSION
		unsigned char BlockSize;		// Block Size: 4 bytes
		unsigned char PackedFields;		// Packed Fields. Bits detail:
										//    0: Transparent Color Flag
										//    1: User Input Flag
										//  2-4: Disposal Method
		unsigned short Delay;			// Delay Time (1/100 seconds)
		unsigned char Transparent;		// Transparent Color Index
	} gifgce;
	int GraphicExtensionFound = 0;

	// OPEN FILE
	ifstream giffile (szFileName,ios::in|ios::nocreate|ios::binary);
	if (!giffile.is_open()) {ERRORMSG("File not found");return 0;}

	// *1* READ HEADER (SIGNATURE + VERSION)
	char szSignature[6];				// First 6 bytes (GIF87a or GIF89a)
	giffile.read(szSignature,6);
	if ( memcmp(szSignature,"GIF",2) != 0)
		{ ERRORMSG("Not a GIF File"); return 0; }

	// *2* READ LOGICAL SCREEN DESCRIPTOR
	struct GIFLSDtag {
		unsigned short ScreenWidth;		// Logical Screen Width
		unsigned short ScreenHeight;	// Logical Screen Height
		unsigned char PackedFields;		// Packed Fields. Bits detail:
										//  0-2: Size of Global Color Table
										//    3: Sort Flag
										//  4-6: Color Resolution
										//    7: Global Color Table Flag
		unsigned char Background;		// Background Color Index
		unsigned char PixelAspectRatio;	// Pixel Aspect Ratio
	} giflsd;

	giffile.read((char*)&giflsd,sizeof(giflsd));

	GlobalBPP = (giflsd.PackedFields & 0x07) + 1;

	// fill some animation data:
	FrameWidth = giflsd.ScreenWidth;
	FrameHeight = giflsd.ScreenHeight;
	nLoops = 0;

	// *3* READ/GENERATE GLOBAL COLOR MAP
	GlobalColorMap = new COLOR [1<<GlobalBPP];
	if (giflsd.PackedFields & 0x80)	// File has global color map?
		for (n=0;n< 1<<GlobalBPP;n++)
		{
			GlobalColorMap[n].r=giffile.get();
			GlobalColorMap[n].g=giffile.get();
			GlobalColorMap[n].b=giffile.get();
		}

	else	// GIF standard says to provide an internal default Palette:
		for (n=0;n<256;n++)
			GlobalColorMap[n].r=GlobalColorMap[n].g=GlobalColorMap[n].b=n;

	// *4* NOW WE HAVE 3 POSSIBILITIES:
	//  4a) Get and Extension Block (Blocks with additional information)
	//  4b) Get an Image Separator (Introductor to an image)
	//  4c) Get the trailer Char (End of GIF File)
	do
	{
		int charGot = giffile.get();

		if (charGot == 0x21)		// *A* EXTENSION BLOCK 
		{
			switch (giffile.get())
			{

			case 0xF9:			// Graphic Control Extension

				giffile.read((char*)&gifgce,sizeof(gifgce));
				GraphicExtensionFound++;
				giffile.get(); // Block Terminator (always 0)
				break;

			case 0xFE:			// Comment Extension: Ignored
			case 0x01:			// PlainText Extension: Ignored
			case 0xFF:			// Application Extension: Ignored
			default:			// Unknown Extension: Ignored
				// read (and ignore) data sub-blocks
				while (int nBlockLength = giffile.get())
					for (n=0;n<nBlockLength;n++) giffile.get();
				break;
			}
		}


		else if (charGot == 0x2c) {	// *B* IMAGE (0x2c Image Separator)

			// Create a new Image Object:
			C_Image* NextImage;
			NextImage = new C_Image;

			// Read Image Descriptor
			struct GIFIDtag {	
				unsigned short xPos;			// Image Left Position
				unsigned short yPos;			// Image Top Position
				unsigned short Width;			// Image Width
				unsigned short Height;			// Image Height
				unsigned char PackedFields;		// Packed Fields. Bits detail:
											//  0-2: Size of Local Color Table
											//  3-4: (Reserved)
											//    5: Sort Flag
											//    6: Interlace Flag
											//    7: Local Color Table Flag
			} gifid;

			giffile.read((char*)&gifid, sizeof(gifid));

			int LocalColorMap = (gifid.PackedFields & 0x08)? 1 : 0;

			NextImage->Init (gifid.Width, gifid.Height,
				LocalColorMap ? (gifid.PackedFields&7)+1 : GlobalBPP);

			// Fill NextImage Data
			NextImage->xPos = gifid.xPos;
			NextImage->yPos = gifid.yPos;
			if (GraphicExtensionFound)
			{
				NextImage->Transparent=
					(gifgce.PackedFields&0x01) ? gifgce.Transparent : -1;
				NextImage->Transparency=
					(gifgce.PackedFields&0x1c)>1 ? 1 : 0;
				NextImage->Delay = gifgce.Delay*10;
			}
		
			if (LocalColorMap)		// Read Color Map (if descriptor says so)
				giffile.read((char*)NextImage->Palette,
					sizeof(COLOR)*(1<<NextImage->BPP));

			else					// Otherwise copy Global
				memcpy (NextImage->Palette, GlobalColorMap,
					sizeof(COLOR)*(1<<NextImage->BPP));

			short firstbyte=giffile.get();	// 1st byte of img block (CodeSize)

			// Calculate compressed image block size
				// to fix: this allocates an extra byte per block
			long ImgStart,ImgEnd;				
			ImgEnd = ImgStart = giffile.tellg();
			while (n=giffile.get()) giffile.seekg (ImgEnd+=n+1);
			giffile.seekg (ImgStart);

			// Allocate Space for Compressed Image
			char * pCompressedImage = new char [ImgEnd-ImgStart+4];
  
			// Read and store Compressed Image
			char * pTemp = pCompressedImage;
			while (int nBlockLength = giffile.get())
			{
				giffile.read(pTemp,nBlockLength);
				pTemp+=nBlockLength;
			}

			// Call LZW/GIF decompressor
			n=LZWDecoder(
				(char*) pCompressedImage,
				(char*) NextImage->Raster,
				firstbyte, NextImage->BytesPerRow,//NextImage->AlignedWidth,
				gifid.Width, gifid.Height,
				((gifid.PackedFields & 0x40)?1:0)	//Interlaced?
				);

			if (n)
				AddImage(NextImage);
			else
			{
				delete NextImage;
				ERRORMSG("GIF File Corrupt");
			}

			// Some cleanup
			delete[]pCompressedImage;
			GraphicExtensionFound=0;
		}


		else if (charGot == 0x3b) {	// *C* TRAILER: End of GIF Info
			break; // Ok. Standard End.
		}

	} while (giffile.good());

	giffile.close();
	if (nImages==0) ERRORMSG("Premature End Of File");
	return nImages;
}