www.pudn.com > flash.rar > bitmap.cpp


///////////////////////////////////////////////////////////// 
// Flash Plugin and Player 
// Copyright (C) 1998 Olivier Debon 
//  
// This program is free software; you can redistribute it and/or 
// modify it under the terms of the GNU General Public License 
// as published by the Free Software Foundation; either version 2 
// of the License, or (at your option) any later version. 
//  
// This program 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 General Public License for more details. 
//  
// You should have received a copy of the GNU General Public License 
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
//  
/////////////////////////////////////////////////////////////// 
//  Author : Olivier Debon   
//   
 
#include "swf.h" 
 
#ifdef RCSID 
static char *rcsid = "$Id: bitmap.cc,v 1.5 1999/09/09 13:19:01 ode Exp $"; 
#endif 
 
static unsigned char *inputData; 
 
// Class variables 
 
int Bitmap::haveTables = 0; 
 
struct jpeg_decompress_struct Bitmap::jpegObject; 
 
struct jpeg_source_mgr Bitmap::jpegSourceManager; 
 
MyErrorHandler Bitmap::jpegErrorMgr; 
 
Bitmap::Bitmap(long id, int level) : Character(BitmapType, id ) 
{ 
    pixels = NULL; 
    alpha_buf = NULL; 
    colormap = NULL; 
    nbColors = 0; 
    defLevel = level; 
} 
 
Bitmap::~Bitmap() 
{ 
	if (pixels) { 
		delete[] pixels; 
	} 
        if (alpha_buf) { 
            delete[] alpha_buf; 
        } 
	if (colormap) 
	{ 
		delete colormap; 
	} 
	if (haveTables) { 
		jpeg_destroy_decompress(&jpegObject); 
		haveTables = 0; 
	} 
} 
 
static void errorExit(j_common_ptr info) 
{ 
	(*info->err->output_message) (info); 
	longjmp(((MyErrorHandler *)info->err)->setjmp_buffer, 1); 
} 
 
// Methods for Source data manager 
static void initSource(struct jpeg_decompress_struct *cInfo) 
{ 
	cInfo->src->bytes_in_buffer = 0; 
} 
 
static boolean fillInputBuffer(struct jpeg_decompress_struct *cInfo) 
{ 
	cInfo->src->next_input_byte = inputData; 
	cInfo->src->bytes_in_buffer = 1; 
	inputData++; 
 
	return 1; 
} 
 
static void skipInputData(struct jpeg_decompress_struct *cInfo, long count) 
{ 
	cInfo->src->bytes_in_buffer = 0; 
	inputData += count; 
} 
 
static boolean resyncToRestart(struct jpeg_decompress_struct *cInfo, int desired) 
{ 
	return jpeg_resync_to_restart(cInfo, desired); 
} 
 
static void termSource(struct jpeg_decompress_struct *cInfo) 
{ 
} 
 
long Bitmap::getWidth() 
{ 
	return width; 
} 
 
long Bitmap::getHeight() 
{ 
	return height; 
} 
 
Color * 
Bitmap::getColormap(long *n) { 
       if (n) *n = nbColors; 
       return colormap; 
} 
 
unsigned char * 
Bitmap::getPixels() 
{ 
       return pixels; 
} 
 
// Read Tables and Compressed data to produce an image 
 
static int buildJpegAlpha(Bitmap *b, unsigned char *buffer) 
{ 
    z_stream	stream; 
    int		status; 
    unsigned char  *data; 
 
    data = new unsigned char[b->width*b->height]; 
    if (data == NULL)  
        return -1; 
 
    stream.next_in = buffer; 
    stream.avail_in = 1; 
    stream.next_out = data; 
    stream.avail_out = b->width*b->height; 
    stream.zalloc = Z_NULL; 
    stream.zfree = Z_NULL; 
             
    status = inflateInit(&stream); 
 
    while (1) { 
        status = inflate(&stream, Z_SYNC_FLUSH) ; 
        if (status == Z_STREAM_END) { 
            break; 
        } 
        if (status != Z_OK) { 
            printf("Zlib data error : %s\n", stream.msg); 
	    delete data; 
            return -1; 
        } 
        stream.avail_in = 1; 
    } 
 
    inflateEnd(&stream); 
             
    b->alpha_buf = data; 
 
    return 0; 
} 
 
