Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImage/PluginGIF.cpp  view on Meta::CPAN

	void Done(void);

protected:
	bool m_done;

	int m_minCodeSize, m_clearCode, m_endCode, m_nextCode;

	int m_bpp, m_slack; //Compressor information

	int m_prefix; //Compressor state variable
	int m_codeSize, m_codeMask; //Compressor/Decompressor state variables
	int m_oldCode; //Decompressor state variable
	int m_partial, m_partialSize; //Compressor/Decompressor bit buffer

	int firstPixelPassed; // A specific flag that indicates if the first pixel
	                      // of the whole image had already been read

	std::string m_strings[MAX_LZW_CODE]; //This is what is really the "string table" data for the Decompressor
	int* m_strmap;

	//input buffer
	BYTE *m_buffer;
	int m_bufferSize, m_bufferRealSize, m_bufferPos, m_bufferShift;

	void ClearCompressorTable(void);
	void ClearDecompressorTable(void);
};

#define GIF_PACKED_LSD_HAVEGCT		0x80
#define GIF_PACKED_LSD_COLORRES		0x70
#define GIF_PACKED_LSD_GCTSORTED	0x08
#define GIF_PACKED_LSD_GCTSIZE		0x07
#define GIF_PACKED_ID_HAVELCT		0x80
#define GIF_PACKED_ID_INTERLACED	0x40
#define GIF_PACKED_ID_LCTSORTED		0x20
#define GIF_PACKED_ID_RESERVED		0x18
#define GIF_PACKED_ID_LCTSIZE		0x07
#define GIF_PACKED_GCE_RESERVED		0xE0
#define GIF_PACKED_GCE_DISPOSAL		0x1C
#define GIF_PACKED_GCE_WAITINPUT	0x02
#define GIF_PACKED_GCE_HAVETRANS	0x01

#define GIF_BLOCK_IMAGE_DESCRIPTOR	0x2C
#define GIF_BLOCK_EXTENSION			0x21
#define GIF_BLOCK_TRAILER			0x3B

#define GIF_EXT_PLAINTEXT			0x01
#define GIF_EXT_GRAPHIC_CONTROL		0xF9
#define GIF_EXT_COMMENT				0xFE
#define GIF_EXT_APPLICATION			0xFF

#define GIF_INTERLACE_PASSES		4
static int g_GifInterlaceOffset[GIF_INTERLACE_PASSES] = {0, 4, 2, 1};
static int g_GifInterlaceIncrement[GIF_INTERLACE_PASSES] = {8, 8, 4, 2};

// ==========================================================
// Helpers Functions
// ==========================================================

static BOOL 
FreeImage_SetMetadataEx(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, WORD id, FREE_IMAGE_MDTYPE type, DWORD count, DWORD length, const void *value)
{
	BOOL bResult = FALSE;
	FITAG *tag = FreeImage_CreateTag();
	if(tag) {
		FreeImage_SetTagKey(tag, key);
		FreeImage_SetTagID(tag, id);
		FreeImage_SetTagType(tag, type);
		FreeImage_SetTagCount(tag, count);
		FreeImage_SetTagLength(tag, length);
		FreeImage_SetTagValue(tag, value);
		if(model == FIMD_ANIMATION) {
			TagLib& s = TagLib::instance();
			// get the tag description
			const char *description = s.getTagDescription(TagLib::ANIMATION, id);
			FreeImage_SetTagDescription(tag, description);
		}
		// store the tag
		bResult = FreeImage_SetMetadata(model, dib, key, tag);
		FreeImage_DeleteTag(tag);
	}
	return bResult;
}

static BOOL 
FreeImage_GetMetadataEx(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FREE_IMAGE_MDTYPE type, FITAG **tag)
{
	if( FreeImage_GetMetadata(model, dib, key, tag) ) {
		if( FreeImage_GetTagType(*tag) == type ) {
			return TRUE;
		}
	}
	return FALSE;
}

StringTable::StringTable()
{
	m_buffer = NULL;
	firstPixelPassed = 0; // Still no pixel read
	// Maximum number of entries in the map is MAX_LZW_CODE * 256 
	// (aka 2**12 * 2**8 => a 20 bits key)
	// This Map could be optmized to only handle MAX_LZW_CODE * 2**(m_bpp)
	m_strmap = new(std::nothrow) int[1<<20];
}

StringTable::~StringTable()
{
	if( m_buffer != NULL ) {
		delete [] m_buffer;
	}
	if( m_strmap != NULL ) {
		delete [] m_strmap;
		m_strmap = NULL;
	}
}

