PageRenderTime 2992ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/modules/_Image_XFace/image_xface.c

http://github.com/pikelang/Pike
C | 490 lines | 368 code | 58 blank | 64 comment | 71 complexity | 7ab248c00301c226385f1c482978fec1 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. /*
  2. || This file is part of Pike. For copyright information see COPYRIGHT.
  3. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
  4. || for more information.
  5. */
  6. #include "module.h"
  7. #include "config.h"
  8. #include "pike_macros.h"
  9. #include "constants.h"
  10. #include "interpret.h"
  11. #include "threads.h"
  12. #include "pike_error.h"
  13. #include "buffer.h"
  14. #include "operators.h"
  15. #include "builtin_functions.h"
  16. #include "pike_types.h"
  17. /* Includes <gmp.h> */
  18. #include "bignum.h"
  19. #include "../Image/image.h"
  20. #define sp Pike_sp
  21. #ifdef DYNAMIC_MODULE
  22. static struct program *image_program=NULL;
  23. #else
  24. extern struct program *image_program;
  25. /* Image module is probably linked static too. */
  26. #endif
  27. /*
  28. **! module Image
  29. **! submodule XFace
  30. **!
  31. **! note
  32. **! This module uses <tt>libgmp</tt>.
  33. */
  34. static const unsigned char tab[] = {
  35. 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0xc7, 0xfb, 0xa0, 0xe8, 0xa0, 0xf0,
  36. 0x00, 0xd8, 0xf0, 0xfb, 0x00, 0x20, 0x00, 0x00, 0xb0, 0xf0, 0xc0, 0xfe,
  37. 0x00, 0x00, 0x00, 0x80, 0x00, 0xb8, 0xa2, 0xf4, 0x00, 0x00, 0x00, 0xb0,
  38. 0x00, 0x50, 0xff, 0xff, 0x00, 0x20, 0x00, 0xa0, 0x80, 0xfc, 0xf3, 0xff,
  39. 0x08, 0x80, 0x01, 0x93, 0xf0, 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  40. 0xd8, 0xf8, 0xff, 0xff, 0xf2, 0x2a, 0xe0, 0xf8, 0xea, 0xe2, 0xeb, 0xbc,
  41. 0xff, 0xff, 0xfa, 0xf8, 0xfe, 0xff, 0xfe, 0xfe, 0xa0, 0xf0, 0x80, 0xf0,
  42. 0xf0, 0xfa, 0xd9, 0xfb, 0xfe, 0xff, 0xfa, 0xb8, 0xfa, 0xff, 0xf0, 0xf8,
  43. 0xf0, 0xfa, 0xc0, 0xf8, 0xf2, 0xfa, 0xef, 0xfe, 0xfe, 0xff, 0xb0, 0xf0,
  44. 0xdf, 0xff, 0xef, 0xfd, 0xf0, 0xf2, 0xeb, 0xfc, 0xf2, 0xfe, 0xff, 0xff,
  45. 0xe6, 0xfd, 0x6a, 0xa4, 0xf8, 0xfe, 0xf9, 0xff, 0x00, 0x00, 0x00, 0xa0,
  46. 0xfa, 0xfe, 0x80, 0xfb, 0x28, 0x00, 0xa0, 0xf0, 0xe0, 0x45, 0x90, 0xf0,
  47. 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfa, 0x18, 0xeb, 0x29, 0x8e, 0x00, 0xa0,
  48. 0xf8, 0xed, 0x30, 0xe0, 0xf0, 0xf0, 0x00, 0xf0, 0xf0, 0xf8, 0x21, 0xf1,
  49. 0xa0, 0xa8, 0xa0, 0xf0, 0xf2, 0xff, 0xe1, 0xfb, 0xa0, 0x80, 0x08, 0x00,
  50. 0xf0, 0xf0, 0x00, 0x10, 0xa0, 0x20, 0x20, 0x80, 0xf2, 0xff, 0xf9, 0xf1,
  51. 0x52, 0x02, 0xfa, 0xfa, 0xff, 0x7f, 0xfb, 0xff, 0xfe, 0xef, 0xff, 0xfe,
  52. 0xff, 0xff, 0xde, 0xff, 0xf0, 0xbf, 0xeb, 0xfa, 0xf2, 0xfe, 0xfe, 0xfb,
  53. 0xff, 0xff, 0xff, 0xff, 0xff, 0xee, 0xfb, 0xfe, 0xf2, 0xf7, 0xff, 0xff,
  54. 0xee, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xf0, 0xf2, 0xff, 0xff, 0xb9, 0xff,
  55. 0xf0, 0xf7, 0xff, 0xfb, 0xf6, 0xff, 0xff, 0xff, 0xf2, 0xff, 0xb3, 0xf0,
  56. 0xf2, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0xd0, 0xa0, 0x40, 0x40, 0xf0,
  57. 0x20, 0x00, 0x00, 0x30, 0x80, 0x60, 0x00, 0xf0, 0x04, 0xc0, 0x00, 0x00,
  58. 0xa0, 0xf0, 0x02, 0x10, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x30, 0xf0,
  59. 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x80, 0xa0,
  60. 0x80, 0xa8, 0xf5, 0xf0, 0x00, 0x80, 0x08, 0x00, 0x10, 0x00, 0x62, 0x30,
  61. 0x04, 0x00, 0x11, 0x00, 0xf0, 0xa8, 0xff, 0xfb, 0x40, 0x00, 0x00, 0xf0,
  62. 0xfe, 0xfa, 0xdb, 0xff, 0xf2, 0x7c, 0xa0, 0xf0, 0xfe, 0xef, 0xa9, 0xf2,
  63. 0xb0, 0xf0, 0x80, 0xf0, 0xf2, 0xfa, 0xf9, 0xfb, 0xa4, 0x70, 0xb0, 0xb0,
  64. 0xf2, 0xfe, 0xf1, 0xf0, 0xf0, 0x5f, 0x20, 0xf2, 0xf2, 0xff, 0xef, 0xee,
  65. 0xe2, 0xb7, 0xa0, 0xf0, 0xff, 0xff, 0xfb, 0xff, 0xf2, 0xf6, 0x1b, 0xfa,
  66. 0xf0, 0xfe, 0xfb, 0xfa, 0xe0, 0xf0, 0x29, 0xb0, 0xf8, 0xff, 0xff, 0xff,
  67. 0x00, 0x40, 0x00, 0xc0, 0x62, 0xea, 0x80, 0xb0, 0x80, 0x10, 0x80, 0xf0,
  68. 0xe2, 0x36, 0xb0, 0xf0, 0x40, 0x00, 0x00, 0x00, 0xd0, 0xf2, 0x00, 0x10,
  69. 0xa0, 0x00, 0xa9, 0x80, 0xf0, 0xfe, 0x30, 0xf0, 0x80, 0x70, 0x00, 0x00,
  70. 0xf0, 0x82, 0x00, 0x00, 0x20, 0x24, 0xb0, 0xf0, 0xf0, 0xfe, 0xf3, 0xfb,
  71. 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x60, 0x64, 0xf3, 0xa0,
  72. 0xf3, 0xfe, 0xfb, 0xfb, 0x00, 0x00, 0xe8, 0xfa, 0xff, 0xbf, 0xff, 0xff,
  73. 0x62, 0x90, 0xf2, 0xfa, 0xfe, 0xbf, 0xfb, 0xff, 0x50, 0x11, 0xe5, 0xfe,
  74. 0xfe, 0xff, 0xff, 0xff, 0xf0, 0x20, 0xfb, 0xfe, 0xf2, 0xff, 0xf9, 0xff,
  75. 0x70, 0x67, 0xfb, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xf0, 0x37, 0xf1, 0xf2,
  76. 0xfe, 0xff, 0xfb, 0xff, 0xf0, 0xf3, 0xfb, 0xff, 0xf6, 0xfe, 0xff, 0xff,
  77. 0xc0, 0x30, 0xb9, 0xf0, 0xfe, 0xff, 0xff, 0xff, 0xec, 0xce, 0x00, 0x98,
  78. 0xea, 0xfe, 0xaf, 0xdf, 0x0e, 0xcc, 0x0f, 0x9f, 0xfe, 0xff, 0xff, 0xff,
  79. 0x0a, 0x00, 0x00, 0x00, 0xa0, 0x00, 0xf0, 0xac, 0x1f, 0x02, 0x82, 0x9e,
  80. 0x0f, 0x42, 0x0c, 0xfa, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x0c, 0xcc, 0xbc,
  81. 0x0e, 0x0a, 0xac, 0xcf, 0x8f, 0xce, 0xfc, 0xff, 0x0f, 0x10, 0x00, 0x04,
  82. 0x82, 0x04, 0x80, 0xa8, 0x0e, 0x4a, 0x0a, 0x0a, 0xcc, 0xda, 0x9f, 0xff,
  83. 0x0f, 0x6e, 0x4f, 0x20, 0x80, 0x0e, 0xf6, 0x75, 0x01, 0x08, 0x8e, 0x9f,
  84. 0x8f, 0xff, 0xff, 0xff, 0x0f, 0x02, 0x00, 0x08, 0x28, 0x4c, 0xf7, 0xcf,
  85. 0x8f, 0x88, 0x88, 0x88, 0xa8, 0x88, 0x88, 0x8c, 0x88, 0x88, 0x88, 0x8c,
  86. 0x88, 0x88, 0xc8, 0x8c, 0x88, 0x8c, 0x88, 0x8c, 0x8c, 0x8c, 0xcc, 0xc8,
  87. 0x88, 0x08, 0x88, 0x88, 0xe8, 0x88, 0x88, 0xe8, 0x0a, 0x00, 0x0f, 0x00,
  88. 0x09, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0f, 0x20, 0x77, 0x02, 0x8b, 0x00,
  89. 0x0f, 0x00, 0x2f, 0x22, 0x0f, 0x80, 0x07, 0x0f, 0x5f, 0x57, 0x2f, 0xea,
  90. 0x7f, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x09, 0x88, 0x08, 0x00, 0x88, 0xb3,
  91. 0x0b, 0x80, 0x0a, 0xf0, 0x0f, 0x80, 0x00, 0xf0, 0x0b, 0x00, 0x2f, 0xaf,
  92. 0xcf, 0xfb, 0xff, 0xff, 0x2f, 0xff, 0x8f, 0xf3, 0xbf, 0xff, 0x1f, 0xff,
  93. 0x0f, 0x00, 0x0b, 0x00, 0x00, 0x80, 0x0a, 0x08, 0x0e, 0x00, 0x08, 0x84,
  94. 0x0f, 0x88, 0x08, 0xea, 0x0f, 0x80, 0x2f, 0xa8, 0x8e, 0xff, 0x0f, 0xea,
  95. 0x0e, 0xab, 0x2f, 0xfb, 0x2f, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x00, 0x04,
  96. 0x0a, 0x80, 0x08, 0xea, 0x8b, 0x80, 0x4a, 0xff, 0x2f, 0xa0, 0x00, 0xfb,
  97. 0x0b, 0x02, 0x0f, 0x8e, 0x0f, 0xee, 0x0f, 0xdf, 0x0f, 0xeb, 0x0f, 0xff,
  98. 0x2f, 0xeb, 0x0b, 0xff, 0x0f, 0x88, 0x0c, 0xec, 0x8f, 0xae, 0xaa, 0xae,
  99. 0xee, 0x0f, 0x08, 0x08, 0x88, 0x0f, 0x8c, 0xcf, 0xff, 0x2f, 0x44
  100. };
  101. /*
  102. 00 01 02 10 20 30 40 11 21 31 41 12 22 32 42
  103. 0000 4096 4224 4228 4740 4804 5060 6084 6116 6124 6156 6220 6222 6223 6227
  104. */
  105. static const int taboffs[] = { 0, 4740, 4228, 5060, 4224, 6222, 6220, 6227,
  106. 4096, 6116, 6084, 6156 };
  107. static void xform(unsigned char *i, unsigned char *o)
  108. {
  109. int x, y, X, Y, p, n;
  110. for(y=0; y<48; y++)
  111. for(x=0; x<48; x++) {
  112. n=0;
  113. for(X=(x<3? 1:x-2); X<x+3; X++)
  114. for(Y=(y<3? 1:y-2); Y<=y; Y++)
  115. if((Y<y || X<x) && X<=48)
  116. n = (n<<1)|i[Y*48+X];
  117. if((p=x)==47)
  118. p = 3;
  119. else if(x>2)
  120. p = 0;
  121. if(y==1)
  122. p += 4;
  123. else if(y==2)
  124. p += 8;
  125. n += taboffs[p];
  126. *o++ ^= (tab[n>>3]>>(n&7))&1;
  127. }
  128. }
  129. static const unsigned int topprob[4][6] = {
  130. {1, 255, 251, 0, 4, 251},
  131. {1, 255, 200, 0, 55, 200},
  132. {33, 223, 159, 0, 64, 159},
  133. {131, 0, 0, 0, 125, 131}
  134. };
  135. static const unsigned int botprob[32] = {
  136. 0, 0, 38, 0, 38, 38, 13, 152,
  137. 38, 76, 13, 165, 13, 178, 6, 230,
  138. 38, 114, 13, 191, 13, 204, 6, 236,
  139. 13, 217, 6, 242, 5, 248, 3, 253
  140. };
  141. static int pop(mpz_t val, const unsigned int *p)
  142. {
  143. unsigned long int n;
  144. int r = 0;
  145. mpz_t dum;
  146. mpz_init(dum);
  147. n = mpz_fdiv_qr_ui(val, dum, val, 256);
  148. mpz_clear(dum);
  149. while(n<p[1] || n>=p[0]+p[1]) {
  150. r++;
  151. p += 2;
  152. }
  153. mpz_mul_ui(val, val, *p++);
  154. mpz_add_ui(val, val, n-*p);
  155. return r;
  156. }
  157. static void push(mpz_t val, const unsigned int *p, int r)
  158. {
  159. unsigned long int n;
  160. mpz_t dum;
  161. p += r<<1;
  162. mpz_init(dum);
  163. n = mpz_fdiv_qr_ui(val, dum, val, p[0]);
  164. mpz_clear(dum);
  165. mpz_mul_ui(val, val, 256);
  166. mpz_add_ui(val, val, n+p[1]);
  167. }
  168. static void popg(mpz_t val, unsigned char *face, int s)
  169. {
  170. if(s>=4) {
  171. s>>=1;
  172. popg(val, face, s);
  173. popg(val, face+s, s);
  174. popg(val, face+s*48, s);
  175. popg(val, face+s*49, s);
  176. } else {
  177. int p = pop(val, botprob);
  178. face[0]=p&1; p>>=1;
  179. face[1]=p&1; p>>=1;
  180. face[48]=p&1; p>>=1;
  181. face[49]=p&1;
  182. }
  183. }
  184. static void pushg(mpz_t val, unsigned char *face, int s)
  185. {
  186. if(s>=4) {
  187. s>>=1;
  188. pushg(val, face+s*49, s);
  189. pushg(val, face+s*48, s);
  190. pushg(val, face+s, s);
  191. pushg(val, face, s);
  192. } else
  193. push(val, botprob,
  194. (face[0])|((face[1])<<1)|((face[48])<<2)|((face[49])<<3));
  195. }
  196. static void uncomp(mpz_t val, unsigned char *face, int s, int l)
  197. {
  198. switch(pop(val, topprob[l])) {
  199. case 0:
  200. popg(val, face, s);
  201. break;
  202. case 1:
  203. s>>=1;
  204. l++;
  205. uncomp(val, face, s, l);
  206. uncomp(val, face+s, s, l);
  207. uncomp(val, face+s*48, s, l);
  208. uncomp(val, face+s*49, s, l);
  209. break;
  210. }
  211. }
  212. static int all_white(unsigned char *face, int s)
  213. {
  214. int i, j;
  215. for(i=0; i<s; i++) {
  216. for(j=0; j<s; j++)
  217. if(face[j])
  218. return 0;
  219. face += 48;
  220. }
  221. return 1;
  222. }
  223. static int all_black(unsigned char *face, int s)
  224. {
  225. if(s>=4) {
  226. s>>=1;
  227. return all_black(face, s) && all_black(face+s, s) &&
  228. all_black(face+s*48, s) && all_black(face+s*49, s);
  229. } else
  230. return face[0] || face[1] || face[48] || face[49];
  231. }
  232. static void comp(mpz_t val, unsigned char *face, int s, int l)
  233. {
  234. if(all_white(face, s))
  235. push(val, topprob[l], 2);
  236. else if(all_black(face, s)) {
  237. pushg(val, face, s);
  238. push(val, topprob[l], 0);
  239. } else {
  240. s>>=1;
  241. l++;
  242. comp(val, face+s*49, s, l);
  243. comp(val, face+s*48, s, l);
  244. comp(val, face+s, s, l);
  245. comp(val, face, s, l);
  246. push(val, topprob[l-1], 1);
  247. }
  248. }
  249. static void decodeface(char *data, INT32 len, rgb_group *out)
  250. {
  251. unsigned char face[48][48];
  252. int i, j;
  253. mpz_t val;
  254. mpz_init(val);
  255. mpz_set_ui(val, 0);
  256. while(len--)
  257. if(*data>='!' && *data<='~') {
  258. mpz_mul_ui(val, val, 94);
  259. mpz_add_ui(val, val, *data++-'!');
  260. } else
  261. data++;
  262. memset(face, 0, sizeof(face));
  263. for(i=0; i<3; i++)
  264. for(j=0; j<3; j++)
  265. uncomp(val, &face[i*16][j*16], 16, 0);
  266. mpz_clear(val);
  267. xform((unsigned char *)face, (unsigned char *)face);
  268. for(i=0; i<48; i++)
  269. for(j=0; j<48; j++) {
  270. if(face[i][j])
  271. out->r = out->g = out->b = 0;
  272. else
  273. out->r = out->g = out->b = 0xff;
  274. out++;
  275. }
  276. }
  277. static struct pike_string *encodeface(rgb_group *in)
  278. {
  279. unsigned char face[48][48], newface[48][48];
  280. int i, j;
  281. unsigned long int n;
  282. mpz_t val, dum;
  283. struct byte_buffer buf;
  284. for(i=0; i<48; i++)
  285. for(j=0; j<48; j++) {
  286. if(in->r || in->g || in->b)
  287. face[i][j] = 0;
  288. else
  289. face[i][j] = 1;
  290. in++;
  291. }
  292. memcpy(newface, face, sizeof(face));
  293. xform((unsigned char *)face, (unsigned char *)newface);
  294. mpz_init(val);
  295. mpz_set_ui(val, 0);
  296. for(i=2; i>=0; --i)
  297. for(j=2; j>=0; --j)
  298. comp(val, &newface[i*16][j*16], 16, 0);
  299. buffer_init( &buf );
  300. mpz_init(dum);
  301. i = 0;
  302. while(mpz_cmp_ui(val, 0)) {
  303. n = mpz_fdiv_qr_ui(val, dum, val, 94);
  304. buffer_add_char( &buf , (char)(n+'!'));
  305. i++;
  306. }
  307. if (i==0)
  308. buffer_add_char( &buf , '!');
  309. mpz_clear(dum);
  310. mpz_clear(val);
  311. return buffer_finish_pike_string( &buf );
  312. }
  313. /*
  314. **! method object decode(string data)
  315. **! method object decode(string data, mapping options)
  316. **! Decodes an X-Face image.
  317. **!
  318. **! The <tt>options</tt> argument may be a mapping
  319. **! containing zero options.
  320. **!
  321. */
  322. static void image_xface_decode(INT32 args)
  323. {
  324. struct object *o;
  325. struct image *img;
  326. if(args<1 || TYPEOF(sp[-args]) != T_STRING)
  327. Pike_error("Illegal arguments\n");
  328. o=clone_object(image_program,0);
  329. img=get_storage(o,image_program);
  330. if (!img) Pike_error("image no image? foo?\n"); /* should never happen */
  331. img->img=malloc(sizeof(rgb_group)*48*48);
  332. if (!img->img) {
  333. free_object(o);
  334. Pike_error("Out of memory\n");
  335. }
  336. img->xsize=48;
  337. img->ysize=48;
  338. decodeface(sp[-args].u.string->str, sp[-args].u.string->len, img->img);
  339. pop_n_elems(args);
  340. push_object(o);
  341. }
  342. /*
  343. **! method string encode(object img)
  344. **! method string encode(object img, mapping options)
  345. **! Encodes an X-Face image.
  346. **!
  347. **! The <tt>img</tt> argument must be an image of the dimensions
  348. **! 48 by 48 pixels. All non-black pixels will be considered white.
  349. **!
  350. **! The <tt>options</tt> argument may be a mapping
  351. **! containing zero options.
  352. **!
  353. */
  354. static void image_xface_encode(INT32 args)
  355. {
  356. struct image *img=NULL;
  357. struct pike_string *res;
  358. if (args<1
  359. || TYPEOF(sp[-args]) != T_OBJECT
  360. || !(img=get_storage(sp[-args].u.object,image_program))
  361. || (args>1 && TYPEOF(sp[1-args]) != T_MAPPING))
  362. Pike_error("Illegal arguments\n");
  363. if (!img->img)
  364. Pike_error("Given image is empty.\n");
  365. if (img->xsize != 48 || img->ysize != 48)
  366. Pike_error("Wrong image dimensions (must be 48 by 48).\n");
  367. res = encodeface(img->img);
  368. pop_n_elems(args);
  369. if (res == NULL)
  370. push_int(0);
  371. else {
  372. push_string(res);
  373. f_reverse(1);
  374. }
  375. }
  376. /*
  377. **! method object decode_header(string data)
  378. **! method object decode_header(string data, mapping options)
  379. **! Decodes an X-Face image header.
  380. **!
  381. **! <pre>
  382. **! "xsize":int
  383. **! "ysize":int
  384. **! size of image
  385. **! "type":"image/x-xface"
  386. **! file type information
  387. **! </pre>
  388. **!
  389. **! The <tt>options</tt> argument may be a mapping
  390. **! containing zero options.
  391. **!
  392. **! note
  393. **! There aint no such thing as a X-Face image header.
  394. **! This stuff tells the characteristics of an X-Face image.
  395. **!
  396. */
  397. static void image_xface_decode_header(INT32 args)
  398. {
  399. if(args<1 || TYPEOF(sp[-args]) != T_STRING)
  400. Pike_error("Illegal arguments\n");
  401. pop_n_elems(args);
  402. ref_push_string(literal_type_string);
  403. push_static_text("image/x-xface");
  404. push_static_text("xsize");
  405. push_int(48);
  406. push_static_text("ysize");
  407. push_int(48);
  408. f_aggregate_mapping(6);
  409. }
  410. /*** module init & exit & stuff *****************************************/
  411. PIKE_MODULE_EXIT
  412. {
  413. }
  414. PIKE_MODULE_INIT
  415. {
  416. #ifdef DYNAMIC_MODULE
  417. push_static_text("Image.Image");
  418. SAFE_APPLY_MASTER("resolv",1);
  419. if (TYPEOF(sp[-1]) == T_PROGRAM)
  420. image_program=program_from_svalue(sp-1);
  421. pop_stack();
  422. #endif /* DYNAMIC_MODULE */
  423. if (image_program)
  424. {
  425. /* function(string,void|mapping(string:int):object) */
  426. ADD_FUNCTION("decode",image_xface_decode,tFunc(tStr tOr(tVoid,tMap(tStr,tInt)),tObj),0);
  427. /* function(string,void|mapping(string:int):object) */
  428. ADD_FUNCTION("decode_header",image_xface_decode_header,tFunc(tStr tOr(tVoid,tMap(tStr,tInt)),tObj),0);
  429. /* function(object,void|mapping(string:int):string) */
  430. ADD_FUNCTION("encode",image_xface_encode,tFunc(tObj tOr(tVoid,tMap(tStr,tInt)),tStr),0);
  431. }
  432. }