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. || $Id: wbf.c,v 1.13 2002/10/11 01:39:44 nilsson Exp $ */
2588311999-10-22Per Hedbor #include "global.h" #include <math.h> #include <stdio.h> #include <ctype.h> #include "stralloc.h"
e576bb2002-10-11Martin Nilsson RCSID("$Id: wbf.c,v 1.13 2002/10/11 01:39:44 nilsson Exp $");
2588311999-10-22Per Hedbor #include "pike_macros.h" #include "object.h" #include "mapping.h" #include "constants.h" #include "interpret.h" #include "operators.h" #include "svalue.h" #include "threads.h" #include "array.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
2588311999-10-22Per Hedbor #include "builtin_functions.h"
9de2c01999-11-19Henrik Grubbström (Grubba) #include "program.h"
2588311999-10-22Per Hedbor  #include "image.h" #include "builtin_functions.h" #include "module_support.h"
6dc2772000-07-28Fredrik Hübinette (Hubbe) /* MUST BE INCLUDED LAST */ #include "module_magic.h"
6ad2372002-05-11Martin Nilsson #define sp Pike_sp
6dc2772000-07-28Fredrik Hübinette (Hubbe) 
2588311999-10-22Per Hedbor extern struct program *image_program;
eab08e2001-11-07Martin Nilsson /*! @module Image */ /*! @module WBMP *! WAP bitmap format - WBMP. */
2588311999-10-22Per Hedbor  struct buffer {
3bd87a2000-08-03Henrik Grubbström (Grubba)  size_t len;
2588311999-10-22Per Hedbor  unsigned char *str; }; struct ext_header { struct ext_header *next; char name[8]; char value[16]; char name_len; char value_len; }; struct wbf_header { unsigned int width; unsigned int height; int type; int header; int fix_header_field; int ext_header_field; struct ext_header *first_ext_header; }; static void read_string( struct buffer *from, unsigned int len, char *to ) { if( from->len < len )
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Invalid data format\n");
2588311999-10-22Per Hedbor  MEMCPY( from->str, to, len ); from->str += len; from->len -= len; } static unsigned char read_uchar( struct buffer *from ) { unsigned char res = 0; if(from->len) { res = from->str[0]; from->str++; from->len--; } else
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Invalid data format\n");
2588311999-10-22Per Hedbor  return res; }
6dc2772000-07-28Fredrik Hübinette (Hubbe) static int wbf_read_int( struct buffer *from )
2588311999-10-22Per Hedbor { int res = 0; while( 1 ) { int i = read_uchar( from );
b5f3b21999-10-22Per Hedbor  res <<= 7;
2588311999-10-22Per Hedbor  res |= i&0x7f;
b5f3b21999-10-22Per Hedbor  if( !(i & 0x80 ) )
2588311999-10-22Per Hedbor  break; } return res; } static void push_ext_header( struct ext_header *eh ) { push_constant_text( "identifier" ); push_string( make_shared_binary_string( eh->name, eh->name_len ) ); push_constant_text( "value" ); push_string( make_shared_binary_string( eh->value, eh->value_len ) ); f_aggregate_mapping( 4 ); } static struct wbf_header decode_header( struct buffer *data ) { struct wbf_header res; MEMSET( &res, 0, sizeof(res) );
6dc2772000-07-28Fredrik Hübinette (Hubbe)  res.type = wbf_read_int( data );
2588311999-10-22Per Hedbor  res.fix_header_field = read_uchar( data ); if( res.fix_header_field & 0x80 ) { switch( (res.fix_header_field>>5) & 0x3 ) { case 0: /* Single varint extra header */
6dc2772000-07-28Fredrik Hübinette (Hubbe)  res.ext_header_field = wbf_read_int( data );
2588311999-10-22Per Hedbor  break; case 1: /* reserved */ case 2: /* reserved */ case 3: /* Array of parameter/value */ { int q = 0x80; while( q & 0x80 ) { struct ext_header *eh; q = read_uchar( data ); eh = malloc( sizeof( struct ext_header ) ); MEMSET( eh, 0, sizeof( struct ext_header ) ); eh->name_len = ((q>>4) & 0x7) + 1; eh->value_len = (q & 0xf) + 1; read_string( data, eh->name_len, eh->name ); read_string( data, eh->value_len, eh->value ); eh->next = res.first_ext_header; res.first_ext_header = eh->next; } } } }
6dc2772000-07-28Fredrik Hübinette (Hubbe)  res.width = wbf_read_int( data ); res.height = wbf_read_int( data );
2588311999-10-22Per Hedbor  return res; } static void free_wbf_header_contents( struct wbf_header *wh ) { while( wh->first_ext_header ) { struct ext_header *eh = wh->first_ext_header; wh->first_ext_header = eh->next; free( eh ); } } static void low_image_f_wbf_decode_type0( struct wbf_header *wh, struct buffer *buff ) { unsigned int x, y; struct image *i; struct object *io; unsigned int rowsize = (wh->width+7) / 8; rgb_group white; rgb_group *id; push_int( wh->width ); push_int( wh->height ); io = clone_object( image_program, 2 ); i = (struct image*)get_storage(io,image_program); id = i->img; white.r = 255; white.g = 255; white.b = 255; for( y = 0; y<wh->height; y++ ) { unsigned char q = 0; /* avoid warning */ unsigned char *data = buff->str + y * rowsize; if( buff->len < (rowsize+1)*y ) break; for( x = 0; x<wh->width; x++ ) { if( !(x % 8) ) q = data[x/8]; else
b5f3b21999-10-22Per Hedbor  q <<= 1;
2588311999-10-22Per Hedbor  if( q & 128 ) *id = white; id++; } } push_object( io ); } static void low_image_f_wbf_decode( int args, int mode ) { struct pike_string *s; struct wbf_header wh; int map_num_elems = 0; struct buffer buff; get_all_args( "decode", args, "%S", &s ); buff.len = s->len;
01a9572000-02-03Henrik Grubbström (Grubba)  buff.str = (unsigned char *)s->str;
2588311999-10-22Per Hedbor  sp--; /* Evil me */ wh = decode_header( &buff ); switch( wh.type ) { case 0: /* The only supported format. B/W uncompressed bitmap No compresson. Colour: 1 = white, 0 = black. Depth: 1 bit. high bit = rightmost. first byte is upper left corner of image. each row is padded to one byte */ switch( mode ) { case 2: /* Image only */ low_image_f_wbf_decode_type0( &wh, &buff ); return; case 1: /* Image and header */ push_constant_text( "image" ); low_image_f_wbf_decode_type0( &wh, &buff ); map_num_elems++; case 0: /* Header only */ push_constant_text( "format" ); push_constant_text( "image/x-wap.wbmp; type=0" ); map_num_elems++; push_constant_text( "xsize" ); push_int( wh.width ); map_num_elems++; push_constant_text( "ysize" ); push_int( wh.height ); map_num_elems++; if( wh.fix_header_field ) { push_constant_text( "fix_header_field" ); push_int( wh.fix_header_field ); map_num_elems++; } if( wh.ext_header_field ) { push_constant_text( "ext_header_field" ); push_int( wh.ext_header_field ); map_num_elems++; } if( wh.first_ext_header ) { int num_headers = 0; struct ext_header *eh = wh.first_ext_header; while( eh ) { push_ext_header( eh ); eh = eh->next; num_headers++; } f_aggregate( num_headers ); f_reverse( 1 ); map_num_elems++; } f_aggregate_mapping( map_num_elems * 2 ); } free_string( s ); free_wbf_header_contents( &wh ); break; default: free_string( s ); free_wbf_header_contents( &wh );
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Unsupported wbf image type.\n");
2588311999-10-22Per Hedbor  } }
eab08e2001-11-07Martin Nilsson /*! @decl object decode(string image) *! *! @fixme *! Document this function. */
2588311999-10-22Per Hedbor static void image_f_wbf_decode( int args ) { low_image_f_wbf_decode( args, 2 ); }
eab08e2001-11-07Martin Nilsson /*! @decl mapping _decode(string image) *! *! @fixme *! Document this function. */
2588311999-10-22Per Hedbor static void image_f_wbf__decode( int args ) { low_image_f_wbf_decode( args, 1 ); }
eab08e2001-11-07Martin Nilsson /*! @decl mapping decode_header(string image) *! *! @returns *! @mapping *! @member string "format" *! The MIME type and encoding for the image, e.g. "image/x-wap.wbmp; type=0". *! @member int "xsize" *! @member int "ysize" *! @member int "fix_header_field" *! @member int "ext_header_field" *! @endmapping */
2588311999-10-22Per Hedbor static void image_f_wbf_decode_header( int args ) { low_image_f_wbf_decode( args, 0 ); }
b5f3b21999-10-22Per Hedbor void push_wap_integer( unsigned int i )
2588311999-10-22Per Hedbor {
b5f3b21999-10-22Per Hedbor  char data[10]; /* More than big enough... */
2588311999-10-22Per Hedbor  int pos = 0;
b5f3b21999-10-22Per Hedbor  if( !i ) { data[0] = 0; pos=1; } while( i )
2588311999-10-22Per Hedbor  {
b5f3b21999-10-22Per Hedbor  data[pos] = (i&0x7f) | 0x80; i>>=7; pos++;
2588311999-10-22Per Hedbor  }
b5f3b21999-10-22Per Hedbor  data[0] &= 0x7f; push_string( make_shared_binary_string( data, pos ) ); f_reverse(1);
2588311999-10-22Per Hedbor } static void push_wap_type0_image_data( struct image *i ) { int x, y; unsigned char *data, *p; rgb_group *is; data = malloc( i->ysize * (i->xsize+7)/8 ); MEMSET( data, 0, i->ysize * (i->xsize+7)/8 ); is = i->img; for( y = 0; y<i->ysize; y++ ) { p = data + (i->xsize+7)/8*y; for( x = 0; x<i->xsize; x++ ) { if( is->r || is->g || is->b ) p[x/8] |= 128 >> (x%8); is++; } }
01a9572000-02-03Henrik Grubbström (Grubba)  push_string( make_shared_binary_string( (char *)data, i->ysize * (i->xsize+7)/8 ) );
2588311999-10-22Per Hedbor }
eab08e2001-11-07Martin Nilsson /*! @decl string encode(object image, void|mapping args) *! @decl string _encode(object image, void|mapping args) *! *! @fixme *! Document this function. */
2588311999-10-22Per Hedbor static void image_f_wbf_encode( int args ) { struct object *o; struct image *i; struct mapping *options = NULL; int num_strings = 0; if( !args )
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("No image given to encode.\n");
2588311999-10-22Per Hedbor  if( args > 2 )
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Too many arguments to encode.\n");
2588311999-10-22Per Hedbor  if( sp[-args].type != T_OBJECT )
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("No image given to encode.\n");
2588311999-10-22Per Hedbor  o = sp[-args].u.object; i = (struct image*)get_storage(o,image_program); if(!i)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Wrong type object argument\n");
2588311999-10-22Per Hedbor  if( args == 2 ) { if( sp[-args+1].type != T_MAPPING )
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Wrong type for argument 2.\n");
2588311999-10-22Per Hedbor  options = sp[-args+1].u.mapping; } sp-=args; num_strings=0; push_wap_integer( 0 ); num_strings++; /* type */ push_wap_integer( 0 ); num_strings++; /* extra header */ push_wap_integer( i->xsize ); num_strings++; push_wap_integer( i->ysize ); num_strings++; push_wap_type0_image_data( i ); num_strings++; f_add( num_strings ); if( options ) free_mapping( options ); free_object( o ); }
eab08e2001-11-07Martin Nilsson /*! @endmodule */ /*! @endmodule */
2588311999-10-22Per Hedbor void init_image_wbf() { add_function( "encode", image_f_wbf_encode, "function(object,void|mapping:string)", 0); add_function( "_encode", image_f_wbf_encode, "function(object,void|mapping:string)", 0); add_function( "decode", image_f_wbf_decode, "function(string:object)", 0); add_function( "_decode", image_f_wbf__decode, "function(string:mapping)", 0); add_function( "decode_header", image_f_wbf_decode_header, "function(string:mapping)", 0); } void exit_image_wbf() { }