mirror of
https://github.com/dyne/FreeJ.git
synced 2026-02-07 21:39:22 +01:00
flash vectorial graphics in a layer git-svn-id: svn://dyne.org/rastasoft/freej/freej@621 383723c8-4afa-0310-b8a8-b1afb83214fc
607 lines
12 KiB
C++
607 lines
12 KiB
C++
/////////////////////////////////////////////////////////////
|
|
// 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 <odebon@club-internet.fr>
|
|
//
|
|
|
|
#include "swf.h"
|
|
|
|
#ifdef RCSID
|
|
static char *rcsid = "$Id: bitmap.cc,v 1.1.1.1 2004/06/04 21:16:31 tgc 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, int tableHasAlpha)
|
|
{
|
|
z_stream stream;
|
|
int status;
|
|
unsigned char *data;
|
|
int elementSize;
|
|
|
|
#if PRINT&1
|
|
printf("flash: loading with zlib\n");
|
|
#endif
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->bpl = width;
|
|
|
|
if (tableHasAlpha) {
|
|
elementSize = 4; // Cmap is RGBA
|
|
} else {
|
|
elementSize = 3; // Cmap is RGB
|
|
}
|
|
|
|
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*elementSize];
|
|
if (colorTable == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
stream.next_out = colorTable;
|
|
stream.avail_out = tableSize*elementSize;
|
|
|
|
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*elementSize+0];
|
|
colormap[n].green = colorTable[n*elementSize+1];
|
|
colormap[n].blue = colorTable[n*elementSize+2];
|
|
if (tableHasAlpha) {
|
|
colormap[n].alpha = colorTable[n*elementSize+3];
|
|
}
|
|
}
|
|
|
|
delete colorTable;
|
|
|
|
} else if (format == 4) {
|
|
depth = 2;
|
|
width = (width+1)/2*2;
|
|
this->bpl = width;
|
|
} 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:
|
|
a = 1;
|
|
r = (data[n] & 0x78)<<1;
|
|
g = ((data[n] & 0x03)<<6) | (data[n+1] & 0xc0)>>2;
|
|
b = (data[n+1] & 0x1e)<<3;
|
|
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);
|
|
if (tableHasAlpha) {
|
|
int n;
|
|
unsigned char *ptr, *alpha;
|
|
|
|
alpha_buf = (unsigned char *)malloc(width*height);
|
|
ptr = data;
|
|
alpha = alpha_buf;
|
|
for(n=0; n < width*height; n++, ptr++, alpha++) {
|
|
*alpha = colormap[*ptr].alpha;
|
|
}
|
|
}
|
|
}
|
|
|
|
delete data;
|
|
return 0;
|
|
}
|
|
|