Updated the gfli plug-in to the version on the registry and folded the patch

for the "chunk-type-7-bug" back in.


--Sven
This commit is contained in:
Sven Neumann 1998-05-18 18:34:11 +00:00
parent eface111d7
commit 63a96d867d
3 changed files with 278 additions and 355 deletions

View File

@ -1,3 +1,8 @@
Mon May 18 20:30:44 MEST 1998 Sven Neumann <sven@gimp.org>
* updated the gfli plug-in to the version on the registry and
folded the "chunk-type-7-bug"-patch back in
Sun May 17 23:06:38 EDT 1998 Matthew Wilson <msw@gimp.org>
* app/app_procs.c: applied patch from Michael Sweet to correct
@ -157,7 +162,7 @@ Sun May 3 22:10:05 EDT 1998 Matthew Wilson <msw@gimp.org>
Sun May 3 00:24:31 MEST 1998 Sven Neumann <sven@gimp.org>
* app/channels_dialog.c: minimalistic change to the interface,
make it's possible to set the channel opacity to 100.0%
makes it possible to set the channel opacity to 100.0%
(was 99.0% before)
Sat May 2 14:31:46 PDT 1998 Manish Singh <yosh@gimp.org>

View File

@ -5,6 +5,8 @@ pluginlibdir = $(gimpplugindir)/plug-ins
pluginlib_PROGRAMS = gfli
gfli_SOURCES = \
fli.h \
fli.c \
gfli.c
INCLUDES = \

View File

