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

📄 gif_decoder.h

📁 彩信浏览器
💻 H
字号:
/* * This file is part of Ambulant Player, www.ambulantplayer.org. * * Copyright (C) 2003-2007 Stichting CWI,  * Kruislaan 413, 1098 SJ Amsterdam, The Netherlands. * * Ambulant Player is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * Ambulant Player is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Ambulant Player; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA *//*  * @$Id: gif_decoder.h,v 1.5 2007/02/12 14:14:14 jackjansen Exp $  */#ifndef AMBULANT_GUI_GIF_DECODER_H#define AMBULANT_GUI_GIF_DECODER_H#include "ambulant/config/config.h"#ifndef _WINDOWS_#include <windows.h>#endif#include <cassert>#include "ambulant/gui/dg/img_decoder.h"#include "ambulant/lib/logger.h"#include "ambulant/lib/basic_types.h"#include "ambulant/lib/win32/win32_error.h"using ambulant::lib::win32::win_show_last_error;namespace ambulant {namespace gui {namespace dg {template <class DataSource>class gif_decoder : public img_decoder<DataSource> {  public:	typedef unsigned short uint16_t;		gif_decoder(DataSource* src, HDC hdc);		virtual ~gif_decoder();		virtual bool can_decode();	virtual dib_surface<surf_color_t>* decode();		virtual bool is_transparent() 		{ return m_transparent>=0;}	virtual void get_transparent_color(BYTE *rgb) {		if(m_transparent>=0) {			color_quad& t = m_palette[m_transparent];			rgb[0] = t.r; rgb[1] = t.g; rgb[2] = t.b;			AM_DBG m_logger->debug("Gif transparent color (%d, %d, %d)", int(t.r), int(t.g), int(t.b));		} else {			rgb[0] = 0; rgb[1] = 0; rgb[2] = 0;		}	}  private:	dib_surface<surf_color_t>* parse_metadata();	dib_surface<surf_color_t>* parse_image();	bool parse_image_pixels(int width, int height, 		int interlace, surface<surf_color_t> *psurf);	int next_block(uchar *m_buf);	int next_code(int code_size, bool flag);	int next_lzwbyte(bool flag, int input_code_size);	void skip_block();	int get_data_block(uchar *buf);	UINT to_uint(uchar a, uchar b) { return (b<<8) | a;}	color_quad *m_palette;	int m_scr_width;	int m_scr_height;	int m_scr_colors;	int m_transparent;	int m_delayTime;	int m_inputFlag;	int m_disposal;	int m_curbit, m_lastbit, m_lastbyte;	bool m_done;	int m_last_block_size;	uchar m_buf[280];	enum { MAX_LZW_BITS = 12};	lib::logger *m_logger;};template <class DataSource>gif_decoder<DataSource>::gif_decoder(DataSource* src, HDC hdc):	img_decoder<DataSource>(src, hdc), 	m_palette(NULL),	m_curbit(0), m_lastbit(0), m_lastbyte(0),	m_last_block_size(-1), m_done(false),	m_transparent(-1),	m_logger(lib::logger::get_logger()) {}template <class DataSource>inline gif_decoder<DataSource>::~gif_decoder() {	if(m_palette) delete[] m_palette;}template <class DataSource>inline bool gif_decoder<DataSource>::can_decode() {	m_src->seekg(0);	uchar_t b[16];	if(m_src->read(b, 6) != 6) return false;    return b[0] == 'G' && b[1] == 'I' && b[2] == 'F' && b[3] == '8' &&		(b[4] == '7' || b[4] == '9') && b[5] == 'a';}template <class DataSource>inline dib_surface<surf_color_t>* gif_decoder<DataSource>::decode() {	if(!can_decode()) return NULL;	m_scr_width = m_src->get_be_ushort();	m_scr_height = m_src->get_be_ushort();		uchar_t uch = m_src->get();	m_scr_colors = 2 << (uch & 0x07);	int screen_color_res = ((uch & 0x70) >> 3) + 1;	int screen_bg = m_src->get();	int screen_aspect_ration = m_src->get();	if(m_palette != NULL) {		delete[] m_palette;		m_palette = NULL;	}    if((uch & 0x80) == 0x80) {		AM_DBG m_logger->debug("Gif palette entries = %d", int(m_scr_colors));		m_palette = new color_quad[m_scr_colors];		memset(m_palette, 0, m_scr_colors*sizeof(color_quad));		for(int i=0; i<m_scr_colors;i++) {			uchar_t rgb[3];			if(m_src->read(rgb, 3) != 3) break;			m_palette[i].a = 0;			m_palette[i].r = rgb[0];			m_palette[i].g = rgb[1];			m_palette[i].b = rgb[2];		}	}	return parse_metadata();}template <class DataSource>inline dib_surface<surf_color_t>* gif_decoder<DataSource>::parse_metadata() {	uchar ext_buf[256];	while(true) {		uchar_t blockType = m_src->get();		if(blockType == 0x2c) { 			AM_DBG m_logger->debug("Image Descriptor");			return parse_image();		} else if (blockType == 0x21) {			AM_DBG m_logger->debug("Extension block");			uchar_t label = m_src->get();			if(label == 0xf9) { 				AM_DBG m_logger->debug("Graphics Control Extension");				if(get_data_block(ext_buf)>0) {					m_disposal= (ext_buf[0]>>2)	& 0x7;					m_inputFlag	= (ext_buf[0]>>1) & 0x1;					m_delayTime	= to_uint(ext_buf[1], ext_buf[2]);					if((ext_buf[0] & 0x1) != 0) {						m_transparent = ext_buf[3];						AM_DBG m_logger->debug("Gif transparent index = %d", int(m_transparent));					}				}				skip_block();			} else if (label == 0x1) { 				AM_DBG m_logger->debug("Plain text extension");				skip_block();			} else if (label == 0xfe) { 				AM_DBG m_logger->debug("Comment extension");				skip_block();			} else if (label == 0xff) { 				AM_DBG m_logger->debug("Application extension");				skip_block();			} else { 				AM_DBG m_logger->debug("Unknown extension");				skip_block();			}		}	} 	return 0;}template <class DataSource>inline void gif_decoder<DataSource>::skip_block() {	int length = 0;	do	{		length = m_src->get();		m_src->skip(length);	} while (length > 0);}template <class DataSource>inline int gif_decoder<DataSource>::get_data_block(uchar *buf) {	int length = m_src->get();	if(m_src->read(buf, length) != length)		return -1;	return length;}// 9 bytes header + color_map + datatemplate <class DataSource>inline dib_surface<surf_color_t>* gif_decoder<DataSource>::parse_image() {	uint16_t imageLeftPosition = m_src->get_be_ushort();	uint16_t imageTopPosition = m_src->get_be_ushort();    uint16_t imageWidth = m_src->get_be_ushort();    uint16_t imageHeight = m_src->get_be_ushort();	uchar_t packedFields = m_src->get();    bool localColorTableFlag = (packedFields & 0x80) != 0;    bool interlaceFlag = (packedFields & 0x40) != 0;    bool sortFlag = (packedFields & 0x20) != 0;    int numLCTEntries = 1 << ((packedFields & 0x7) + 1);	if(localColorTableFlag) {		// read color table		// numLCTEntries colors		//cout << "has local color table" << endl;		m_src->skip(numLCTEntries*3);	}	//else cout << "uses global color table" << endl;	AM_DBG  m_logger->debug("ImageDescription: %d x %d",  int(imageWidth), int(imageHeight));	/////////////	// create a bmp surface	surf_color_t *pBits = NULL;	BITMAPINFO *pbmpi = get_bmp_info(imageWidth, imageHeight, surf_color_t::get_bits_size());	HBITMAP bmp = CreateDIBSection(NULL, pbmpi, DIB_RGB_COLORS, (void**)&pBits, NULL, 0);	if(bmp==NULL || pBits==NULL) {		win_show_last_error("CreateDIBSection");		return NULL;	}	surface<surf_color_t> *psurf = 		new surface<surf_color_t>(imageWidth, imageHeight, surf_color_t::get_bits_size(), pBits);			parse_image_pixels(imageWidth, imageHeight, interlaceFlag, psurf);	uchar_t img_terminator = m_src->get(); // read ';'	return new dib_surface<surf_color_t>(bmp, psurf);}template <class DataSource>inline int gif_decoder<DataSource>::next_block(uchar *buf) {	uchar count = m_src->get();	m_last_block_size = count;	m_src->read(buf, count);	return count;}template <class DataSource>inline int gif_decoder<DataSource>::next_code(int code_size, bool flag) {	int i,j;	uchar count;	if(flag)  {		m_curbit=0;		m_lastbit=0;		m_done = false;		return 0;	}	if((m_curbit+code_size) >= m_lastbit) {		if(m_done) {			if(m_curbit >= m_lastbit)  {				// "Ran off the end of bits";				return 0;			}			return -1;		}		m_buf[0] = m_buf[m_lastbyte-2];			m_buf[1] = m_buf[m_lastbyte-1];		count = next_block(&m_buf[2]);		if(count == 0) m_done = true;		m_lastbyte = 2 + count;		m_curbit = (m_curbit - m_lastbit) + 16;		m_lastbit = (2 + count) * 8;	}	int ret=0;	for (i=m_curbit,j=0; j<code_size;++i,++j)		ret |= ((m_buf[i/8]&(1<<(i% 8)))!=0)<<j;	m_curbit += code_size;	return ret;}template <class DataSource>inline int gif_decoder<DataSource>::next_lzwbyte(bool flag, int input_code_size) {	static bool fresh = false;	int code, incode;	static int code_size, set_code_size;	static int max_code, max_code_size;	static int firstcode, oldcode;	static int clear_code, end_code;	static unsigned short  next[1 << MAX_LZW_BITS];	static uchar  vals[1 << MAX_LZW_BITS];	static uchar  stack[1 << (MAX_LZW_BITS+1)];	static uchar  *sp;		int i;	if(flag) {		set_code_size = input_code_size;		code_size = set_code_size + 1;		clear_code = 1 << set_code_size;		end_code = clear_code + 1;		max_code = clear_code+2;		max_code_size = 2*clear_code;		next_code(0, true);		fresh = TRUE;			for(i=0;i<clear_code;++i) {			next[i]=0;			vals[i]=i;		}		for (;i<(1<<MAX_LZW_BITS);++i)			next[i]=vals[0]=0;			sp=stack;		return 0;			} else if (fresh) {		fresh = false;		do	{			firstcode = oldcode = next_code(code_size, false);		}	while (firstcode == clear_code);		return firstcode;	}	if (sp > stack)		return *--sp;	while((code = next_code(code_size, false)) >=0) {		if (code == clear_code) {			for (i=0;i<clear_code;++i) {				next[i]=0;				vals[i]=i;			}			for (;i<(1<<MAX_LZW_BITS);++i)					next[i] = vals[i] = 0;			code_size = set_code_size + 1;			max_code_size = 2*clear_code;			max_code = clear_code+2;			sp = stack;			firstcode = oldcode = next_code(code_size, false);			return firstcode;		} else if (code == end_code) {			int count;			uchar m_buf[260];					if (m_last_block_size == 0)				return -2;						while ((count = next_block(m_buf)) >0);			if (count != 0)				return -2;			}		incode = code;		if (code >= max_code) {			*sp++=firstcode;			code=oldcode;		}		while (code >=clear_code) {			*sp++=vals[code];			if (code==(int)next[code]) {				// "Circular table entry";				return -1;			}			code=next[code];		}		*sp++ = firstcode=vals[code];		if((code=max_code) <(1<<MAX_LZW_BITS)) {			next[code]=oldcode;			vals[code]=firstcode;			++max_code;			if ((max_code >=max_code_size) &&				(max_code_size < (1<<MAX_LZW_BITS))) {				 max_code_size*=2;				++code_size;			}		}		oldcode = incode;		if (sp > stack)			return *--sp;	}	return code;}   template <class DataSource>inline bool gif_decoder<DataSource>::parse_image_pixels(	int width, int height, int interlace, surface<surf_color_t> *psurf) {	assert(psurf!=0);	uchar c = m_src->get();	int color;	int xpos=0, ypos=0, pass=0;	if (next_lzwbyte(true, c) < 0) 		return false;		while((color = next_lzwbyte(false, c)) >= 0) {		surf_color_t rgb(m_palette[color].r, m_palette[color].g, m_palette[color].b);		psurf->set_pixel(xpos, ypos, rgb);		++xpos;		if(xpos==width) {			xpos=0;			if (interlace) {				switch(pass) {					case 0:					case 1: ypos+=8; break;					case 2: ypos+=4; break;					case 3: ypos+=2; break;				}				if (ypos>=height) {					++pass;					switch (pass) {						case 1: ypos=4;break;						case 2: ypos=2;break;						case 3: ypos=1;break;						default : goto fini;					}				}			} else {				++ypos;			}		}		if (ypos >= height)			break;	}	fini:	if(next_lzwbyte(false, c)>=0) {}	return true;}	} // namespace dg} // namespace gui } // namespace ambulant#endif // AMBULANT_GUI_GIF_DECODER_H

⌨️ 快捷键说明

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