gimp/plug-ins/gfli/gfli.c

468 lines
12 KiB
C
Raw Normal View History

1997-11-25 06:05:25 +08:00
/*
* GFLI 1.0
*
* A gimp plug-in to read FLI and FLC movies.
*
* Copyright (C) 1997 Jens Ch. Restemeier <jchrr@hrz.uni-bielefeld.de>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This is a first loader for FLI and FLC movies. It uses as the same method as
* the gif plug-in to store the animation (i.e. 1 layer/frame).
*
* Current disadvantages:
* - All frames must share the same colormap. Maybe I add an option for
* generating RGB images in the next version !
* - Generates A LOT OF warnings.
* - Consumes a lot of memory (See wish-list: use the original data or
* compression).
* - doesn't save movies (will be added to next version, depends on
* feedback). You can save as animated GIF, of course...
*
* Wish-List:
* - I'd like to have a different format for storing animations, so I can use
* Layers and Alpha-Channels for effects. I'm working on another movie-loader
* that _requires_ layers (Gold Disk moviesetter). An older version of
* this plug-in created one image per frame, and went real soon out of
* memory.
* - I'd like a method that requests unmodified frames from the original
* image, and stores modified frames compressed (suggestion: libpng).
* - I'd like a way to store additional information about a image to it, for
* example copyright stuff or a timecode.
*
* Ideas:
* - I could put all the functions for loading / saving fli into a
* gimp-independant library. Anybody interested to save fli from his
* application ?
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#ifdef __GNUC__
#define inline inline
#else
#define inline
#endif
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
gint32 load_image (char *filename);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
gimp_install_procedure ("file_fli_load",
"load AA-movies",
"This is a experimantal plug-in to handle FLI movies",
"Jens Ch. Restemeier",
"Jens Ch. Restemeier",
"1997",
"<Load>/FLI",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_register_magic_load_handler ("file_fli_load", "fli,flc", "", "5,byte,175 ");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_fli_load") == 0)
{
image_ID = load_image (param[1].data.d_string);
if (image_ID != -1)
{
*nreturn_vals = 2;
values[0].data.d_status = STATUS_SUCCESS;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
}
else
{
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
}
typedef struct _fli_header {
unsigned long filesize;
unsigned short magic;
unsigned short frames;
unsigned short width;
unsigned short height;
unsigned short depth;
unsigned short flags;
unsigned long speed;
} s_fli_header;
typedef struct _fli_frame {
unsigned long framesize;
unsigned short magic;
unsigned short chunks;
} s_fli_frame;
/* read byte/word/long */
inline unsigned char fli_read_char(FILE *f)
{
unsigned char b;
fread(&b,1,1,f);
return b;
}
inline unsigned short fli_read_short(FILE *f)
{
unsigned char b[2];
fread(&b,1,2,f);
return (unsigned short)(b[1]<<8) | b[0];
}
inline unsigned long fli_read_long(FILE *f)
{
unsigned char b[4];
fread(&b,1,4,f);
return (unsigned long)(b[3]<<24) | (b[2]<<16) | (b[1]<<8) | b[0];
}
void fli_read_header(FILE *f, s_fli_header *fli_header)
{
fli_header->filesize=fli_read_long(f); /* 0 */
fli_header->magic=fli_read_short(f); /* 4 */
fli_header->frames=fli_read_short(f); /* 6 */
fli_header->width=fli_read_short(f); /* 8 */
fli_header->height=fli_read_short(f); /* 10 */
fli_header->depth=fli_read_short(f); /* 12 */
fli_header->flags=fli_read_short(f); /* 14 */
if (fli_header->magic == 0xAF11) { /* FLI */
/* FLI saves speed in 1/70s */
fli_header->speed=fli_read_short(f)*14; /* 16 */
} else {
if (fli_header->magic == 0xAF12) { /* FLC */
/* FLC saves speed in 1/1000s */
fli_header->speed=fli_read_long(f); /* 16 */
} else {
fprintf(stderr, "error: magic number is wrong !\n");
}
}
}
void fli_read_frame(FILE *f, s_fli_header *fli_header, gchar *framebuf, gchar *cmap)
{
s_fli_frame fli_frame;
unsigned long framepos;
int c;
unsigned short col_pos;
col_pos=0;
framepos=ftell(f);
fli_frame.framesize=fli_read_long(f);
fli_frame.magic=fli_read_short(f);
fli_frame.chunks=fli_read_short(f);
if (fli_frame.magic == 0xF1FA) {
fseek(f, framepos+16, SEEK_SET);
for (c=0;c<fli_frame.chunks;c++) {
unsigned long chunkpos, chunksize;
unsigned short chunktype;
chunkpos = ftell(f);
chunksize=fli_read_long(f);
chunktype=fli_read_short(f);
switch (chunktype) {
case 11 : { /* fli_color */
unsigned short num_packets;
int cnt_packets;
num_packets=fli_read_short(f);
for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
unsigned short skip_col, num_col, col_cnt;
skip_col=fli_read_char(f);
num_col=fli_read_char(f);
if (num_col == 0) {
for (col_pos=0; col_pos<768; col_pos++) {
cmap[col_pos]=fli_read_char(f)<<2;
}
} else {
col_pos+=(skip_col*3);
for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
cmap[col_pos++]=fli_read_char(f)<<2;
cmap[col_pos++]=fli_read_char(f)<<2;
cmap[col_pos++]=fli_read_char(f)<<2;
}
}
}
break;
}
case 13 : /* fli_black */
memset(framebuf, 0, fli_header->width * fli_header->height);
break;
case 15 : { /* fli_brun */
unsigned short yc;
char *pos;
for (yc=0; yc< fli_header->height; yc++) {
unsigned short xc, pc, pcnt;
pc=fli_read_char(f);
xc=0;
pos=framebuf+(fli_header->width * yc);
for (pcnt=pc; pcnt>0; pcnt --) {
unsigned short ps;
ps=fli_read_char(f);
if (ps & 0x80) {
unsigned short len;
ps^=0xFF;
ps+=1;
for (len=ps; len>0; len--) {
pos[xc++]=fli_read_char(f);
}
} else {
unsigned char val;
val=fli_read_char(f);
memset(&(pos[xc]), val, ps);
xc+=ps;
}
}
}
break;
}
case 16 : { /* fli_copy */
unsigned long cc;
char *pos;
pos=framebuf;
for (cc=fli_header->width * fli_header->height; cc>0; cc--) {
*(pos++)=fli_read_char(f);
}
break;
}
case 12 : { /* fli_lc */
unsigned short yc, firstline, numline;
char *pos;
firstline = fli_read_short(f);
numline = fli_read_short(f);
for (yc=0; yc < numline; yc++) {
unsigned short xc, pc, pcnt;
pc=fli_read_char(f);
xc=0;
pos=framebuf+(fli_header->width * (firstline+yc));
for (pcnt=pc; pcnt>0; pcnt --) {
unsigned short ps,skip;
skip=fli_read_char(f);
ps=fli_read_char(f);
xc+=skip;
if (ps & 0x80) {
unsigned char val;
ps^=0xFF;
ps+=1;
val=fli_read_char(f);
memset(&(pos[xc]), val, ps);
xc+=ps;
} else {
unsigned short len;
for (len=ps; len>0; len--) {
pos[xc++]=fli_read_char(f);
}
}
}
}
break;
}
case 7 : { /* fli_lc2 */
unsigned short yc, lc, numline;
char *pos;
yc=0;
numline = fli_read_short(f);
for (lc=0; lc < numline; lc++) {
unsigned short xc, pc, pcnt, lpf, lpn;
pc=fli_read_short(f);
lpf=0; lpn=0;
while (pc & 0x8000) {
if (pc & 0x4000) {
yc+=pc & 0x3FFF;
} else {
lpf=1;lpn=pc&0xFF;
}
pc=fli_read_short(f);
}
xc=0;
pos=framebuf+(fli_header->width * yc);
for (pcnt=pc; pcnt>0; pcnt --) {
unsigned short ps,skip;
skip=fli_read_char(f);
ps=fli_read_char(f);
xc+=skip;
if (ps & 0x80) {
unsigned char v1,v2;
ps^=0xFF;
ps++;
v1=fli_read_char(f);
v2=fli_read_char(f);
while (ps>0) {
pos[xc++]=v1;
pos[xc++]=v2;
ps--;
}
} else {
unsigned short len;
for (len=ps; len>0; len--) {
pos[xc++]=fli_read_char(f);
pos[xc++]=fli_read_char(f);
}
}
}
if (lpf) pos[xc]=lpn;
yc++;
}
break;
}
case 4 : { /* fli_color_2 */
unsigned short num_packets;
int cnt_packets;
num_packets=fli_read_short(f);
col_pos=0;
for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
unsigned short skip_col, num_col, col_cnt;
skip_col=fli_read_char(f);
num_col=fli_read_char(f);
if (num_col == 0) {
for (col_pos=0; col_pos<768; col_pos++) {
cmap[col_pos]=fli_read_char(f);
}
} else {
col_pos+=(skip_col+=3);
for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
cmap[col_pos++]=fli_read_char(f);
cmap[col_pos++]=fli_read_char(f);
cmap[col_pos++]=fli_read_char(f);
}
}
}
break;
}
case 18 : /* fli_mini (ignored) */ break;
}
if (chunksize & 1) chunksize++;
fseek(f,chunkpos+chunksize,SEEK_SET);
}
}
fseek(f, framepos+fli_frame.framesize, SEEK_SET);
}
gint32 load_image (char *filename)
{
FILE *f;
char *name_buf;
GDrawable *drawable;
gint32 image_ID, layer_ID;
gchar *frame_buffer;
gchar cmap[768];
GPixelRgn pixel_rgn;
s_fli_header fli_header;
int cnt;
name_buf = g_malloc (64);
sprintf (name_buf, "Loading %s:", filename);
gimp_progress_init (name_buf);
f=fopen(filename ,"r");
if (!f) {
printf ("FLI: can't open \"%s\"\n", filename);
return -1;
}
fli_read_header(f, &fli_header);
fseek(f,128,SEEK_SET);
image_ID = gimp_image_new (fli_header.width, fli_header.height, INDEXED);
gimp_image_set_filename (image_ID, filename);
frame_buffer=g_malloc(fli_header.width * fli_header.height);
for (cnt=0; cnt< fli_header.frames; cnt++) {
sprintf(name_buf, "Frame (%i)",cnt+1);
layer_ID = gimp_layer_new (
image_ID, name_buf,
fli_header.width, fli_header.height,
INDEXED_IMAGE, 100, NORMAL_MODE);
gimp_image_add_layer (image_ID, layer_ID, 0);
drawable = gimp_drawable_get (layer_ID);
gimp_progress_update ((double) cnt / fli_header.frames);
fli_read_frame(f, &fli_header, frame_buffer, cmap);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, fli_header.width, fli_header.height, TRUE, FALSE);
gimp_pixel_rgn_set_rect (&pixel_rgn, frame_buffer, 0, 0, fli_header.width, fli_header.height);
gimp_drawable_flush (drawable);
gimp_drawable_detach (drawable);
}
gimp_image_set_cmap (image_ID, cmap, 256);
fclose(f);
g_free (name_buf);
g_free(frame_buffer);
return image_ID;
}