@ -1,9 +1,9 @@
/*
* GFLI 1.0
*
* A gimp plug-in to read FLI and FLC movies.
* A gimp plug-in to read and write FLI and FLC movies.
*
* Copyright (C) 1997 Jens Ch. Restemeier <jchrr@hrz.uni-bielefeld.de>
* Copyright (C) 1998 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
@ -17,19 +17,16 @@
*
* 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.
* 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...
* - doesn't support palette changes between two frames.
*
* Wish-List:
* - I'd like to have a different format for storing animations, so I can use
@ -41,382 +38,142 @@
* 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 ?
*
* - I've thought about a small utility to mix MIDI events as custom chunks
* between the FLI chunks. Anyone interested in implementing this ?
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
gint32 load_image (char *filename);
#include "fli.h"
GPlugInInfo PLUG_IN_INFO =
{
static void query (void);
static void run (gchar *name, gint nparams, GParam *param, gint *nreturn_vals, GParam **return_vals);
static gint32 load_image (gchar *filename);
static void save_image (gchar *filename, gint32 image);
GPlugInInfo PLUG_IN_INFO = {
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
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" },
};
GParamDef load_return_vals[] = {
{ PARAM_IMAGE, "image", "Output image" },
};
gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
gint nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
GParamDef save_args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_STRING, "filename", "The name of the file to save" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
GParamDef save_return_vals[] = {
};
gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gint nsave_return_vals = sizeof (save_return_vals) / sizeof (save_return_vals[0]);
MAIN ()
static void
query ()
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 FLI-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", "", "4,byte,0x11,4,byte,0x12,5,byte,0xAF");
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", "", "4,short,0x11af,4,short,0x12af");
gimp_install_procedure (
"file_fli_save",
"save FLI-movies",
"This is a experimantal plug-in to handle FLI movies",
"Jens Ch. Restemeier",
"Jens Ch. Restemeier",
"1997",
"<Save>/FLI",
"INDEXED,GRAY",
PROC_PLUG_IN,
nsave_args, nsave_return_vals,
save_args, save_return_vals);
gimp_register_save_handler ("file_fli_save", "fli", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
GParam values[2];
void run (gchar *name, gint nparams, GParam *param, gint *nreturn_vals, GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
gint32 image_ID;
GRunModeType run_mode;
gint32 image_ID;
run_mode = param[0].data.d_int32;
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;
*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 (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 */
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 {
fprintf(stderr, "error: magic number is wrong !\n");
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
return;
}
if (strcmp (name, "file_fli_save") == 0) {
if (param[1].type == PARAM_IMAGE) {
save_image (param[3].data.d_string, param[1].data.d_image);
*nreturn_vals = 1;
values[0].data.d_status = STATUS_SUCCESS;
} else {
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
return;
}
}
void fli_read_frame(FILE *f, s_fli_header *fli_header, guchar *framebuf, guchar *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;
guchar *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;
guchar *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;
guchar *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;
guchar *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; */ /* BANG! */
yc+=0x10000-pc; /* better */
} 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)
/*
* load fli animation and store as framestack
*/
gint32 load_image (gchar *filename)
{
FILE *f;
char *name_buf;
gchar *name_buf;
GDrawable *drawable;
gint32 image_ID, layer_ID;
guchar *frame_buffer;
guchar cmap[768];
gchar *fb, *ofb, *fb_x;
gchar cm[768], ocm[768];
GPixelRgn pixel_rgn;
s_fli_header fli_header;
int cnt;
gint cnt;
name_buf = g_malloc (64);
@ -425,7 +182,7 @@ gint32 load_image (char *filename)
f=fopen(filename ,"r");
if (!f) {
printf ("FLI: can't open \"%s\"\n", filename);
fprintf (stderr, "FLI: can't open \"%s\"\n", filename);
return -1;
}
fli_read_header(f, &fli_header);
@ -434,30 +191,189 @@ gint32 load_image (char *filename)
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++) {
fb=g_malloc(fli_header.width * fli_header.height);
ofb=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);
gimp_image_add_layer (image_ID, layer_ID, cnt);
drawable = gimp_drawable_get (layer_ID);
gimp_progress_update ((double) cnt / fli_header.frames);
gimp_progress_update ((double) cnt / (double)fli_header.frames);
fli_read_frame(f, &fli_header, frame_buffer, cmap);
fli_read_frame(f, &fli_header, ofb, ocm, fb, cm);
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_pixel_rgn_set_rect (&pixel_rgn, fb, 0, 0, fli_header.width, fli_header.height);
gimp_drawable_flush (drawable);
gimp_drawable_detach (drawable);
memcpy(ocm, cm, 768);
fb_x=fb; fb=ofb; ofb=fb_x;
}
gimp_image_set_cmap (image_ID, cmap, 256);
gimp_image_set_cmap (image_ID, cm, 256);
fclose(f);
g_free (name_buf);
g_free(frame_buffer);
g_free(name_buf);
g_free(fb);
g_free(ofb);
return image_ID;
}
/*
* get framestack and store as fli animation
* (some code was taken from the GIF plugin.)
*/
void save_image(gchar *filename, gint32 image_ID)
{
FILE *f;
gchar *name_buf;
GDrawable *drawable;
GDrawableType drawable_type;
gint32 *framelist;
gint nframes;
gchar *fb, *ofb;
gchar cm[768];
GPixelRgn pixel_rgn;
s_fli_header fli_header;
gint cnt;
/*
* prepare header and check information
*/
framelist = gimp_image_get_layers(image_ID, &nframes);
drawable_type = gimp_drawable_type(framelist[0]);
switch (drawable_type) {
case INDEXEDA_IMAGE:
case GRAYA_IMAGE:
/* FIXME: should be a popup */
fprintf (stderr, "FLI: Sorry, can't save images with Alpha.\n");
return;
break;
case GRAY_IMAGE: {
/* build grayscale palette */
int i;
for (i=0; i<256; i++) {
cm[i*3+0]=cm[i*3+1]=cm[i*3+2]=i;
}
break;
}
case INDEXED_IMAGE: {
gint colors, i;
gchar *cmap;
cmap=gimp_image_get_cmap(image_ID, &colors);
for (i=0; i<colors; i++) {
cm[i*3+0]=cmap[i*3+0];
cm[i*3+1]=cmap[i*3+1];
cm[i*3+2]=cmap[i*3+2];
}
for (i=colors; i<256; i++) {
cm[i*3+0]=cm[i*3+1]=cm[i*3+2]=i;
}
break;
}
default:
/* FIXME: should be a popup */
fprintf (stderr, "FLI: Sorry, I can save only INDEXED and GRAY images.\n");
return;
break;
}
name_buf = g_malloc (64);
sprintf (name_buf, "Saving %s:", filename);
gimp_progress_init (name_buf);
/*
* First build the fli header.
*/
fli_header.filesize=0; /* will be fixed when writing the header */
fli_header.frames=0; /* will be fixed during the write */
fli_header.width=gimp_image_width(image_ID);
fli_header.height=gimp_image_height(image_ID);
if ((fli_header.width==320) && (fli_header.height=200)) {
fli_header.magic=HEADER_FLI;
} else {
fli_header.magic=HEADER_FLC;
}
fli_header.depth=8; /* I've never seen a depth != 8 */
fli_header.flags=3;
fli_header.speed=1000/25;
fli_header.created=0; /* program ID. not neccessary... */
fli_header.updated=0; /* date in MS-DOS format. ignore...*/
fli_header.aspect_x=1; /* aspect ratio. Will be added as soon.. */
fli_header.aspect_y=1; /* ... as GIMP supports it. */
f=fopen(filename ,"w");
if (!f) {
fprintf (stderr, "FLI: can't open \"%s\"\n", filename);
}
fseek(f,128,SEEK_SET);
fb=g_malloc(fli_header.width * fli_header.height);
ofb=g_malloc(fli_header.width * fli_header.height);
/*
* Now write all frames
*/
for (cnt=0; cnt<nframes; cnt++) {
gint offset_x, offset_y, xc, yc;
guint rows, cols, rowstride;
gchar *tmp;
gimp_progress_update ((double) cnt / (double)nframes);
/* get layer data from GIMP */
drawable = gimp_drawable_get (framelist[cnt]);
gimp_drawable_offsets (framelist[cnt], &offset_x, &offset_y);
cols = drawable->width;
rows = drawable->height;
rowstride = drawable->width;
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
tmp=malloc(cols * rows);
gimp_pixel_rgn_get_rect (&pixel_rgn, tmp, 0, 0, drawable->width, drawable->height);
/* now paste it into the framebuffer, with the neccessary offset */
for (yc=0; yc<cols; yc++) {
int yy;
yy=yc+offset_y;
if ((yy>0) && (yy<fli_header.height)) {
for (xc=0; xc<cols; xc++) {
int xx;
xx=xc+offset_x;
if ((xx>0) && (xx<fli_header.width)) {
fb[yy*fli_header.width + xx]=tmp[yc*cols+xc];
}
}
}
}
free(tmp);
/* save the frame */
if (cnt>0) {
/* save frame, allow all codecs */
fli_write_frame(f, &fli_header, ofb, cm, fb, cm, W_ALL);
} else {
/* save first frame, no delta information, allow all codecs */
fli_write_frame(f, &fli_header, NULL, NULL, fb, cm, W_ALL);
}
memcpy(ofb, fb, fli_header.width * fli_header.height);
}
/*
* finish fli
*/
fli_write_header(f, &fli_header);
fclose(f);
g_free(name_buf);
g_free(fb);
g_free(ofb);
g_free(framelist);
}