int 
Bitmap::buildFromJpegInterchangeData(unsigned char *stream, int read_alpha, long offset) 
{ 
	struct jpeg_decompress_struct cInfo; 
	struct jpeg_source_mgr mySrcMgr; 
	MyErrorHandler errorMgr; 
	JSAMPROW buffer[1]; 
	unsigned char *ptrPix; 
	int stride; 
	long n; 
 
#if PRINT&1 
        printf("flash: loading jpeg (interchange)\n"); 
#endif 
 
	// Kludge to correct some corrupted files 
	if (stream[1] == 0xd9 && stream[3] == 0xd8) { 
		stream[3] = 0xd9; 
		stream[1] = 0xd8; 
	} 
 
	// Setup error handler 
	cInfo.err = jpeg_std_error(&errorMgr.pub); 
	errorMgr.pub.error_exit = errorExit; 
 
	if (setjmp(errorMgr.setjmp_buffer)) { 
		// JPEG data Error 
		jpeg_destroy_decompress(&cInfo); 
		if (pixels) { 
			delete[] pixels; 
			pixels = NULL; 
		} 
		return -1; 
	} 
 
	// Set current stream pointer to stream 
	inputData = stream; 
 
	// Here it's Ok 
 
	jpeg_create_decompress(&cInfo); 
 
	// Setup source manager structure 
	mySrcMgr.init_source = initSource; 
	mySrcMgr.fill_input_buffer = fillInputBuffer; 
	mySrcMgr.skip_input_data = skipInputData; 
	mySrcMgr.resync_to_restart = resyncToRestart; 
	mySrcMgr.term_source = termSource; 
 
	// Set default source manager 
	cInfo.src = &mySrcMgr; 
 
	jpeg_read_header(&cInfo, FALSE); 
 
	jpeg_read_header(&cInfo, TRUE); 
	cInfo.quantize_colors = TRUE;	// Create colormapped image 
	jpeg_start_decompress(&cInfo); 
 
	// Set objet dimensions 
	height = cInfo.output_height; 
	width = cInfo.output_width; 
        bpl = width; 
	pixels = new unsigned char [height*width]; 
	if (pixels == NULL) { 
		jpeg_finish_decompress(&cInfo); 
		jpeg_destroy_decompress(&cInfo); 
		return -1; 
	} 
	ptrPix = pixels; 
 
	stride = cInfo.output_width * cInfo.output_components; 
 
	buffer[0] = (JSAMPROW)malloc(stride); 
 
	while (cInfo.output_scanline < cInfo.output_height) { 
 
		jpeg_read_scanlines(&cInfo, buffer, 1); 
 
		memcpy(ptrPix,buffer[0],stride); 
 
		ptrPix+= stride; 
	} 
 
        free(buffer[0]); 
 
	colormap = new Color[cInfo.actual_number_of_colors]; 
	if (colormap == NULL) { 
		delete pixels; 
		jpeg_finish_decompress(&cInfo); 
		jpeg_destroy_decompress(&cInfo); 
		return -1; 
	} 
	nbColors = cInfo.actual_number_of_colors; 
 
	for(n=0; n < nbColors; n++) 
	{ 
		colormap[n].red = cInfo.colormap[0][n]; 
		colormap[n].green = cInfo.colormap[1][n]; 
		colormap[n].blue = cInfo.colormap[2][n]; 
	} 
 
	jpeg_finish_decompress(&cInfo); 
	jpeg_destroy_decompress(&cInfo); 
 
        if (read_alpha) { 
            if (buildJpegAlpha(this,  stream + offset) < 0) { 
	    	return -1; 
	    } 
        } 
	return 0; 
} 
 
// Read JPEG image using pre-loaded Tables 
 
