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

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