From 3f0284935c8189959dd312686416e178556aa52b Mon Sep 17 00:00:00 2001 From: Marcus Comstedt <marcus@mc.pp.se> Date: Tue, 6 Apr 1999 19:24:32 +0200 Subject: [PATCH] ILBM decoder added. Rev: src/modules/Image/encodings/Makefile.in:1.22 Rev: src/modules/Image/encodings/any.c:1.5 Rev: src/modules/Image/encodings/iff.c:1.1 Rev: src/modules/Image/encodings/ilbm.c:1.1 Rev: src/modules/Image/image.c:1.121 --- .gitattributes | 2 + src/modules/Image/encodings/Makefile.in | 4 +- src/modules/Image/encodings/any.c | 12 +- src/modules/Image/encodings/iff.c | 62 ++++ src/modules/Image/encodings/ilbm.c | 462 ++++++++++++++++++++++++ src/modules/Image/image.c | 10 +- 6 files changed, 544 insertions(+), 8 deletions(-) create mode 100644 src/modules/Image/encodings/iff.c create mode 100644 src/modules/Image/encodings/ilbm.c diff --git a/.gitattributes b/.gitattributes index a0d3457305..d6ea693fce 100644 --- a/.gitattributes +++ b/.gitattributes @@ -183,6 +183,8 @@ testfont binary /src/modules/Image/encodings/gif.c foreign_ident /src/modules/Image/encodings/gif_lzw.c foreign_ident /src/modules/Image/encodings/gif_lzw.h foreign_ident +/src/modules/Image/encodings/iff.c foreign_ident +/src/modules/Image/encodings/ilbm.c foreign_ident /src/modules/Image/encodings/pcx.c foreign_ident /src/modules/Image/encodings/png.c foreign_ident /src/modules/Image/encodings/pnm.c foreign_ident diff --git a/src/modules/Image/encodings/Makefile.in b/src/modules/Image/encodings/Makefile.in index 127352fb0e..3a5f5d2dc1 100644 --- a/src/modules/Image/encodings/Makefile.in +++ b/src/modules/Image/encodings/Makefile.in @@ -1,7 +1,7 @@ -# $Id: Makefile.in,v 1.21 1999/04/06 11:37:16 per Exp $ +# $Id: Makefile.in,v 1.22 1999/04/06 17:24:29 marcus Exp $ SRCDIR=@srcdir@ VPATH=@srcdir@:@srcdir@/../../..:../../.. -OBJS = gif.o gif_lzw.o pnm.o x.o xwd.o png.o any.o bmp.o tga.o pcx.o xbm.o _xpm.o +OBJS = gif.o gif_lzw.o pnm.o x.o xwd.o png.o any.o bmp.o tga.o pcx.o xbm.o _xpm.o ilbm.o iff.o @SET_MAKE@ diff --git a/src/modules/Image/encodings/any.c b/src/modules/Image/encodings/any.c index d5293e563f..61b0a4ede6 100644 --- a/src/modules/Image/encodings/any.c +++ b/src/modules/Image/encodings/any.c @@ -1,9 +1,9 @@ -/* $Id: any.c,v 1.4 1999/03/11 08:29:32 mirar Exp $ */ +/* $Id: any.c,v 1.5 1999/04/06 17:24:30 marcus Exp $ */ /* **! module Image **! note -**! $Id: any.c,v 1.4 1999/03/11 08:29:32 mirar Exp $ +**! $Id: any.c,v 1.5 1999/04/06 17:24:30 marcus Exp $ **! submodule ANY **! **! This method calls the other decoding methods @@ -23,7 +23,7 @@ #include <ctype.h> #include "stralloc.h" -RCSID("$Id: any.c,v 1.4 1999/03/11 08:29:32 mirar Exp $"); +RCSID("$Id: any.c,v 1.5 1999/04/06 17:24:30 marcus Exp $"); #include "pike_macros.h" #include "operators.h" #include "builtin_functions.h" @@ -97,6 +97,12 @@ void image_any__decode(INT32 args) error("can't handle gif's yet\n"); return; + case CHAR2('F','O'): + /* ILBM (probably) */ + img_ilbm_decode(1); + push_text("image/x-ilbm"); + goto simple_image; + case CHAR2(0,0): switch (CHAR2(sp[-args].u.string->str[2],sp[-args].u.string->str[3])) { diff --git a/src/modules/Image/encodings/iff.c b/src/modules/Image/encodings/iff.c new file mode 100644 index 0000000000..b294b05a5b --- /dev/null +++ b/src/modules/Image/encodings/iff.c @@ -0,0 +1,62 @@ +/* $Id: iff.c,v 1.1 1999/04/06 17:24:32 marcus Exp $ */ + +#include "global.h" + +#include "stralloc.h" +RCSID("$Id: iff.c,v 1.1 1999/04/06 17:24:32 marcus Exp $"); +#include "pike_macros.h" +#include "object.h" +#include "constants.h" +#include "interpret.h" +#include "svalue.h" +#include "mapping.h" +#include "error.h" + + +static INT32 low_parse_iff(unsigned char *data, INT32 len, unsigned char *hdr, + struct mapping *m, unsigned char *stopchunk) +{ + INT32 clen; + clen = (EXTRACT_CHAR(hdr+4)<<24)|(hdr[5]<<16)|(hdr[6]<<8)|hdr[7]; + + if(clen==-1) + clen = len; + else { + if(!memcmp(hdr, "FORM", 4)) + clen -= 4; + if(clen > len) + error("truncated file\n"); + else if(clen < 0) + error("invalid chunk length\n"); + } + + if((!memcmp(hdr, "FORM", 4)) || (!memcmp(hdr, "LIST", 4))) { + INT32 pos=0; + while(pos+8 <= clen) { + INT32 l = low_parse_iff(data+pos+8, clen-pos-8, data+pos, m, stopchunk); + if(!l) + return 0; + pos += l+8; + } + } else { + push_string(make_shared_binary_string(hdr, 4)); + push_string(make_shared_binary_string(data, clen)); + mapping_insert(m, sp-2, sp-1); + pop_n_elems(2); + if(!memcmp(hdr, stopchunk, 4)) + return 0; + } + return clen + (clen & 1); +} + +void parse_iff(char *id, unsigned char *data, INT32 len, + struct mapping *m, char *stopchunk) +{ + if(len<12 || memcmp("FORM", data, 4)) + error("invalid IFF FORM\n"); + + if(memcmp(id, data+8, 4)) + error("FORM is not %s\n", id); + + low_parse_iff(data+12, len-12, data, m, stopchunk); +} diff --git a/src/modules/Image/encodings/ilbm.c b/src/modules/Image/encodings/ilbm.c new file mode 100644 index 0000000000..10cb1cde49 --- /dev/null +++ b/src/modules/Image/encodings/ilbm.c @@ -0,0 +1,462 @@ +/* $Id: ilbm.c,v 1.1 1999/04/06 17:24:32 marcus Exp $ */ + +/* +**! module Image +**! note +**! $Id: ilbm.c,v 1.1 1999/04/06 17:24:32 marcus Exp $ +**! submodule ILBM +**! +**! This submodule keep the ILBM encode/decode capabilities +**! of the <ref>Image</ref> module. +**! +**! see also: Image, Image.image, Image.colortable +*/ +#include "global.h" + +#include "stralloc.h" +RCSID("$Id: ilbm.c,v 1.1 1999/04/06 17:24:32 marcus Exp $"); +#include "pike_macros.h" +#include "object.h" +#include "constants.h" +#include "interpret.h" +#include "svalue.h" +#include "array.h" +#include "mapping.h" +#include "error.h" +#include "threads.h" +#include "builtin_functions.h" +#include "module_support.h" + +#include "image.h" +#include "colortable.h" + + +extern struct program *image_colortable_program; +extern struct program *image_program; + +#define string_BMHD 0 +#define string_CMAP 1 +#define string_CAMG 2 +#define string_BODY 3 + +static struct svalue string_[4]; + +struct BMHD { + unsigned int w, h; + int x, y; + unsigned char nPlanes, masking, compression, pad1; + unsigned int transparentColor; + unsigned char xAspect, yAspect; + int pageWidth, pageHeight; +}; + +#define mskNone 0 +#define mskHasMask 1 +#define mskHasTransparentColor 2 +#define mskLasso 3 + +#define cmpNone 0 +#define cmpByteRun1 1 + + + +/** decoding *****************************************/ + +/* +**! method array __decode(); +**! Decodes an ILBM image structure down to chunks and +**! returns an array containing the ILBM structure; +**! +**! <pre> +**! ({int xsize,int ysize, // 0: size of image drawing area +**! string bitmapheader, // 2: BMHD chunk +**! void|string colortable, // 3: opt. colortable chunk (CMAP) +**! void|string colortable, // 4: opt. colormode chunk (CAMG) +**! string body, // 5: BODY chunk +**! mapping more_chunks}) // 6: mapping with other chunks +**! </pre> +**! +**! returns the above array +**! +**! note +**! May throw errors if the ILBM header is incomplete or illegal. +*/ + +static void image_ilbm___decode(INT32 args) +{ + unsigned char *s; + INT32 len; + struct pike_string *str; + struct mapping *m; + int n; + extern void parse_iff(char *, unsigned char *, INT32, + struct mapping *, char *); + + get_all_args("__decode", args, "%S", &str); + + s=(unsigned char *)str->str; + len=str->len; + pop_n_elems(args-1); + + for(n=0; n<5; n++) + push_int(0); + push_mapping(m = allocate_mapping(4)); + + parse_iff("ILBM", s, len, m, "BODY"); + + mapping_index_no_free(sp-5, m, &string_[string_BMHD]); + mapping_index_no_free(sp-4, m, &string_[string_CMAP]); + mapping_index_no_free(sp-3, m, &string_[string_CAMG]); + mapping_index_no_free(sp-2, m, &string_[string_BODY]); + + map_delete(m, &string_[string_BMHD]); + map_delete(m, &string_[string_CMAP]); + map_delete(m, &string_[string_CAMG]); + map_delete(m, &string_[string_BODY]); + + if(sp[-5].type != T_STRING) + error("Missing BMHD chunk\n"); + if(sp[-2].type != T_STRING) + error("Missing BODY chunk\n"); + + /* Extract image size from BMHD */ + s=(unsigned char *)STR0(sp[-5].u.string); + len=sp[-5].u.string->len; + + if(len<20) + error("Short BMHD chunk\n"); + + free_svalue(sp-7); + + sp[-7].u.integer = (s[0]<<8)|s[1]; + sp[-7].type = T_INT; + sp[-7].subtype = NUMBER_NUMBER; + sp[-6].u.integer = (s[2]<<8)|s[3]; + sp[-6].type = T_INT; + sp[-6].subtype = NUMBER_NUMBER; + + f_aggregate(7); +} + + +/* +**! method array _decode(string|array data) +**! Decode an ILBM image file. +**! +**! Result is a mapping, +**! <pre> +**! ([ +**! "image": object image, +**! +**! ... more ... +**! ]) +**! </pre> +**! +**! <tt>image</tt> is the stored image. +**! +*/ + +static void parse_bmhd(struct BMHD *bmhd, unsigned char *s, INT32 len) +{ + if(len<20) + error("Short BMHD chunk\n"); + + bmhd->w = (s[0]<<8)|s[1]; + bmhd->h = (s[2]<<8)|s[3]; + bmhd->x = (EXTRACT_CHAR(s+4)<<8)|s[5]; + bmhd->y = (EXTRACT_CHAR(s+6)<<8)|s[7]; + bmhd->nPlanes = s[8]; + bmhd->masking = s[9]; + bmhd->compression = s[10]; + bmhd->pad1 = s[11]; + bmhd->transparentColor = (s[12]<<8)|s[13]; + bmhd->xAspect = s[14]; + bmhd->yAspect = s[15]; + bmhd->pageWidth = (EXTRACT_CHAR(s+16)<<8)|s[17]; + bmhd->pageHeight = (EXTRACT_CHAR(s+18)<<8)|s[19]; +} + +static void br1unpack(unsigned char *src, unsigned char *dst, int size) +{ + unsigned char d, *end=dst+size; + signed char c; + + while(dst<end) + if((c=*src++)>=0) + do { *dst++ = *src++; } while(c--); + else if(c!=-128) { + d = *src++; + do { *dst++ = d; } while(c++); + } +} + + +static INT32 unpackByteRun1(unsigned char *src, INT32 srclen, + unsigned char *dest, int destlen, int depth) +{ + unsigned char d, *src0 = src; + while(depth>0) { + int c, left = destlen; + while(left>0) { + if(srclen<=0) + return src+1-src0; + if((c=EXTRACT_CHAR(src++))>=0) { + if(srclen<c+2) + return src+2+c-src0; + srclen -= c+2; + if(1+c>left) { + c = left-1; + } else + left -= c+1; + do { *dest++ = *src++; } while(c--); + } else if(c!=-128) { + if(srclen<2) + return src+2-src0; + d = *src++; + srclen -= 2; + if(1-c>left) { + c = 1-left; + left = 0; + } else + left -= 1-c; + do { *dest++ = d; } while(c++); + } + } + --depth; + } + return src-src0; +} + +static void planar2chunky(unsigned char *src, int srcmod, int depth, + int w, INT32 *dest) +{ + int x, p, bit=0x80; + /* Really slow... */ + for(x=0; x<w; x++) { + INT32 pix = 0; + for(p=0; p<depth; p++) + if(src[p*srcmod]&bit) + pix |= 1<<p; + *dest++ = pix; + if(!(bit>>=1)) { + bit = 0x80; + src++; + } + } +} + +static void parse_body(struct BMHD *bmhd, unsigned char *body, INT32 blen, + struct image *img, struct image *alpha, + struct neo_colortable *ctable) +{ + unsigned int x, y; + int rbyt = ((bmhd->w+15)&~15)>>3; + int eplanes = (bmhd->masking == mskHasMask? bmhd->nPlanes+1:bmhd->nPlanes); + unsigned char *line; + INT32 *cptr, *cline = alloca((rbyt<<3)*sizeof(INT32)); + INT32 suse; + rgb_group *dest = img->img; + + if(ctable != NULL && ctable->type != NCT_FLAT) + ctable = NULL; + + switch(bmhd->compression) { + case cmpNone: + break; + case cmpByteRun1: + line = alloca(rbyt*eplanes); + break; + default: + error("Unsupported ILBM compression %d\n", bmhd->compression); + } + + THREADS_ALLOW(); + + for(y=0; y<bmhd->h; y++) { + switch(bmhd->compression) { + case cmpNone: + line = body; + suse = rbyt*eplanes; + break; + case cmpByteRun1: + suse = unpackByteRun1(body, blen, line, rbyt, eplanes); + break; + } + body += suse; + if((blen -= suse)<0) + break; + planar2chunky(line, rbyt, bmhd->nPlanes, bmhd->w, cptr=cline); + if(ctable != NULL) { + int numcolors = ctable->u.flat.numentries; + struct nct_flat_entry *entries = ctable->u.flat.entries; + for(x=0; x<bmhd->w; x++) + if(*cptr<numcolors) + *dest++ = entries[*cptr++].color; + else + cptr++; + } else + for(x=0; x<bmhd->w; x++) { + /* ILBM-24 */ + dest->r = ((*cptr)&0xff0000)>>16; + dest->g = ((*cptr)&0x00ff00)>>8; + dest->b = ((*cptr)&0x0000ff); + cptr++; + dest++; + } + } + + THREADS_DISALLOW(); + + if(blen<0) + error("truncated or corrupt BODY chunk\n"); +} + +static void image_ilbm__decode(INT32 args) +{ + struct array *arr; + struct object *o; + struct image *img; + struct BMHD bmhd; + struct neo_colortable *ctable = NULL; + int n = 0; + + if(args>0 && sp[-args].type == T_STRING) { + image_ilbm___decode(args); + args = 1; + } + + get_all_args("_decode", args, "%a", &arr); + + if(args>1) + pop_n_elems(args-1); + + if(arr->size < 6 || + ITEM(arr)[2].type != T_STRING || ITEM(arr)[2].u.string->size_shift != 0 || + ITEM(arr)[5].type != T_STRING || ITEM(arr)[5].u.string->size_shift != 0) + error("Image.ILBM._decode: illegal argument\n"); + + parse_bmhd(&bmhd, STR0(ITEM(arr)[2].u.string), ITEM(arr)[2].u.string->len); + + push_text("image"); + push_int(bmhd.w); + push_int(bmhd.h); + o=clone_object(image_program,2); + img=(struct image*)get_storage(o,image_program); + push_object(o); + n++; + + if(ITEM(arr)[3].type == T_STRING && ITEM(arr)[3].u.string->size_shift == 0) { + unsigned char *pal = STR0(ITEM(arr)[3].u.string); + INT32 col, ncol = ITEM(arr)[3].u.string->len/3; + push_text("palette"); + for(col=0; col<ncol; col++) { + push_int(*pal++); + push_int(*pal++); + push_int(*pal++); + f_aggregate(3); + } + f_aggregate(ncol); + push_object(clone_object(image_colortable_program,1)); + ctable=(struct neo_colortable*)get_storage(sp[-1].u.object, + image_colortable_program); + n++; + } + + parse_body(&bmhd, STR0(ITEM(arr)[5].u.string), ITEM(arr)[5].u.string->len, + img, NULL, ctable); + + f_aggregate_mapping(2*n); + stack_swap(); + pop_stack(); +} + + +/* +**! method object decode(string data) +**! method object decode(array _decoded) +**! method object decode(array __decoded) +**! Decodes ILBM data and creates an image object. +**! +**! see also: encode +**! +**! note +**! This function may throw errors upon illegal ILBM data. +**! This function uses <ref>__decode</ref> and +**! <ref>_decode</ref> internally. +**! +**! returns the decoded image as an image object +*/ + +void img_ilbm_decode(INT32 args) +{ + struct svalue *sv; + + if (!args) + error("Image.ILBM.decode: too few argument\n"); + + if (sp[-args].type != T_MAPPING) { + image_ilbm__decode(args); + args = 1; + } + + if (sp[-args].type != T_MAPPING) + error("Image.ILBM.decode: illegal argument\n"); + + if(args>1) + pop_n_elems(args-1); + + sv = simple_mapping_string_lookup(sp[-args].u.mapping, "image"); + + if(sv == NULL || sv->type != T_OBJECT) + error("Image.ILBM.decode: illegal argument\n"); + + ref_push_object(sv->u.object); + stack_swap(); + pop_stack(); +} + +/** module *******************************************/ + +struct program *image_encoding_ilbm_program=NULL; + +void init_image_ilbm(void) +{ + static char *str[] = { "BMHD", "CMAP", "CAMG", "BODY" }; + int n; + + for(n=0; n<4; n++) { + push_string(make_shared_binary_string(str[n], 4)); + assign_svalue_no_free(&string_[n], sp-1); + pop_stack(); + } + + start_new_program(); + + add_function("__decode",image_ilbm___decode, + "function(string:array)",0); + add_function("_decode",image_ilbm__decode, + "function(string|array:mapping)",0); + add_function("decode",img_ilbm_decode, + "function(string|array:object)",0); + + image_encoding_ilbm_program=end_program(); + push_object(clone_object(image_encoding_ilbm_program,0)); + { + struct pike_string *s=make_shared_string("ILBM"); + add_constant(s,sp-1,0); + free_string(s); + } + pop_stack(); +} + +void exit_image_ilbm(void) +{ + int n; + if(image_encoding_ilbm_program) + { + free_program(image_encoding_ilbm_program); + image_encoding_ilbm_program=NULL; + } + for(n=0; n<4; n++) + free_svalue(&string_[n]); +} diff --git a/src/modules/Image/image.c b/src/modules/Image/image.c index 15ceafc3fd..9e36a5e6d1 100644 --- a/src/modules/Image/image.c +++ b/src/modules/Image/image.c @@ -1,9 +1,9 @@ -/* $Id: image.c,v 1.120 1999/04/06 11:36:41 per Exp $ */ +/* $Id: image.c,v 1.121 1999/04/06 17:24:26 marcus Exp $ */ /* **! module Image **! note -**! $Id: image.c,v 1.120 1999/04/06 11:36:41 per Exp $ +**! $Id: image.c,v 1.121 1999/04/06 17:24:26 marcus Exp $ **! class image **! **! The main object of the <ref>Image</ref> module, this object @@ -97,7 +97,7 @@ #include "stralloc.h" #include "global.h" -RCSID("$Id: image.c,v 1.120 1999/04/06 11:36:41 per Exp $"); +RCSID("$Id: image.c,v 1.121 1999/04/06 17:24:26 marcus Exp $"); #include "pike_macros.h" #include "object.h" #include "constants.h" @@ -3486,6 +3486,8 @@ extern void init_image__xpm(void); extern void exit_image__xpm(void); extern void exit_image_xbm(void); extern void init_image_xbm(void); +extern void exit_image_ilbm(void); +extern void init_image_ilbm(void); /* dynamic encoders (dependent on other modules, loaded dynamically) */ @@ -3859,6 +3861,7 @@ void pike_module_init(void) init_image_pcx(); init_image_xbm(); init_image__xpm(); + init_image_ilbm(); init_image_x(); } @@ -3882,6 +3885,7 @@ void pike_module_exit(void) exit_image_pcx(); exit_image__xpm(); exit_image_xbm(); + exit_image_ilbm(); if (png_object) { free_object(png_object); -- GitLab