/* * mng.c -- preliminary mng driver for enfle, using libmng * (C)Copyright 2000 by Hiroshi Takekawa * This file is part of Enfle. * * Last Modified: Wed Aug 2 05:48:56 2000. * $Id: mng.c,v 1.1 2000/08/01 20:50:01 sian Exp $ * * Note: mng implementation is far from complete. * * Enfle 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. * * Enfle 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 */ #include #include #include #include "enfle.h" #include "_mng.h" #include "quantize.h" #include "cmrender.h" #include "plugin.h" #ifndef TRUE # define TRUE 1 # define FALSE 0 #endif int #ifdef PIC get_plugininfo(PluginInfo *p) #else loader_mng_get_plugininfo(PluginInfo *p) #endif { p->version = 1; p->type = _Loader; p->pluginname = "MNG Format Loader Plugin version 0.1"; p->pluginshortname = FORMAT_NAME; p->author = "Hiroshi Takekawa"; p->dlhandle = NULL; /* set by plugin_load */ p->functions.loader.load_image = mng_load_image; return 1; } typedef struct { mng_handle mng; Info *info; Image *p; Image *now; int npics; int rc; unsigned int delay; unsigned int canvas_width; unsigned int canvas_height; unsigned int canvas_bpl; unsigned int canvas_size; unsigned char *canvas_buffer; } MNG_info; /* libmng callbacks */ static mng_ptr memalloc(mng_size_t n) { #ifdef DEBUG fprintf(stderr, "memalloc: request %d bytes\n", n); #endif return calloc(1, n); } static void memfree(mng_ptr p, mng_size_t n) { free(p); } static mng_bool openstream(mng_handle mng) { return MNG_TRUE; } static mng_bool closestream(mng_handle mng) { return MNG_TRUE; } static mng_bool readdata(mng_handle mng, mng_ptr p, mng_uint32 len, mng_uint32 *readsize) { MNG_info *this = (MNG_info *)mng_get_userdata(mng); if (archive_read(this->info->ar, p, len) != len) { *readsize = 0; return MNG_FALSE; } *readsize = len; return MNG_TRUE; } static mng_bool processheader(mng_handle mng, mng_uint32 width, mng_uint32 height) { MNG_info *this = (MNG_info *)mng_get_userdata(mng); this->info->swidth = width; this->info->sheight = height; this->canvas_width = width; this->canvas_height = height; this->canvas_bpl = width * 3; this->canvas_size = this->canvas_bpl * height; this->canvas_buffer = calloc(1, this->canvas_size); mng_set_canvasstyle (mng, MNG_CANVAS_RGB8); return MNG_TRUE; } static mng_ptr getcanvasline(mng_handle mng, mng_uint32 nthline) { MNG_info *this = (MNG_info *)mng_get_userdata(mng); unsigned char *pp = &this->canvas_buffer[this->canvas_bpl * nthline]; return (mng_ptr) pp; } static mng_bool refresh(mng_handle mng, mng_uint32 left, mng_uint32 top, mng_uint32 width, mng_uint32 height) { MNG_info *this = (MNG_info *)mng_get_userdata(mng); Image *p; unsigned char *s, *d; int y; #ifdef DEBUG fprintf(stderr, "refresh(): (%d,%d)-(%d,%d)\n", left, top, left + width, top + height); #endif if (this->now == NULL) this->now = this->p; else { this->now->next = image_allocate(); this->now = this->now->next; } p = this->now; p->left = left; p->top = top; p->width = width; p->height = height; p->type = _RGB24; p->bytes_per_line = image_calculate_bytes_per_line(p->width, _RGB24); p->image_size = p->bytes_per_line * height; p->image = d = calloc(1, p->image_size); s = &this->canvas_buffer[this->canvas_bpl * top + left * 3]; for (y = 0; y < height; y++) { memcpy(d, s, width * 3); s += this->canvas_bpl; d += p->bytes_per_line; } this->npics++; return MNG_TRUE; } static mng_uint32 gettickcount(mng_handle mng) { struct timeval tv; gettimeofday(&tv, NULL); return (tv.tv_sec * 1000 * 1000 + tv.tv_usec) / 1000; } static mng_bool settimer(mng_handle mng, mng_uint32 msec) { MNG_info *this = (MNG_info *)mng_get_userdata(mng); this->now->delay = msec; return MNG_TRUE; } static mng_bool errorproc(mng_handle mng, mng_int32 errcode, mng_int8 severity, mng_chunkid chunkname, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar errtext) { unsigned int c = chunkname; fprintf(stderr, "mng_errorproc: [%c%c%c%c]: errcode %d: %s\n", c >> 24, c >> 16, c >> 8, c & 0xff, errcode, errtext); return MNG_TRUE; } /* end of libmng callbacks */ /* Static variable for signal handler */ static Info *global_info; static void mng_alarmset(Info *info) { struct itimerval value; Image *p = info->shown_image; global_info = info; #ifdef DEBUG fprintf(stderr, "mng_alarmset %d delay\n", p->delay); #endif if (p->delay > 0) { long delay = p->delay * 1000 * info->delay_factor; long delaysec = delay / 1000000, delayusec = delay % 1000000; if (signal(SIGALRM, (void(*)())info->handler.alarm) == SIG_ERR) { perror("mng_alarmset(): signal()"); exit(1); } value.it_interval.tv_sec = value.it_interval.tv_usec = 0L; value.it_value.tv_sec = delaysec; value.it_value.tv_usec = delayusec; if (setitimer(ITIMER_REAL, &value, NULL) != 0) { fprintf(stderr, "p->delay = %d, delay_factor = %f\n", p->delay, info->delay_factor); perror("mng_alarmset(): setitimer()"); exit(1); } } } static void * mng_alarm(int sig) { global_info->rerender = (global_info->shown_image->next == NULL) ? RERENDER_FIRST : RERENDER_NEXT; return NULL; } static void mng_alarmoff(void) { struct itimerval value; if (global_info != NULL && global_info->shown_image->delay) { value.it_value.tv_sec = 0; value.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &value, NULL); signal(SIGALRM, SIG_DFL); } } static unsigned char mng_sig[] = { 0x8a, 'M', 'N', 'G' }; static int mng_decode_image(Info *info, Image *p) { MNG_info this; Archive *ar = info->ar; int err = 0; unsigned char buf[4]; if (archive_read(ar, buf, 4) != 4) return PROC_NOT; if (memcmp(mng_sig, buf, 4)) return PROC_NOT; archive_seek(ar, 0, SEEK_SET); memset(&this, 0, sizeof(MNG_info)); this.info = info; this.p = p; this.npics = 0; this.mng = mng_initialize((mng_ptr)&this, memalloc, memfree, NULL); if (mng_setcb_openstream (this.mng, openstream )) err++; if (mng_setcb_closestream (this.mng, closestream )) err++; if (mng_setcb_readdata (this.mng, readdata )) err++; if (mng_setcb_processheader (this.mng, processheader)) err++; if (mng_setcb_getcanvasline (this.mng, getcanvasline)) err++; if (mng_setcb_refresh (this.mng, refresh )) err++; if (mng_setcb_gettickcount (this.mng, gettickcount )) err++; if (mng_setcb_settimer (this.mng, settimer )) err++; if (mng_setcb_errorproc (this.mng, errorproc )) err++; if (err) { fprintf(stderr, "failed to install %d callback function(s)\n", err); return PROC_ERROR; } this.rc = mng_readdisplay(this.mng); while (this.rc != MNG_IMAGEFROZEN && this.rc != MNG_NOERROR) { switch (this.rc) { case MNG_NEEDTIMERWAIT: break; default: fprintf(stderr, "Error %d\n", this.rc); image_destroy(this.p); return PROC_ERROR; } this.rc = mng_display_resume(this.mng); } mng_cleanup(&this.mng); info->format = FORMAT_NAME; info->npics = this.npics; info->if_animated = 1; return PROC_OK; } int mng_load_image(Info *info, Image *p) { int f; if ((f = mng_decode_image(info, p)) != PROC_OK) return f; /* set handler */ info->handler.destroy = NULL; info->handler.alarmset = mng_alarmset; info->handler.alarm = mng_alarm; info->handler.alarmoff = mng_alarmoff; return PROC_OK; }