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.
 
 
 
 
 
 

691 lines
19 KiB

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