int 
Bitmap::buildFromJpegAbbreviatedData(unsigned char *stream) 
{ 
	JSAMPROW buffer[1]; 
	unsigned char *ptrPix; 
	int stride; 
	long n; 
	int status; 
 
#if PRINT&1 
        printf("flash: loading jpeg (abbreviated)\n"); 
#endif 
 
	// Set current stream pointer to stream 
	inputData = stream; 
 
	// Error handler 
	if (setjmp(jpegErrorMgr.setjmp_buffer)) { 
		// JPEG data Error 
		//jpeg_destroy_decompress(&jpegObject); 
		if (pixels) { 
			delete[] pixels; 
			pixels = NULL; 
		} 
		return -1; 
	} 
 
	// Here it's ok 
 
	jpeg_read_header(&jpegObject, TRUE); 
	jpegObject.quantize_colors = TRUE;	// Create colormapped image 
	jpeg_start_decompress(&jpegObject); 
 
	// Set objet dimensions 
	height = jpegObject.output_height; 
	width = jpegObject.output_width; 
        bpl = width; 
	pixels = new unsigned char [height*width]; 
	if (pixels == NULL) { 
		jpeg_finish_decompress(&jpegObject); 
		return -1; 
	} 
	ptrPix = pixels; 
 
	stride = jpegObject.output_width * jpegObject.output_components; 
 
	buffer[0] = (JSAMPROW)malloc(stride); 
 
	while (jpegObject.output_scanline < jpegObject.output_height) { 
 
		status = jpeg_read_scanlines(&jpegObject, buffer, 1); 
 
		memcpy(ptrPix,buffer[0],stride); 
 
		ptrPix+= stride; 
	} 
         
        free(buffer[0]); 
 
	colormap = new Color[jpegObject.actual_number_of_colors]; 
	if (colormap == NULL) { 
		jpeg_finish_decompress(&jpegObject); 
		delete pixels; 
		return -1; 
	} 
	nbColors = jpegObject.actual_number_of_colors; 
 
	for(n=0; n < nbColors; n++) 
	{ 
		colormap[n].red = jpegObject.colormap[0][n]; 
		colormap[n].green = jpegObject.colormap[1][n]; 
		colormap[n].blue = jpegObject.colormap[2][n]; 
	} 
 
	status = jpeg_finish_decompress(&jpegObject); 
 
	return 0; 
} 
 
// Just init JPEG object and read JPEG Tables 
 
int 
Bitmap::readJpegTables(unsigned char *stream) 
{ 
	if (haveTables) { 
		//Error, it has already been initialized 
		return -1; 
	} 
 
	// Setup error handler 
	jpegObject.err = jpeg_std_error(&jpegErrorMgr.pub); 
	jpegErrorMgr.pub.error_exit = errorExit; 
 
	if (setjmp(jpegErrorMgr.setjmp_buffer)) { 
		// JPEG data Error 
		jpeg_destroy_decompress(&jpegObject); 
		return -1; 
	} 
 
	// Set current stream pointer to stream 
	inputData = stream; 
 
	// Here it's Ok 
 
	jpeg_create_decompress(&jpegObject); 
 
	// Setup source manager structure 
	jpegSourceManager.init_source = initSource; 
	jpegSourceManager.fill_input_buffer = fillInputBuffer; 
	jpegSourceManager.skip_input_data = skipInputData; 
	jpegSourceManager.resync_to_restart = resyncToRestart; 
	jpegSourceManager.term_source = termSource; 
 
	// Set default source manager 
	jpegObject.src = &jpegSourceManager; 
 
	jpeg_read_header(&jpegObject, FALSE); 
 
	haveTables = 1; 
 
	return 0; 
} 
 
