You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

context.c 20 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. /*
  2. * libpipi Pathetic image processing interface library
  3. * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * context.c: processing stack handling routines
  16. */
  17. #include "config.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <stdarg.h>
  21. #include <string.h>
  22. #include "pipi.h"
  23. #include "pipi_internals.h"
  24. pipi_context_t *pipi_create_context()
  25. {
  26. pipi_context_t *ret;
  27. ret = malloc(sizeof(pipi_context_t));
  28. memset(ret, 0, sizeof(pipi_context_t));
  29. return ret;
  30. }
  31. void pipi_destroy_context(pipi_context_t *ctx)
  32. {
  33. free(ctx);
  34. }
  35. pipi_command_t const *pipi_get_command_list(void)
  36. {
  37. static pipi_command_t const list[] =
  38. {
  39. { "load", 1 },
  40. { "save", 1 },
  41. { "dup", 0 },
  42. { "swap", 0 },
  43. { "roll", 1 },
  44. { "gamma", 1 },
  45. { "scale", 1 },
  46. { "crop", 1 },
  47. { "geometry", 1 },
  48. { "tile", 1 },
  49. { "dither", 1 },
  50. { "blur", 1 },
  51. { "boxblur", 1 },
  52. { "median", 1 },
  53. { "gray", 0 },
  54. { "brightness", 1 },
  55. { "contrast", 1 },
  56. { "autocontrast", 0 },
  57. { "order", 0 },
  58. { "hflip", 0 },
  59. { "vflip", 0 },
  60. { "rotate90", 0 },
  61. { "rotate180", 0 },
  62. { "rotate270", 0 },
  63. { "rotate", 1 },
  64. { "invert", 0 },
  65. { "threshold", 1 },
  66. { "dilate", 0 },
  67. { "erode", 0 },
  68. { "wrap", 0 },
  69. { "combine", 0 },
  70. { "split", 0 },
  71. { "blit", 1 },
  72. { "mean", 0 },
  73. { "merge", 1 },
  74. { "min", 0 },
  75. { "max", 0 },
  76. { "add", 0 },
  77. { "sub", 0 },
  78. { "difference", 0 },
  79. { "multiply", 0 },
  80. { "divide", 0 },
  81. { "screen", 0 },
  82. { "overlay", 0 },
  83. { "line", 1 },
  84. { "sine", 1 },
  85. { "wave", 1 },
  86. /* End marker */
  87. { NULL, 0 }
  88. };
  89. return list;
  90. }
  91. int pipi_command(pipi_context_t *ctx, char const *cmd, ...)
  92. {
  93. if(!strcmp(cmd, "load"))
  94. {
  95. char const *file;
  96. va_list ap;
  97. va_start(ap, cmd);
  98. file = va_arg(ap, char const *);
  99. va_end(ap);
  100. ctx->images[ctx->nimages] = pipi_load(file);
  101. if(ctx->images[ctx->nimages] == NULL)
  102. return -1;
  103. ctx->nimages++;
  104. }
  105. else if(!strcmp(cmd, "save"))
  106. {
  107. char const *file;
  108. va_list ap;
  109. if(ctx->nimages < 1)
  110. return -1;
  111. ctx->nimages--;
  112. va_start(ap, cmd);
  113. file = va_arg(ap, char const *);
  114. va_end(ap);
  115. pipi_save(ctx->images[ctx->nimages], file);
  116. pipi_free(ctx->images[ctx->nimages]);
  117. }
  118. else if(!strcmp(cmd, "gamma"))
  119. {
  120. char const *val;
  121. va_list ap;
  122. va_start(ap, cmd);
  123. val = va_arg(ap, char const *);
  124. va_end(ap);
  125. pipi_set_gamma(atof(val));
  126. }
  127. else if(!strcmp(cmd, "dither"))
  128. {
  129. pipi_image_t *src, *dst;
  130. char const *method;
  131. va_list ap;
  132. if(ctx->nimages < 1)
  133. return -1;
  134. va_start(ap, cmd);
  135. method = va_arg(ap, char const *);
  136. va_end(ap);
  137. src = ctx->images[ctx->nimages - 1];
  138. dst = NULL;
  139. if(!strcmp(method, "ost"))
  140. dst = pipi_dither_ostromoukhov(src, 0);
  141. else if(!strcmp(method, "sost"))
  142. dst = pipi_dither_ostromoukhov(src, 1);
  143. else if(!strcmp(method, "ediff"))
  144. {
  145. if(ctx->nimages < 2)
  146. return -1;
  147. dst = pipi_dither_ediff(ctx->images[ctx->nimages - 2], src, 0);
  148. pipi_free(ctx->images[ctx->nimages - 2]);
  149. ctx->nimages--;
  150. }
  151. else if(!strcmp(method, "sediff"))
  152. {
  153. if(ctx->nimages < 2)
  154. return -1;
  155. dst = pipi_dither_ediff(ctx->images[ctx->nimages - 2], src, 1);
  156. pipi_free(ctx->images[ctx->nimages - 2]);
  157. ctx->nimages--;
  158. }
  159. else if(!strncmp(method, "ordered", 7))
  160. {
  161. double scale = 1., angle = .0;
  162. if(ctx->nimages < 2)
  163. return -1;
  164. method = strchr(method, ':');
  165. if(method)
  166. {
  167. scale = atof(method + 1);
  168. method = strchr(method + 1, ':');
  169. if(method)
  170. angle = atof(method + 1);
  171. }
  172. if(scale <= 0.)
  173. scale = 1.;
  174. dst = pipi_dither_ordered_ext(ctx->images[ctx->nimages - 2], src,
  175. scale, angle);
  176. pipi_free(ctx->images[ctx->nimages - 2]);
  177. ctx->nimages--;
  178. }
  179. else if(!strncmp(method, "halftone", 8))
  180. {
  181. double r, angle = .0;
  182. method = strchr(method, ':');
  183. if(!method)
  184. return -1;
  185. r = atof(method + 1);
  186. method = strchr(method + 1, ':');
  187. if(method)
  188. angle = atof(method + 1);
  189. if(r < 1.)
  190. r = 1.;
  191. dst = pipi_dither_halftone(src, r, angle);
  192. }
  193. else if(!strcmp(method, "random"))
  194. dst = pipi_dither_random(src);
  195. else if(!strcmp(method, "dbs"))
  196. dst = pipi_dither_dbs(src);
  197. if(dst == NULL)
  198. return -1;
  199. pipi_free(src);
  200. ctx->images[ctx->nimages - 1] = dst;
  201. }
  202. else if(!strcmp(cmd, "blur"))
  203. {
  204. pipi_image_t *src, *dst;
  205. char const *arg;
  206. va_list ap;
  207. double w, h, a = 0.0;
  208. if(ctx->nimages < 1)
  209. return -1;
  210. va_start(ap, cmd);
  211. arg = va_arg(ap, char const *);
  212. va_end(ap);
  213. w = h = atof(arg);
  214. arg = strchr(arg, 'x');
  215. if(arg)
  216. {
  217. h = atof(arg + 1);
  218. arg = strchr(arg, 'r');
  219. if(arg)
  220. a = atof(arg + 1);
  221. }
  222. src = ctx->images[ctx->nimages - 1];
  223. dst = pipi_gaussian_blur_ext(src, w, h, a, 0.0, 0.0);
  224. if(dst == NULL)
  225. return -1;
  226. pipi_free(src);
  227. ctx->images[ctx->nimages - 1] = dst;
  228. }
  229. else if(!strcmp(cmd, "boxblur") || !strcmp(cmd, "median"))
  230. {
  231. pipi_image_t *src, *dst = NULL;
  232. char const *arg;
  233. va_list ap;
  234. double w, h;
  235. if(ctx->nimages < 1)
  236. return -1;
  237. va_start(ap, cmd);
  238. arg = va_arg(ap, char const *);
  239. va_end(ap);
  240. w = h = atof(arg);
  241. arg = strchr(arg, 'x');
  242. if(arg)
  243. h = atof(arg + 1);
  244. src = ctx->images[ctx->nimages - 1];
  245. switch(cmd[0])
  246. {
  247. case 'b': dst = pipi_box_blur_ext(src, w, h); break;
  248. case 'm': dst = pipi_median_ext(src, w, h); break;
  249. }
  250. if(dst == NULL)
  251. return -1;
  252. pipi_free(src);
  253. ctx->images[ctx->nimages - 1] = dst;
  254. }
  255. else if(!strcmp(cmd, "geometry") || !strcmp(cmd, "tile"))
  256. {
  257. pipi_image_t *src, *dst = NULL;
  258. char const *arg;
  259. va_list ap;
  260. int w, h;
  261. if(ctx->nimages < 1)
  262. return -1;
  263. va_start(ap, cmd);
  264. arg = va_arg(ap, char const *);
  265. va_end(ap);
  266. w = atoi(arg);
  267. arg = strchr(arg, 'x');
  268. if(!arg)
  269. return -1;
  270. h = atoi(arg + 1);
  271. if(w <= 0 || h <= 0)
  272. return -1;
  273. src = ctx->images[ctx->nimages - 1];
  274. switch(cmd[0])
  275. {
  276. case 'g': dst = pipi_resize(src, w, h); break;
  277. case 't': dst = pipi_tile(src, w, h); break;
  278. }
  279. if(dst == NULL)
  280. return -1;
  281. pipi_free(src);
  282. ctx->images[ctx->nimages - 1] = dst;
  283. }
  284. else if(!strcmp(cmd, "scale"))
  285. {
  286. pipi_image_t *src, *dst;
  287. char const *arg;
  288. va_list ap;
  289. double scale;
  290. int w, h;
  291. if(ctx->nimages < 1)
  292. return -1;
  293. src = ctx->images[ctx->nimages - 1];
  294. va_start(ap, cmd);
  295. arg = va_arg(ap, char const *);
  296. va_end(ap);
  297. scale = atof(arg);
  298. w = (int)(scale * src->w + 0.5);
  299. h = (int)(scale * src->h + 0.5);
  300. if(w <= 0 || h <= 0)
  301. return -1;
  302. dst = pipi_resize(src, w, h);
  303. if(dst == NULL)
  304. return -1;
  305. pipi_free(src);
  306. ctx->images[ctx->nimages - 1] = dst;
  307. }
  308. else if(!strcmp(cmd, "crop"))
  309. {
  310. pipi_image_t *tmp;
  311. char const *arg;
  312. va_list ap;
  313. int w, h, x = 0, y = 0;
  314. int ret;
  315. if(ctx->nimages < 1)
  316. return -1;
  317. va_start(ap, cmd);
  318. arg = va_arg(ap, char const *);
  319. va_end(ap);
  320. ret = sscanf(arg, "%dx%d+%d+%d", &w, &h, &x, &y);
  321. if(ret < 2)
  322. return -1;
  323. tmp = ctx->images[ctx->nimages - 1];
  324. ctx->images[ctx->nimages - 1] = pipi_crop(tmp, w, h, x, y);
  325. pipi_free(tmp);
  326. }
  327. else if(!strcmp(cmd, "brightness") || !strcmp(cmd, "contrast")
  328. || !strcmp(cmd, "threshold") || !strcmp(cmd, "rotate"))
  329. {
  330. pipi_image_t *src, *dst = NULL;
  331. char const *arg;
  332. va_list ap;
  333. double val;
  334. if(ctx->nimages < 1)
  335. return -1;
  336. va_start(ap, cmd);
  337. arg = va_arg(ap, char const *);
  338. va_end(ap);
  339. val = atof(arg);
  340. src = ctx->images[ctx->nimages - 1];
  341. switch(cmd[0])
  342. {
  343. case 'b': dst = pipi_brightness(src, val); break;
  344. case 'c': dst = pipi_contrast(src, val); break;
  345. case 'r': dst = pipi_rotate(src, val); break;
  346. case 't': dst = pipi_threshold(src, val); break;
  347. }
  348. if(dst == NULL)
  349. return -1;
  350. pipi_free(src);
  351. ctx->images[ctx->nimages - 1] = dst;
  352. }
  353. else if(!strcmp(cmd, "hflip"))
  354. {
  355. pipi_image_t *tmp;
  356. if(ctx->nimages < 1)
  357. return -1;
  358. tmp = ctx->images[ctx->nimages - 1];
  359. ctx->images[ctx->nimages - 1] = pipi_hflip(tmp);
  360. pipi_free(tmp);
  361. }
  362. else if(!strcmp(cmd, "vflip"))
  363. {
  364. pipi_image_t *tmp;
  365. if(ctx->nimages < 1)
  366. return -1;
  367. tmp = ctx->images[ctx->nimages - 1];
  368. ctx->images[ctx->nimages - 1] = pipi_vflip(tmp);
  369. pipi_free(tmp);
  370. }
  371. else if(!strcmp(cmd, "rotate90"))
  372. {
  373. pipi_image_t *tmp;
  374. if(ctx->nimages < 1)
  375. return -1;
  376. tmp = ctx->images[ctx->nimages - 1];
  377. ctx->images[ctx->nimages - 1] = pipi_rotate90(tmp);
  378. pipi_free(tmp);
  379. }
  380. else if(!strcmp(cmd, "rotate180"))
  381. {
  382. pipi_image_t *tmp;
  383. if(ctx->nimages < 1)
  384. return -1;
  385. tmp = ctx->images[ctx->nimages - 1];
  386. ctx->images[ctx->nimages - 1] = pipi_rotate180(tmp);
  387. pipi_free(tmp);
  388. }
  389. else if(!strcmp(cmd, "rotate270"))
  390. {
  391. pipi_image_t *tmp;
  392. if(ctx->nimages < 1)
  393. return -1;
  394. tmp = ctx->images[ctx->nimages - 1];
  395. ctx->images[ctx->nimages - 1] = pipi_rotate270(tmp);
  396. pipi_free(tmp);
  397. }
  398. else if(!strcmp(cmd, "order"))
  399. {
  400. pipi_image_t *tmp;
  401. if(ctx->nimages < 1)
  402. return -1;
  403. tmp = ctx->images[ctx->nimages - 1];
  404. ctx->images[ctx->nimages - 1] = pipi_order(tmp);
  405. pipi_free(tmp);
  406. }
  407. else if(!strcmp(cmd, "split"))
  408. {
  409. pipi_image_t *src;
  410. if(ctx->nimages < 1)
  411. return -1;
  412. src = ctx->images[ctx->nimages - 1];
  413. ctx->nimages += 2;
  414. ctx->images[ctx->nimages - 3] = pipi_red(src);
  415. ctx->images[ctx->nimages - 2] = pipi_green(src);
  416. ctx->images[ctx->nimages - 1] = pipi_blue(src);
  417. pipi_free(src);
  418. }
  419. else if(!strcmp(cmd, "combine"))
  420. {
  421. pipi_image_t *dst;
  422. if(ctx->nimages < 3)
  423. return -1;
  424. dst = pipi_rgb(ctx->images[ctx->nimages - 3],
  425. ctx->images[ctx->nimages - 2],
  426. ctx->images[ctx->nimages - 1]);
  427. if(dst == NULL)
  428. return -1;
  429. pipi_free(ctx->images[ctx->nimages - 3]);
  430. pipi_free(ctx->images[ctx->nimages - 2]);
  431. pipi_free(ctx->images[ctx->nimages - 1]);
  432. ctx->images[ctx->nimages - 3] = dst;
  433. ctx->nimages -= 2;
  434. }
  435. else if(!strcmp(cmd, "blit"))
  436. {
  437. pipi_image_t *dst;
  438. char const *arg;
  439. va_list ap;
  440. int x, y;
  441. if(ctx->nimages < 2)
  442. return -1;
  443. va_start(ap, cmd);
  444. arg = va_arg(ap, char const *);
  445. va_end(ap);
  446. x = atoi(arg);
  447. arg = strchr(arg, 'x');
  448. if(!arg)
  449. return -1;
  450. y = atoi(arg + 1);
  451. dst = pipi_blit(ctx->images[ctx->nimages - 2],
  452. ctx->images[ctx->nimages - 1], x, y);
  453. if(dst == NULL)
  454. return -1;
  455. pipi_free(ctx->images[ctx->nimages - 2]);
  456. pipi_free(ctx->images[ctx->nimages - 1]);
  457. ctx->images[ctx->nimages - 2] = dst;
  458. ctx->nimages--;
  459. }
  460. else if(!strcmp(cmd, "merge"))
  461. {
  462. pipi_image_t *dst;
  463. char const *arg;
  464. va_list ap;
  465. double val;
  466. if(ctx->nimages < 2)
  467. return -1;
  468. va_start(ap, cmd);
  469. arg = va_arg(ap, char const *);
  470. va_end(ap);
  471. val = atof(arg);
  472. dst = pipi_merge(ctx->images[ctx->nimages - 2],
  473. ctx->images[ctx->nimages - 1], val);
  474. if(dst == NULL)
  475. return -1;
  476. pipi_free(ctx->images[ctx->nimages - 2]);
  477. pipi_free(ctx->images[ctx->nimages - 1]);
  478. ctx->images[ctx->nimages - 2] = dst;
  479. ctx->nimages--;
  480. }
  481. else if(!strcmp(cmd, "mean") || !strcmp(cmd, "min") || !strcmp(cmd, "max")
  482. || !strcmp(cmd, "add") || !strcmp(cmd, "sub")
  483. || !strcmp(cmd, "difference") || !strcmp(cmd, "multiply")
  484. || !strcmp(cmd, "divide") || !strcmp(cmd, "screen")
  485. || !strcmp(cmd, "overlay"))
  486. {
  487. pipi_image_t *dst = NULL;
  488. if(ctx->nimages < 2)
  489. return -1;
  490. switch(cmd[2])
  491. {
  492. case 'a': dst = pipi_mean(ctx->images[ctx->nimages - 2],
  493. ctx->images[ctx->nimages - 1]);
  494. break;
  495. case 'n': dst = pipi_min(ctx->images[ctx->nimages - 2],
  496. ctx->images[ctx->nimages - 1]);
  497. break;
  498. case 'x': dst = pipi_max(ctx->images[ctx->nimages - 2],
  499. ctx->images[ctx->nimages - 1]);
  500. break;
  501. case 'd': dst = pipi_add(ctx->images[ctx->nimages - 2],
  502. ctx->images[ctx->nimages - 1]);
  503. break;
  504. case 'b': dst = pipi_sub(ctx->images[ctx->nimages - 2],
  505. ctx->images[ctx->nimages - 1]);
  506. break;
  507. case 'f': dst = pipi_difference(ctx->images[ctx->nimages - 2],
  508. ctx->images[ctx->nimages - 1]);
  509. break;
  510. case 'l': dst = pipi_multiply(ctx->images[ctx->nimages - 2],
  511. ctx->images[ctx->nimages - 1]);
  512. break;
  513. case 'v': dst = pipi_divide(ctx->images[ctx->nimages - 2],
  514. ctx->images[ctx->nimages - 1]);
  515. break;
  516. case 'r': dst = pipi_screen(ctx->images[ctx->nimages - 2],
  517. ctx->images[ctx->nimages - 1]);
  518. break;
  519. case 'e': dst = pipi_overlay(ctx->images[ctx->nimages - 2],
  520. ctx->images[ctx->nimages - 1]);
  521. break;
  522. }
  523. if(dst == NULL)
  524. return -1;
  525. pipi_free(ctx->images[ctx->nimages - 2]);
  526. pipi_free(ctx->images[ctx->nimages - 1]);
  527. ctx->images[ctx->nimages - 2] = dst;
  528. ctx->nimages--;
  529. }
  530. else if(!strcmp(cmd, "wrap"))
  531. {
  532. if(ctx->nimages < 1)
  533. return -1;
  534. ctx->images[ctx->nimages - 1]->wrap = 1;
  535. }
  536. else if(!strcmp(cmd, "autocontrast"))
  537. {
  538. pipi_image_t *tmp;
  539. if(ctx->nimages < 1)
  540. return -1;
  541. tmp = ctx->images[ctx->nimages - 1];
  542. ctx->images[ctx->nimages - 1] = pipi_autocontrast(tmp);
  543. pipi_free(tmp);
  544. }
  545. else if(!strcmp(cmd, "invert"))
  546. {
  547. pipi_image_t *tmp;
  548. if(ctx->nimages < 1)
  549. return -1;
  550. tmp = ctx->images[ctx->nimages - 1];
  551. ctx->images[ctx->nimages - 1] = pipi_invert(tmp);
  552. pipi_free(tmp);
  553. }
  554. else if(!strcmp(cmd, "dilate"))
  555. {
  556. pipi_image_t *tmp;
  557. if(ctx->nimages < 1)
  558. return -1;
  559. tmp = ctx->images[ctx->nimages - 1];
  560. ctx->images[ctx->nimages - 1] = pipi_dilate(tmp);
  561. pipi_free(tmp);
  562. }
  563. else if(!strcmp(cmd, "erode"))
  564. {
  565. pipi_image_t *tmp;
  566. if(ctx->nimages < 1)
  567. return -1;
  568. tmp = ctx->images[ctx->nimages - 1];
  569. ctx->images[ctx->nimages - 1] = pipi_erode(tmp);
  570. pipi_free(tmp);
  571. }
  572. else if(!strcmp(cmd, "gray"))
  573. {
  574. if(ctx->nimages < 1)
  575. return -1;
  576. pipi_get_pixels(ctx->images[ctx->nimages - 1], PIPI_PIXELS_Y_F32);
  577. }
  578. else if(!strcmp(cmd, "free"))
  579. {
  580. if(ctx->nimages < 1)
  581. return -1;
  582. ctx->nimages--;
  583. pipi_free(ctx->images[ctx->nimages]);
  584. }
  585. else if(!strcmp(cmd, "dup"))
  586. {
  587. if(ctx->nimages < 1)
  588. return -1;
  589. ctx->images[ctx->nimages] = pipi_copy(ctx->images[ctx->nimages - 1]);
  590. ctx->nimages++;
  591. }
  592. else if(!strcmp(cmd, "swap"))
  593. {
  594. pipi_image_t *tmp;
  595. if(ctx->nimages < 2)
  596. return -1;
  597. tmp = ctx->images[ctx->nimages - 1];
  598. ctx->images[ctx->nimages - 1] = ctx->images[ctx->nimages - 2];
  599. ctx->images[ctx->nimages - 2] = tmp;
  600. }
  601. else if(!strcmp(cmd, "roll"))
  602. {
  603. pipi_image_t *tmp;
  604. char const *arg;
  605. va_list ap;
  606. int val;
  607. va_start(ap, cmd);
  608. arg = va_arg(ap, char const *);
  609. va_end(ap);
  610. val = atoi(arg);
  611. if(val <= 0 || ctx->nimages < val)
  612. return -1;
  613. if(val == 1)
  614. return 0;
  615. tmp = ctx->images[ctx->nimages - val];
  616. memmove(ctx->images + ctx->nimages - val,
  617. ctx->images + ctx->nimages - val + 1,
  618. (val - 1) * sizeof(*ctx->images));
  619. ctx->images[ctx->nimages - 1] = tmp;
  620. }
  621. else if(!strcmp(cmd, "line"))
  622. {
  623. char const *arg;
  624. va_list ap;
  625. int x1, y1, x2, y2, aa = 0, ret;
  626. uint32_t color = 0;
  627. if(ctx->nimages < 1)
  628. return -1;
  629. va_start(ap, cmd);
  630. arg = va_arg(ap, char const *);
  631. va_end(ap);
  632. ret = sscanf(arg, "%d,%d,%d,%d,%08x,%d",
  633. &x1, &y1, &x2, &y2, &color, &aa);
  634. if(ret < 5) return -1;
  635. ctx->images[ctx->nimages] = pipi_copy(ctx->images[ctx->nimages - 1]);
  636. pipi_draw_line(ctx->images[ctx->nimages],
  637. x1, y1, x2, y2, color, aa);
  638. ctx->nimages++;
  639. }
  640. else if(!strcmp(cmd, "sine") || !strcmp(cmd, "wave"))
  641. {
  642. pipi_image_t *src, *dst = NULL;
  643. char const *arg;
  644. va_list ap;
  645. float dw, dh, d = 0.0, a = 0.0;
  646. int ret;
  647. if(ctx->nimages < 1)
  648. return -1;
  649. va_start(ap, cmd);
  650. arg = va_arg(ap, char const *);
  651. va_end(ap);
  652. ret = sscanf(arg, "%gx%g+%gr%g", &dw, &dh, &d, &a);
  653. if(ret < 2)
  654. return -1;
  655. src = ctx->images[ctx->nimages - 1];
  656. switch(cmd[0])
  657. {
  658. case 's': dst = pipi_sine(src, dw, dh, d, a); break;
  659. case 'w': dst = pipi_wave(src, dw, dh, d, a); break;
  660. }
  661. if(dst == NULL)
  662. return -1;
  663. pipi_free(src);
  664. ctx->images[ctx->nimages - 1] = dst;
  665. }
  666. else
  667. {
  668. return -1;
  669. }
  670. return 0;
  671. }