Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

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