void StringTable::Initialize(int minCodeSize)
{
	m_done = false;

	m_bpp = 8;
	m_minCodeSize = minCodeSize;
	m_clearCode = 1 << m_minCodeSize;
	if(m_clearCode > MAX_LZW_CODE) {
		m_clearCode = MAX_LZW_CODE;
	}
	m_endCode = m_clearCode + 1;

	m_partial = 0;
	m_partialSize = 0;

src/Source/FreeImage/PluginGIF.cpp  view on Meta::CPAN

				} else {
					globalpalette_size = 256;
					packed |= 7 & GIF_PACKED_LSD_GCTSIZE;
				}
				if( FreeImage_GetBackgroundColor(dib, &background_color) ) {
					for( int i = 0; i < globalpalette_size; i++ ) {
						if( background_color.rgbRed == globalpalette[i].rgbRed &&
							background_color.rgbGreen == globalpalette[i].rgbGreen &&
							background_color.rgbBlue == globalpalette[i].rgbBlue ) {

							b = (BYTE)i;
							break;
						}
					}
				}
			} else {
				packed |= (bpp - 1) & GIF_PACKED_LSD_GCTSIZE;
			}
			io->write_proc(&packed, 1, 1, handle);
			io->write_proc(&b, 1, 1, handle);
			b = 0;
			io->write_proc(&b, 1, 1, handle);

			//Global Color Table
			if( globalpalette != NULL ) {
				int i = 0;
				while( i < globalpalette_size ) {
					io->write_proc(&globalpalette[i].rgbRed, 1, 1, handle);
					io->write_proc(&globalpalette[i].rgbGreen, 1, 1, handle);
					io->write_proc(&globalpalette[i].rgbBlue, 1, 1, handle);
					i++;
				}
			}

			//Application Extension
			LONG loop = 0;
			if( FreeImage_GetMetadataEx(FIMD_ANIMATION, dib, "Loop", FIDT_LONG, &tag) ) {
				loop = *(LONG *)FreeImage_GetTagValue(tag);
			}
			if( loop != 1 ) {
				//the Netscape extension is really "repeats" not "loops"
				if( loop > 1 ) loop--;
				if( loop > 0xFFFF ) loop = 0xFFFF;
				w = (WORD)loop;
#ifdef FREEIMAGE_BIGENDIAN
				SwapShort(&w);
#endif
				io->write_proc((void *)"\x21\xFF\x0BNETSCAPE2.0\x03\x01", 16, 1, handle);
				io->write_proc(&w, 2, 1, handle);
				b = 0;
				io->write_proc(&b, 1, 1, handle);
			}

			//Comment Extension
			FIMETADATA *mdhandle = NULL;
			FITAG *tag = NULL;
			mdhandle = FreeImage_FindFirstMetadata(FIMD_COMMENTS, dib, &tag);
			if( mdhandle ) {
				do {
					if( FreeImage_GetTagType(tag) == FIDT_ASCII ) {
						int length = FreeImage_GetTagLength(tag) - 1;
						char *value = (char *)FreeImage_GetTagValue(tag);
						io->write_proc((void *)"\x21\xFE", 2, 1, handle);
						while( length > 0 ) {
							b = (BYTE)(length >= 255 ? 255 : length);
							io->write_proc(&b, 1, 1, handle);
							io->write_proc(value, b, 1, handle);
							value += b;
							length -= b;
						}
						b = 0;
						io->write_proc(&b, 1, 1, handle);
					}
				} while(FreeImage_FindNextMetadata(mdhandle, &tag));

				FreeImage_FindCloseMetadata(mdhandle);
			}
		}

		//Graphic Control Extension
		if( FreeImage_IsTransparent(dib) ) {
			int count = FreeImage_GetTransparencyCount(dib);
			BYTE *table = FreeImage_GetTransparencyTable(dib);
			for( int i = 0; i < count; i++ ) {
				if( table[i] == 0 ) {
					have_transparent = true;
					transparent_color = i;
					break;
				}
			}
		}
		io->write_proc((void *)"\x21\xF9\x04", 3, 1, handle);
		b = (BYTE)((disposal_method << 2) & GIF_PACKED_GCE_DISPOSAL);
		if( have_transparent ) b |= GIF_PACKED_GCE_HAVETRANS;
		io->write_proc(&b, 1, 1, handle);
		//Notes about delay time for GIFs:
		//IE5/IE6 have a minimum and default of 100ms
		//Mozilla/Firefox/Netscape 6+/Opera have a minimum of 20ms and a default of 100ms if <20ms is specified or the GCE is absent
		//Netscape 4 has a minimum of 10ms if 0ms is specified, but will use 0ms if the GCE is absent
		w = (WORD)(delay_time / 10); //convert ms to cs
