e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
3f02841999-04-06Marcus Comstedt  /* **! module Image **! submodule ILBM **! **! This submodule keep the ILBM encode/decode capabilities **! of the <ref>Image</ref> module. **!
144ca72014-07-31Per Hedbor **! ILBM is a subtype of the Interchange File Format (IFF) used for **! storing picture data. ILBM stands for InterLeaved BitMap which **! refers to the way the pictures are stored. The image data is **! stored as a varying number of bitplanes, each storing one bit of **! data for each pixel in the image. The format supports horizontal **! and vertical RLE (Run Length Encoding) compression. **! **! The format also natively supports images using the somewhat **! esoteric image modes of the original Commodore Amiga, such as HAM **! (Hold And Modify) **! **! The format was commonly used for images on the Amiga. **!
448c201999-04-13Mirar (Pontus Hagland) **! see also: Image, Image.Image, Image.Colortable
3f02841999-04-06Marcus Comstedt */ #include "global.h" #include "stralloc.h" #include "object.h" #include "interpret.h" #include "svalue.h" #include "array.h" #include "mapping.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
3f02841999-04-06Marcus Comstedt #include "threads.h" #include "builtin_functions.h" #include "module_support.h" #include "image.h" #include "colortable.h"
82ff642000-07-03Henrik Grubbström (Grubba) #include "encodings.h"
6dc2772000-07-28Fredrik Hübinette (Hubbe) 
6ad2372002-05-11Martin Nilsson #define sp Pike_sp
3f02841999-04-06Marcus Comstedt 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
e41f6f1999-04-07Marcus Comstedt #define CAMG_HAM 0x800 #define CAMG_EHB 0x080
3f02841999-04-06Marcus Comstedt  /** decoding *****************************************/ /* **! method array __decode(); **! Decodes an ILBM image structure down to chunks and **! returns an array containing the ILBM structure;
13670c2015-05-25Martin Nilsson **!
3f02841999-04-06Marcus Comstedt **! <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;
3bd87a2000-08-03Henrik Grubbström (Grubba)  ptrdiff_t len;
3f02841999-04-06Marcus Comstedt  struct pike_string *str; struct mapping *m; int n;
9e53482000-08-06Henrik Grubbström (Grubba)  extern void parse_iff(char *, unsigned char *, ptrdiff_t,
3f02841999-04-06Marcus Comstedt  struct mapping *, char *);
391ac52018-08-05Martin Nilsson  get_all_args(NULL, args, "%S", &str);
3f02841999-04-06Marcus Comstedt 
3bd87a2000-08-03Henrik Grubbström (Grubba)  s = (unsigned char *)str->str; len = str->len;
3f02841999-04-06Marcus Comstedt  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]);
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[-5]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Missing BMHD chunk\n");
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[-2]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Missing BODY chunk\n");
3f02841999-04-06Marcus Comstedt  /* Extract image size from BMHD */
3bd87a2000-08-03Henrik Grubbström (Grubba)  s = (unsigned char *)STR0(sp[-5].u.string); len = sp[-5].u.string->len;
3f02841999-04-06Marcus Comstedt  if(len<20)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Short BMHD chunk\n");
3f02841999-04-06Marcus Comstedt  free_svalue(sp-7);
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(sp[-7], T_INT, NUMBER_NUMBER, integer, (s[0]<<8)|s[1]); SET_SVAL(sp[-6], T_INT, NUMBER_NUMBER, integer, (s[2]<<8)|s[3]);
3f02841999-04-06Marcus Comstedt  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. **! */
3bd87a2000-08-03Henrik Grubbström (Grubba) static void parse_bmhd(struct BMHD *bmhd, unsigned char *s, ptrdiff_t len)
3f02841999-04-06Marcus Comstedt { if(len<20)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Short BMHD chunk\n");
3f02841999-04-06Marcus Comstedt  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];
5668ef1999-04-07Marcus Comstedt  #ifdef ILBM_DEBUG fprintf(stderr, "w = %d, h = %d, x = %d, y = %d, nPlanes = %d,\n" "masking = %d, compression = %d, pad1 = %d, transparentColor = %d,\n" "xAspect = %d, yAspect = %d, pageWidth = %d, pageHeight = %d\n", bmhd->w, bmhd->h, bmhd->x, bmhd->y, bmhd->nPlanes, bmhd->masking, bmhd->compression, bmhd->pad1, bmhd->transparentColor, bmhd->xAspect,
13670c2015-05-25Martin Nilsson  bmhd->yAspect, bmhd->pageWidth, bmhd->pageHeight);
5668ef1999-04-07Marcus Comstedt #endif
3f02841999-04-06Marcus Comstedt }
bea2ad2000-08-14Henrik Grubbström (Grubba) static ptrdiff_t unpackByteRun1(unsigned char *src, ptrdiff_t srclen,
3bd87a2000-08-03Henrik Grubbström (Grubba)  unsigned char *dest, int destlen, int depth)
3f02841999-04-06Marcus Comstedt { unsigned char d, *src0 = src;
5668ef1999-04-07Marcus Comstedt 
3f02841999-04-06Marcus Comstedt  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++; } } }
0af1852000-08-11Henrik Grubbström (Grubba) static void parse_body(struct BMHD *bmhd, unsigned char *body, ptrdiff_t blen,
3f02841999-04-06Marcus Comstedt  struct image *img, struct image *alpha,
4116e11999-04-07Marcus Comstedt  struct neo_colortable *ctable, int ham)
3f02841999-04-06Marcus Comstedt { unsigned int x, y; int rbyt = ((bmhd->w+15)&~15)>>3; int eplanes = (bmhd->masking == mskHasMask? bmhd->nPlanes+1:bmhd->nPlanes);
8db2c31999-05-23Mirar (Pontus Hagland)  unsigned char *line=0;
3c30aa1999-09-26Henrik Grubbström (Grubba)  unsigned INT32 *cptr, *cline = alloca((rbyt<<3)*sizeof(unsigned INT32));
0af1852000-08-11Henrik Grubbström (Grubba)  ptrdiff_t suse=0;
3f02841999-04-06Marcus Comstedt  rgb_group *dest = img->img;
d728311999-04-19Marcus Comstedt  rgb_group *adest = (alpha==NULL? NULL : alpha->img);
3f02841999-04-06Marcus Comstedt  if(ctable != NULL && ctable->type != NCT_FLAT) ctable = NULL; switch(bmhd->compression) { case cmpNone: break; case cmpByteRun1: line = alloca(rbyt*eplanes); break; default:
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Unsupported ILBM compression %d\n", bmhd->compression);
3f02841999-04-06Marcus Comstedt  }
d728311999-04-19Marcus Comstedt  switch(bmhd->masking) { case mskNone: case mskHasMask: case mskHasTransparentColor: break; case mskLasso:
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Lasso masking not supported\n");
d728311999-04-19Marcus Comstedt  default:
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Unsupported ILBM masking %d\n", bmhd->masking);
d728311999-04-19Marcus Comstedt  }
3f02841999-04-06Marcus Comstedt  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;
01a9572000-02-03Henrik Grubbström (Grubba)  planar2chunky(line, rbyt, bmhd->nPlanes, bmhd->w, (INT32 *)(cptr=cline));
d728311999-04-19Marcus Comstedt  if(alpha != NULL) switch(bmhd->masking) { case mskNone:
ab98542014-04-27Martin Nilsson  memset(adest, ~0, bmhd->w*sizeof(*adest));
d728311999-04-19Marcus Comstedt  adest += bmhd->w; break; case mskHasMask: {
340c562001-06-13Henrik Grubbström (Grubba)  int bit=0x80;
d728311999-04-19Marcus Comstedt  unsigned char *src = line+bmhd->nPlanes*rbyt; unsigned char ss = *src++; for(x=0; x<bmhd->w; x++) { if(ss&bit) {
a875f82000-09-15Henrik Grubbström (Grubba)  adest->r = adest->g = adest->b = 0xff;
d728311999-04-19Marcus Comstedt  } else { adest->r = adest->g = adest->b = 0; } if(!(bit>>=1)) { bit = 0x80; ss = *src++; } } } break; case mskHasTransparentColor: for(x=0; x<bmhd->w; x++) { if(cline[x] == bmhd->transparentColor) adest->r = adest->g = adest->b = 0; else
a875f82000-09-15Henrik Grubbström (Grubba)  adest->r = adest->g = adest->b = 0xff;
d728311999-04-19Marcus Comstedt  adest++; } break; }
4116e11999-04-07Marcus Comstedt  if(ctable != NULL) if(ham) if(bmhd->nPlanes>6) { /* HAM7/HAM8 */ rgb_group hold;
3c30aa1999-09-26Henrik Grubbström (Grubba)  int clr;
0af1852000-08-11Henrik Grubbström (Grubba)  size_t numcolors = ctable->u.flat.numentries;
4116e11999-04-07Marcus Comstedt  struct nct_flat_entry *entries = ctable->u.flat.entries; hold.r = hold.g = hold.b = 0; for(x=0; x<bmhd->w; x++) switch((*cptr)&0xc0) { case 0x00: if(*cptr<numcolors) *dest++ = hold = entries[*cptr++].color; else { *dest++ = hold; cptr++; } break; case 0x80: clr = (*cptr++)&0x3f; hold.r = (clr<<2)|(clr>>4); *dest++ = hold; break; case 0xc0: clr = (*cptr++)&0x3f; hold.g = (clr<<2)|(clr>>4); *dest++ = hold; break; case 0x40: clr = (*cptr++)&0x3f; hold.b = (clr<<2)|(clr>>4); *dest++ = hold; break; } } else {
13670c2015-05-25Martin Nilsson  /* HAM5/HAM6 */
4116e11999-04-07Marcus Comstedt  rgb_group hold;
3c30aa1999-09-26Henrik Grubbström (Grubba)  int clr;
0af1852000-08-11Henrik Grubbström (Grubba)  size_t numcolors = ctable->u.flat.numentries;
4116e11999-04-07Marcus Comstedt  struct nct_flat_entry *entries = ctable->u.flat.entries; hold.r = hold.g = hold.b = 0; for(x=0; x<bmhd->w; x++) switch((*cptr)&0x30) { case 0x00: if(*cptr<numcolors) *dest++ = hold = entries[*cptr++].color; else { *dest++ = hold; cptr++; } break; case 0x20: clr = (*cptr++)&0xf; hold.r = (clr<<4)|clr; *dest++ = hold; break; case 0x30: clr = (*cptr++)&0xf; hold.g = (clr<<4)|clr; *dest++ = hold; break; case 0x10: clr = (*cptr++)&0xf; hold.b = (clr<<4)|clr; *dest++ = hold; break; }
5668ef1999-04-07Marcus Comstedt  }
4116e11999-04-07Marcus Comstedt  else { /* normal palette */
0af1852000-08-11Henrik Grubbström (Grubba)  size_t numcolors = ctable->u.flat.numentries;
4116e11999-04-07Marcus Comstedt  struct nct_flat_entry *entries = ctable->u.flat.entries; for(x=0; x<bmhd->w; x++) if(*cptr<numcolors) *dest++ = entries[*cptr++].color; else { dest++; cptr++; } } else
3f02841999-04-06Marcus Comstedt  for(x=0; x<bmhd->w; x++) { /* ILBM-24 */
a2f2b41999-04-07Marcus Comstedt  dest->b = ((*cptr)&0xff0000)>>16;
3f02841999-04-06Marcus Comstedt  dest->g = ((*cptr)&0x00ff00)>>8;
a2f2b41999-04-07Marcus Comstedt  dest->r = ((*cptr)&0x0000ff);
3f02841999-04-06Marcus Comstedt  cptr++; dest++; } } THREADS_DISALLOW(); if(blen<0)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("truncated or corrupt BODY chunk\n");
3f02841999-04-06Marcus Comstedt } static void image_ilbm__decode(INT32 args) { struct array *arr; struct object *o;
d728311999-04-19Marcus Comstedt  struct image *img, *alpha = NULL;
3f02841999-04-06Marcus Comstedt  struct BMHD bmhd; struct neo_colortable *ctable = NULL; int n = 0;
e41f6f1999-04-07Marcus Comstedt  INT32 camg = 0;
3f02841999-04-06Marcus Comstedt 
017b572011-10-28Henrik Grubbström (Grubba)  if(args>0 && TYPEOF(sp[-args]) == T_STRING) {
3f02841999-04-06Marcus Comstedt  image_ilbm___decode(args); args = 1; }
13670c2015-05-25Martin Nilsson 
391ac52018-08-05Martin Nilsson  get_all_args(NULL, args, "%a", &arr);
3f02841999-04-06Marcus Comstedt  if(args>1) pop_n_elems(args-1); if(arr->size < 6 ||
017b572011-10-28Henrik Grubbström (Grubba)  TYPEOF(ITEM(arr)[2]) != T_STRING || ITEM(arr)[2].u.string->size_shift != 0 || TYPEOF(ITEM(arr)[5]) != T_STRING || ITEM(arr)[5].u.string->size_shift != 0)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Image.ILBM._decode: illegal argument\n");
3f02841999-04-06Marcus Comstedt  parse_bmhd(&bmhd, STR0(ITEM(arr)[2].u.string), ITEM(arr)[2].u.string->len);
5e9fc02015-08-18Per Hedbor  push_static_text("image");
3f02841999-04-06Marcus Comstedt  push_int(bmhd.w); push_int(bmhd.h); o=clone_object(image_program,2);
13b5ed2014-05-26Per Hedbor  img=get_storage(o,image_program);
3f02841999-04-06Marcus Comstedt  push_object(o); n++;
d728311999-04-19Marcus Comstedt  if(bmhd.masking != mskNone) {
5e9fc02015-08-18Per Hedbor  push_static_text("alpha");
d728311999-04-19Marcus Comstedt  push_int(bmhd.w); push_int(bmhd.h); o=clone_object(image_program,2);
13b5ed2014-05-26Per Hedbor  alpha=get_storage(o,image_program);
d728311999-04-19Marcus Comstedt  push_object(o); n++; }
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(ITEM(arr)[4]) == T_STRING && ITEM(arr)[4].u.string->size_shift == 0 &&
e41f6f1999-04-07Marcus Comstedt  ITEM(arr)[4].u.string->len>=4) { unsigned char *camgp = STR0(ITEM(arr)[4].u.string); camg = (camgp[0]<<24)|(camgp[1]<<16)|(camgp[2]<<8)|camgp[3]; } if((camg & CAMG_HAM)) {
5e9fc02015-08-18Per Hedbor  push_static_text("ham");
e41f6f1999-04-07Marcus Comstedt  push_int(1); n++; } if((camg & CAMG_EHB)) {
5e9fc02015-08-18Per Hedbor  push_static_text("ehb");
e41f6f1999-04-07Marcus Comstedt  push_int(1); n++; }
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(ITEM(arr)[3]) == T_STRING && ITEM(arr)[3].u.string->size_shift == 0) {
3f02841999-04-06Marcus Comstedt  unsigned char *pal = STR0(ITEM(arr)[3].u.string);
0af1852000-08-11Henrik Grubbström (Grubba)  INT32 col, mcol = 1<<bmhd.nPlanes; ptrdiff_t ncol = ITEM(arr)[3].u.string->len/3;
e41f6f1999-04-07Marcus Comstedt  if((camg & CAMG_HAM)) mcol = (bmhd.nPlanes>6? 64:16); else if((camg & CAMG_EHB)) mcol >>= 1; if(ncol>mcol) ncol = mcol;
5e9fc02015-08-18Per Hedbor  push_static_text("palette");
3f02841999-04-06Marcus Comstedt  for(col=0; col<ncol; col++) { push_int(*pal++); push_int(*pal++); push_int(*pal++); f_aggregate(3); }
e41f6f1999-04-07Marcus Comstedt  if((camg & CAMG_EHB) && !(camg & CAMG_HAM)) { for(col=0; col<ncol; col++) { struct svalue *old = ITEM(sp[-ncol].u.array); push_int(old[0].u.integer>>1); push_int(old[1].u.integer>>1); push_int(old[2].u.integer>>1); f_aggregate(3); } ncol <<= 1; }
cc7cf42015-10-14Martin Nilsson  f_aggregate((INT32)ncol);
3f02841999-04-06Marcus Comstedt  push_object(clone_object(image_colortable_program,1));
13b5ed2014-05-26Per Hedbor  ctable=get_storage(sp[-1].u.object,
3f02841999-04-06Marcus Comstedt  image_colortable_program); n++; } parse_body(&bmhd, STR0(ITEM(arr)[5].u.string), ITEM(arr)[5].u.string->len,
d728311999-04-19Marcus Comstedt  img, alpha, ctable, !!(camg & CAMG_HAM));
3f02841999-04-06Marcus Comstedt  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.
13670c2015-05-25Martin Nilsson **!
3f02841999-04-06Marcus Comstedt **! 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)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Image.ILBM.decode: too few argument\n");
3f02841999-04-06Marcus Comstedt 
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-args]) != T_MAPPING) {
3f02841999-04-06Marcus Comstedt  image_ilbm__decode(args); args = 1; }
13670c2015-05-25Martin Nilsson 
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-args]) != T_MAPPING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Image.ILBM.decode: illegal argument\n");
3f02841999-04-06Marcus Comstedt  if(args>1) pop_n_elems(args-1); sv = simple_mapping_string_lookup(sp[-args].u.mapping, "image");
017b572011-10-28Henrik Grubbström (Grubba)  if(sv == NULL || TYPEOF(*sv) != T_OBJECT)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Image.ILBM.decode: illegal argument\n");
3f02841999-04-06Marcus Comstedt  ref_push_object(sv->u.object); stack_swap(); pop_stack(); }
88fe7a1999-04-09Marcus Comstedt  /** encoding *****************************************/ /* **! method string encode(object image) **! method string encode(object image, mapping options)
13670c2015-05-25Martin Nilsson **! Encodes an ILBM image.
88fe7a1999-04-09Marcus Comstedt **! **! The <tt>options</tt> argument may be a mapping **! containing zero or more encoding options: **! **! <pre> **! normal options: **! "alpha":image object **! Use this image as mask **! (Note: ILBM mask is boolean. **! The values are calculated by (r+2g+b)/4>=128.) **! **! "palette":colortable object **! Use this as palette for pseudocolor encoding **! **! </pre> */ static struct pike_string *make_bmhd(struct BMHD *bmhd) { unsigned char bdat[20]; bdat[0] = (bmhd->w>>8); bdat[1] = bmhd->w&0xff; bdat[2] = (bmhd->h>>8); bdat[3] = bmhd->h&0xff; bdat[4] = (bmhd->x>>8); bdat[5] = bmhd->x&0xff; bdat[6] = (bmhd->y>>8); bdat[7] = bmhd->y&0xff; bdat[8] = bmhd->nPlanes; bdat[9] = bmhd->masking; bdat[10] = bmhd->compression; bdat[11] = bmhd->pad1; bdat[12] = (bmhd->transparentColor>>8); bdat[13]=bmhd->transparentColor&0xff; bdat[14] = bmhd->xAspect; bdat[15] = bmhd->yAspect; bdat[16] = (bmhd->pageWidth>>8); bdat[17] = bmhd->pageWidth&0xff; bdat[18] = (bmhd->pageHeight>>8); bdat[19] = bmhd->pageHeight&0xff;
01a9572000-02-03Henrik Grubbström (Grubba)  return make_shared_binary_string((char *)bdat, 20);
88fe7a1999-04-09Marcus Comstedt }
8d4afd1999-04-09Marcus Comstedt static void packByteRun1(unsigned char *src, int srclen, int depth, struct string_builder *dest) { while(depth>0) { int c, left = srclen; while(left>0) { if(left<2 || src[0] != src[1]) { for(c=1; c<128 && c<left; c++) if(c+2<left && src[c] == src[c+1] && src[c] == src[c+2]) break; string_builder_putchar(dest, c-1);
01a9572000-02-03Henrik Grubbström (Grubba)  string_builder_binary_strcat(dest, (char *)src, c);
8d4afd1999-04-09Marcus Comstedt  } else { for(c=2; c<128 && c<left && src[c]==src[0]; c++); string_builder_putchar(dest, (1-c)&0xff); string_builder_putchar(dest, src[0]); } src += c; left -= c; } --depth; } }
88fe7a1999-04-09Marcus Comstedt static void chunky2planar(INT32 *src, int w, unsigned char *dest, int destmod, int depth) { int x, p, bit=0x80; for(x=0; x<w; x+=8) { INT32 p0, p1, p2, p3, p4, p5, p6, p7; switch(w-x) { default: p0 = *src++; p1 = *src++; p2 = *src++; p3 = *src++; p4 = *src++; p5 = *src++; p6 = *src++; p7 = *src++; break; case 7: p0 = *src++; p1 = *src++; p2 = *src++; p3 = *src++; p4 = *src++; p5 = *src++; p6 = *src++; p7 = 0; break; case 6: p0 = *src++; p1 = *src++; p2 = *src++; p3 = *src++; p4 = *src++; p5 = *src++; p6 = p7 = 0; break; case 5: p0 = *src++; p1 = *src++; p2 = *src++; p3 = *src++; p4 = *src++; p5 = p6 = p7 = 0; break; case 4: p0 = *src++; p1 = *src++; p2 = *src++; p3 = *src++; p4 = p5 = p6 = p7 = 0; break; case 3: p0 = *src++; p1 = *src++; p2 = *src++; p3 = p4 = p5 = p6 = p7 = 0; break; case 2: p0 = *src++; p1 = *src++; p2 = p3 = p4 = p5 = p6 = p7 = 0; break; case 1: p0 = *src; p1 = p2 = p3 = p4 = p5 = p6 = p7 = 0; break; } for(p=0; p<depth; p++) { dest[p*destmod] = ((p0&1)<<7)|((p1&1)<<6)|((p2&1)<<5)|((p3&1)<<4)| ((p4&1)<<3)|((p5&1)<<2)|((p6&1)<<1)|(p7&1); p0>>=1; p1>>=1; p2>>=1; p3>>=1; p4>>=1; p5>>=1; p6>>=1; p7>>=1; } dest++; } } static struct pike_string *make_body(struct BMHD *bmhd,
74dfe82012-12-30Jonas Walldén  struct image *img, struct image *UNUSED(alpha),
88fe7a1999-04-09Marcus Comstedt  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);
66589a2014-04-27Martin Nilsson  unsigned char *line = xcalloc(rbyt, eplanes);
88fe7a1999-04-09Marcus Comstedt  INT32 *cptr, *cline = alloca((rbyt<<3)*sizeof(INT32)); rgb_group *src = img->img; struct string_builder bldr;
e3a3231999-04-09Marcus Comstedt  struct nct_dither dith; void (*ctfunc)(rgb_group *, unsigned INT32 *, int, struct neo_colortable *, struct nct_dither *, int) = NULL; if(ctable != NULL) { image_colortable_initiate_dither(ctable, &dith, bmhd->w); ctfunc = image_colortable_index_32bit_function(ctable); }
88fe7a1999-04-09Marcus Comstedt  init_string_builder(&bldr, 0); for(y=0; y<bmhd->h; y++) {
e3a3231999-04-09Marcus Comstedt  if(ctfunc != NULL) { ctfunc(src, (unsigned INT32 *)cline, bmhd->w, ctable, &dith, bmhd->w); src += bmhd->w;
88fe7a1999-04-09Marcus Comstedt  } else {
e3a3231999-04-09Marcus Comstedt  cptr = cline;
88fe7a1999-04-09Marcus Comstedt  for(x=0; x<bmhd->w; x++) { /* ILBM-24 */ *cptr++ = (src->b<<16)|(src->g<<8)|src->r; src++; } } chunky2planar(cline, bmhd->w, line, rbyt, bmhd->nPlanes);
8d4afd1999-04-09Marcus Comstedt  if(bmhd->compression == cmpByteRun1) packByteRun1(line, rbyt, eplanes, &bldr); else
01a9572000-02-03Henrik Grubbström (Grubba)  string_builder_binary_strcat(&bldr, (char *)line, rbyt*eplanes);
88fe7a1999-04-09Marcus Comstedt  }
e3a3231999-04-09Marcus Comstedt  if(ctable != NULL) image_colortable_free_dither(&dith);
66589a2014-04-27Martin Nilsson  free(line);
88fe7a1999-04-09Marcus Comstedt  return finish_string_builder(&bldr); } static void image_ilbm_encode(INT32 args) { struct object *imgo; struct mapping *optm = NULL; struct image *alpha = NULL, *img; struct neo_colortable *ct = NULL; struct pike_string *res; struct BMHD bmhd; int bpp, n = 0; extern struct pike_string *make_iff(char *id, struct array *chunks);
391ac52018-08-05Martin Nilsson  get_all_args(NULL, args, (args>1 && !UNSAFE_IS_ZERO(&sp[1-args])? "%o%m":"%o"),
88fe7a1999-04-09Marcus Comstedt  &imgo, &optm);
13b5ed2014-05-26Per Hedbor  if((img=get_storage(imgo, image_program))==NULL)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Image.ILBM.encode: illegal argument 1\n");
88fe7a1999-04-09Marcus Comstedt  if(optm != NULL) { struct svalue *s;
9f516a2001-12-16Martin Stjernholm  if((s = simple_mapping_string_lookup(optm, "alpha"))!=NULL && !UNSAFE_IS_ZERO(s))
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(*s) != T_OBJECT ||
13b5ed2014-05-26Per Hedbor  (alpha=get_storage(s->u.object, image_program))==NULL)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Image.ILBM.encode: option (arg 2) \"alpha\" has illegal type\n");
9f516a2001-12-16Martin Stjernholm  if((s=simple_mapping_string_lookup(optm, "palette"))!=NULL && !UNSAFE_IS_ZERO(s))
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(*s) != T_OBJECT ||
13b5ed2014-05-26Per Hedbor  (ct=
88fe7a1999-04-09Marcus Comstedt  get_storage(s->u.object, image_colortable_program))==NULL)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Image.ILBM.encode: option (arg 2) \"palette\" has illegal type\n");
88fe7a1999-04-09Marcus Comstedt  } if (!img->img)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Image.ILBM.encode: no image\n");
88fe7a1999-04-09Marcus Comstedt  if (alpha && !alpha->img)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Image.ILBM.encode: no alpha image\n");
88fe7a1999-04-09Marcus Comstedt 
e3a3231999-04-09Marcus Comstedt  if(ct && ct->type == NCT_NONE) ct = NULL;
88fe7a1999-04-09Marcus Comstedt  if(ct) {
0af1852000-08-11Henrik Grubbström (Grubba)  ptrdiff_t sz = image_colortable_size(ct);
88fe7a1999-04-09Marcus Comstedt  for(bpp=1; (1<<bpp)<sz; bpp++); } else bpp = 24; bmhd.w = img->xsize; bmhd.h = img->ysize; bmhd.x = bmhd.y = 0; bmhd.nPlanes = bpp; bmhd.masking = mskNone;
8d4afd1999-04-09Marcus Comstedt  bmhd.compression = (img->xsize>32? cmpByteRun1:cmpNone);
88fe7a1999-04-09Marcus Comstedt  bmhd.pad1 = 0; bmhd.transparentColor = 0; bmhd.xAspect = bmhd.yAspect = 1; bmhd.pageWidth = img->xsize; bmhd.pageHeight = img->ysize; push_svalue(&string_[string_BMHD]); push_string(make_bmhd(&bmhd)); f_aggregate(2); n++;
e3a3231999-04-09Marcus Comstedt  if(ct) { struct pike_string *str = begin_shared_string(image_colortable_size(ct)*3); push_svalue(&string_[string_CMAP]); image_colortable_write_rgb(ct, STR0(str)); push_string(end_shared_string(str)); f_aggregate(2); n++; }
88fe7a1999-04-09Marcus Comstedt  push_svalue(&string_[string_BODY]); push_string(make_body(&bmhd, img, alpha, ct)); f_aggregate(2); n++; f_aggregate(n); res = make_iff("ILBM", sp[-1].u.array); pop_n_elems(args+1); push_string(res); }
3f02841999-04-06Marcus Comstedt /** module *******************************************/ struct program *image_encoding_ilbm_program=NULL; void init_image_ilbm(void) {
5a59872004-09-19Martin Nilsson  static const char *str[] = { "BMHD", "CMAP", "CAMG", "BODY" };
3f02841999-04-06Marcus Comstedt  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(); }
226ec82005-01-23Martin Nilsson  ADD_FUNCTION("__decode",image_ilbm___decode,tFunc(tStr,tArray),0); ADD_FUNCTION("_decode",image_ilbm__decode, tFunc(tOr(tStr,tArray),tMapping),0); ADD_FUNCTION("decode",img_ilbm_decode,tFunc(tOr(tStr,tArray),tObj),0); ADD_FUNCTION("encode",image_ilbm_encode, tFunc(tObj tOr(tVoid,tMap(tStr,tMix)),tStr),0);
3f02841999-04-06Marcus Comstedt } void exit_image_ilbm(void) { int n; for(n=0; n<4; n++) free_svalue(&string_[n]); }