diff --git a/ChangeLog b/ChangeLog index a90ce89a71..0c9b5b0eab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon May 18 20:30:44 MEST 1998 Sven Neumann + + * 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 * 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 Sun May 3 00:24:31 MEST 1998 Sven Neumann * 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 diff --git a/plug-ins/gfli/Makefile.am b/plug-ins/gfli/Makefile.am index 030e0c9ca8..1f955822c1 100644 --- a/plug-ins/gfli/Makefile.am +++ b/plug-ins/gfli/Makefile.am @@ -5,6 +5,8 @@ pluginlibdir = $(gimpplugindir)/plug-ins pluginlib_PROGRAMS = gfli gfli_SOURCES = \ + fli.h \ + fli.c \ gfli.c INCLUDES = \ diff --git a/plug-ins/gfli/gfli.c b/plug-ins/gfli/gfli.c index 5b85d1219c..efcb0af322 100644 --- a/plug-ins/gfli/gfli.c +++ b/plug-ins/gfli/gfli.c @@ -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 + * Copyright (C) 1998 Jens Ch. Restemeier * * 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 #include #include -#include #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", + "/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", - "/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", + "/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;c0; 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; iwidth; + 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; yc0) && (yy0) && (xx0) { + /* 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); +}