#ifdef FREEIMAGE_BIGENDIAN
		SwapShort(&w);
#endif
		io->write_proc(&w, 2, 1, handle);
		b = (BYTE)transparent_color;
		io->write_proc(&b, 1, 1, handle);
		b = 0;
		io->write_proc(&b, 1, 1, handle);

		//Image Descriptor
		b = GIF_BLOCK_IMAGE_DESCRIPTOR;
		io->write_proc(&b, 1, 1, handle);
		io->write_proc(&left, 2, 1, handle);
		io->write_proc(&top, 2, 1, handle);
		io->write_proc(&width, 2, 1, handle);
		io->write_proc(&height, 2, 1, handle);
		packed = 0;
		if( !no_local_palette ) packed |= GIF_PACKED_ID_HAVELCT | ((bpp - 1) & GIF_PACKED_ID_LCTSIZE);
		if( interlaced ) packed |= GIF_PACKED_ID_INTERLACED;
		io->write_proc(&packed, 1, 1, handle);

		//Local Color Table
		if( !no_local_palette ) {
			int palsize = 1 << bpp;
			for( int i = 0; i < palsize; i++ ) {
				io->write_proc(&pal[i].rgbRed, 1, 1, handle);
				io->write_proc(&pal[i].rgbGreen, 1, 1, handle);
				io->write_proc(&pal[i].rgbBlue, 1, 1, handle);
			}
		}


		//LZW Minimum Code Size
		b = (BYTE)(bpp == 1 ? 2 : bpp);
		io->write_proc(&b, 1, 1, handle);
		StringTable *stringtable = new(std::nothrow) StringTable;
		stringtable->Initialize(b);
		stringtable->CompressStart(bpp, width);

		//Image Data Sub-blocks
		int y = 0, interlacepass = 0, line = FreeImage_GetLine(dib);
		BYTE buf[255], *bufptr = buf; //255 is the max sub-block length
		int size = sizeof(buf);
		b = sizeof(buf);
		while( y < output_height ) {
			memcpy(stringtable->FillInputBuffer(line), FreeImage_GetScanLine(dib, output_height - y - 1), line);
			while( stringtable->Compress(bufptr, &size) ) {
				bufptr += size;
				if( bufptr - buf == sizeof(buf) ) {
					io->write_proc(&b, 1, 1, handle);
					io->write_proc(buf, sizeof(buf), 1, handle);
					size = sizeof(buf);
					bufptr = buf;
				} else {
					size = (int)(sizeof(buf) - (bufptr - buf));
				}
			}
			if( interlaced ) {
				y += g_GifInterlaceIncrement[interlacepass];
				if( y >= output_height && ++interlacepass < GIF_INTERLACE_PASSES ) {
					y = g_GifInterlaceOffset[interlacepass];
				}		
			} else {
				y++;
			}
		}
		size = (int)(bufptr - buf);
		BYTE last[4];
		w = (WORD)stringtable->CompressEnd(last);
		if( size + w >= sizeof(buf) ) {
			//one last full size sub-block
			io->write_proc(&b, 1, 1, handle);
			io->write_proc(buf, size, 1, handle);
			io->write_proc(last, sizeof(buf) - size, 1, handle);
			//and possibly a tiny additional sub-block
			b = (BYTE)(w - (sizeof(buf) - size));
			if( b > 0 ) {
				io->write_proc(&b, 1, 1, handle);
				io->write_proc(last + w - b, b, 1, handle);
			}
		} else {
			//last sub-block less than full size
			b = (BYTE)(size + w);
			io->write_proc(&b, 1, 1, handle);
			io->write_proc(buf, size, 1, handle);
			io->write_proc(last, w, 1, handle);
		}

		//Block Terminator
		b = 0;
		io->write_proc(&b, 1, 1, handle);

		delete stringtable;

	} catch (const char *msg) {
		FreeImage_OutputMessageProc(s_format_id, msg);
		return FALSE;
	}

	return TRUE;
}



( run in 1.159 second using v1.01-cache-2.11-cpan-119454b85a5 )