1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
30
  
31
  
32
  
33
  
34
  
35
  
36
  
37
  
38
  
39
  
40
  
41
  
42
  
43
  
44
  
45
  
46
  
47
  
48
  
49
  
50
  
51
  
52
  
53
  
54
  
55
  
56
  
57
  
58
  
59
  
60
  
61
  
62
  
63
  
64
  
65
  
66
  
67
  
68
  
69
  
70
  
71
  
72
  
73
  
74
  
75
  
76
  
77
  
78
  
79
  
80
  
81
  
82
  
83
  
84
  
85
  
86
  
87
  
88
  
89
  
90
  
91
  
92
  
93
  
94
  
95
  
96
  
97
  
98
  
99
  
100
  
101
  
102
  
103
  
104
  
105
  
106
  
107
  
108
  
109
  
static mapping parse_color( array color ) 
{ 
  mapping res = ([]); 
  for(int i=0; i<sizeof(color); i+=2 ) 
    if(lower_case(color[i+1]) != "none") 
      res[color[i]] = Colors.parse_color( color[i+1] ); 
  return sizeof(res)?res:0; 
} 
 
static array find_color( mapping in, string space ) 
{ 
  if(!in) return 0; 
  switch(space) 
  { 
   default: 
   case "s": 
     if(in->s) return in->s; 
   case "c": 
     if(in->c) return in->c; 
   case "g": 
     if(in->g) return in->g; 
   case "g4": 
     if(in->g4) return in->g4; 
   case "m": 
     if(in->m) return in->m; 
     if(in->s) return in->s; 
  } 
  if(sizeof(in)) 
    return values(in)[0]; 
  return 0; 
} 
 
mapping _decode( string what, void|mapping opts ) 
{ 
  array data; 
  mapping retopts = ([ ]); 
  if(!opts) 
    opts = ([]); 
  if(sscanf(what, "%*s/*%*[ \t]XPM%*[ \t]*/%*[ \t]\n%s", what)  != 5) 
    error("This is not a XPM image (1)\n"); 
  if(sscanf(what, "%*s{%s", what) != 2) 
    error("This is not a XPM image (2)\n"); 
 
  sscanf(what, "%s\n/* XPM */", what ) || 
    sscanf(what, "%s\n/*\tXPM\t*/", what ) || 
    sscanf(what, "%s\n/*\tXPM */", what )|| 
    sscanf(what, "%s\n/* XPM */", what ); 
 
  what = reverse(what); 
  if(sscanf(what, "%*s}%s", what) != 2) 
    error("This is not a XPM image (3)\n"); 
  what = reverse(what); 
 
   
  master()->set_inhibit_compile_errors(1); 
  if(catch { 
    data = compile_string( "mixed foo(){ return ({"+what+"}); }" )()->foo(); 
  }) 
    error("This is not a XPM image\n"); 
  master()->set_inhibit_compile_errors(0); 
   
  array values = (array(int))(replace(data[0], "\t", " ")/" "-({""})); 
  data = data[1..]; 
  int width = values[0]; 
  int height = values[1]; 
  int ncolors = values[2]; 
  int cpp = values[3]; 
  if(sizeof(values)>5) 
  { 
    retopts->hot_x = values[4]; 
    retopts->hot_y = values[5]; 
  } 
  mapping colors = ([]); 
  for(int i = 0; i<ncolors; i++ ) 
  { 
    if(i > sizeof(data)) 
      error("Too few elements in array to decode color values\n"); 
    string color_id = data[i][0..cpp-1]; 
    array color = replace(data[i][cpp..], "\t", " ")/" "-({""}); 
    colors[color_id] = parse_color( color ); 
  } 
  data = data[ncolors..]; 
 
  object i = Image.image( width, height ); 
  object a = Image.image( width, height,255,255,255 ); 
 
  for(int y = 0; y<height && y<sizeof(data); y++) 
  { 
    string line = data[y]; 
    for(int x = 0; x<width ; x++) 
    { 
      array c; 
      if( c = find_color(colors[line[x*cpp..x*cpp+cpp-1]], opts->colorspace) ) 
        i->setpixel( x, y, @c ); 
      else 
        a->setpixel( x, y, 0, 0, 0 ); 
    } 
  } 
  retopts->image = i; 
  retopts->alpha = a; 
  return retopts; 
} 
 
mapping decode( string what ) 
{ 
  return _decode(what)->image; 
}