int Bitmap::buildFromZlibData(unsigned char *buffer, int width, int height, int format, int tableSize) 
{ 
	z_stream	stream; 
	int		status; 
	unsigned char  *data; 
 
#if PRINT&1 
        printf("flash: loading with zlib\n"); 
#endif 
 
	this->width = width; 
	this->height = height; 
        this->bpl = width; 
 
	stream.next_in = buffer; 
	stream.avail_in = 1; 
	stream.zalloc = Z_NULL; 
	stream.zfree = Z_NULL; 
 
	tableSize++; 
 
	// Uncompress Color Table 
	if (format == 3) { 
		unsigned char *colorTable; 
		long n; 
 
		// Ajust width for 32 bit padding 
		width = (width+3)/4*4; 
		this->width = width; 
		this->bpl = width; 
 
		depth = 1; 
		colorTable = new unsigned char[tableSize*3]; 
		if (colorTable == NULL) { 
			return -1; 
		} 
 
		stream.next_out = colorTable; 
		stream.avail_out = tableSize*3; 
 
		inflateInit(&stream); 
 
		while (1) { 
			status = inflate(&stream, Z_SYNC_FLUSH); 
			if (status == Z_STREAM_END) { 
					break; 
			} 
			if (status != Z_OK) { 
				printf("Zlib cmap error : %s\n", stream.msg); 
				return -1; 
			} 
			stream.avail_in = 1; 
			// Colormap if full 
			if (stream.avail_out == 0) { 
				break; 
			} 
		} 
 
		nbColors = tableSize; 
 
		colormap = new Color[nbColors]; 
		if (colormap == NULL) { 
			delete colorTable; 
			return -1; 
		} 
 
		for(n=0; n < nbColors; n++) { 
			colormap[n].red = colorTable[n*3+0]; 
			colormap[n].green = colorTable[n*3+1]; 
			colormap[n].blue = colorTable[n*3+2]; 
		} 
 
		delete colorTable; 
 
	} else if (format == 4) { 
		depth = 2; 
	} else if (format == 5) { 
		depth = 4; 
	} 
 
	data = new unsigned char[depth*width*height]; 
	if (data == NULL) { 
		if (colormap) delete colormap; 
		return -1; 
	} 
 
	stream.next_out = data; 
	stream.avail_out = depth*width*height; 
 
	if (format != 3) { 
		status = inflateInit(&stream); 
	} 
 
	while (1) { 
		status = inflate(&stream, Z_SYNC_FLUSH) ; 
		if (status == Z_STREAM_END) { 
				break; 
		} 
		if (status != Z_OK) { 
			printf("Zlib data error : %s\n", stream.msg); 
			delete data; 
			return -1; 
		} 
		stream.avail_in = 1; 
	} 
 
	inflateEnd(&stream); 
 
	pixels = new unsigned char [height*width]; 
	if (pixels == NULL) { 
		if (colormap) delete colormap; 
		delete data; 
		return -1; 
	} 
 
	if (format != 3) { 
		int n,c; 
		unsigned char r,g,b,a; 
		unsigned char *ptr; 
 
                r = g = b = a = 0; /* to supress warnings */ 
 
		nbColors = 0; 
		colormap = new Color[256]; 
		if (colormap == NULL) { 
			delete data; 
			delete pixels; 
			return -1; 
		} 
                memset(colormap, 0, 256 * sizeof(Color)); 
		ptr = pixels; 
		 
		for(n=0; n < width*height*depth; n+=depth,ptr++) { 
                     
			switch (format) { 
				case 4: 
					break; 
				case 5: 
					a = data[n]; 
					// Reduce color dynamic range 
					r = data[n+1]&0xe0; 
					g = data[n+2]&0xe0; 
					b = data[n+3]&0xe0; 
					break; 
			} 
			for(c=0; c < nbColors; c++) { 
				if (r == colormap[c].red 
				&&  g == colormap[c].green 
				&&  b == colormap[c].blue) { 
					*ptr = c; 
					break; 
				} 
			} 
			if (c == nbColors) { 
				if (nbColors == 256) continue; 
				nbColors++; 
				if (nbColors == 256) { 
					//printf("Colormap entries exhausted. After %d scanned pixels\n", n/4); 
				} 
				colormap[c].alpha = a; 
				colormap[c].red   = r; 
				colormap[c].green = g; 
				colormap[c].blue  = b; 
				*ptr = c; 
			} 
		} 
	} else { 
		memcpy(pixels, data, width*height); 
	} 
 
	delete data; 
	return 0; 
}