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.

img2txt.php 13 KiB

16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. <?php
  2. /*
  3. * img2txt image to text converter
  4. * Copyright (c) 2008 Benjamin C. Wiley Sittler <bsittler@gmail.com>
  5. *
  6. * This file is a Php port of "src/img2txt.c"
  7. * which is:
  8. * Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
  9. * 2007 Jean-Yves Lamoureux <jylam@lnxscene.org>
  10. * All Rights Reserved
  11. *
  12. * $Id$
  13. *
  14. * This program is free software. It comes without any warranty, to
  15. * the extent permitted by applicable law. You can redistribute it
  16. * and/or modify it under the terms of the Do What The Fuck You Want
  17. * To Public License, Version 2, as published by Sam Hocevar. See
  18. * http://sam.zoy.org/wtfpl/COPYING for more details.
  19. */
  20. $img2txt_php = isset($_SERVER['SCRIPT_NAME'])
  21. ?
  22. $_SERVER['SCRIPT_NAME']
  23. :
  24. 'img2txt.php';
  25. $argv = array(basename($img2txt_php));
  26. $file = isset($_FILES['file']) ? $_FILES['file']['tmp_name'] : NULL;
  27. $filename = isset($_FILES['file']) ? $_FILES['file']['name'] : NULL;
  28. $args = NULL;
  29. if(isset($_REQUEST['args']))
  30. {
  31. $args = trim($_REQUEST['args']);
  32. if(strlen($args))
  33. {
  34. foreach(explode(' ', $args) as $arg)
  35. {
  36. $argv[] = $arg;
  37. }
  38. }
  39. }
  40. $argc = count($argv);
  41. $stderr = '';
  42. $stdout = '';
  43. class MygetoptException extends Exception
  44. {
  45. }
  46. $myoptind = 0;
  47. function mygetopt($shortopts, $longopts)
  48. {
  49. global $argc, $argv, $myoptind;
  50. if($myoptind < 0)
  51. {
  52. $myoptind = 0;
  53. }
  54. if(($myoptind + 1) >= $argc)
  55. {
  56. return NULL;
  57. }
  58. $myoptind ++;
  59. $nextarg = $argv[$myoptind];
  60. $ret = NULL;
  61. if((substr($nextarg, 0, 1) != '-')
  62. ||
  63. ($nextarg == '-'))
  64. {
  65. $myoptind = $argc - 1;
  66. }
  67. else
  68. {
  69. $skipopt = $myoptind;
  70. $skipopts = 1;
  71. if($nextarg == '--')
  72. {
  73. $myoptind = $argc - 1;
  74. }
  75. else
  76. {
  77. $opt = NULL;
  78. $arg = NULL;
  79. foreach($longopts as $longopt)
  80. {
  81. $optional = false;
  82. $hasarg = false;
  83. if(($longopt != '::') && substr($longopt, -2) == '::')
  84. {
  85. $optional = true;
  86. $hasarg = true;
  87. $longopt = substr($longopt, 0, -2);
  88. }
  89. else if(($longopt != ':') && substr($longopt, -1) == ':')
  90. {
  91. $optional = false;
  92. $hasarg = true;
  93. $longopt = substr($longopt, 0, -1);
  94. }
  95. if($nextarg == ('--' . $longopt))
  96. {
  97. $opt = '--' . $longopt;
  98. if($hasarg && ! $optional)
  99. {
  100. if(($myoptind + 1) < $argc)
  101. {
  102. $myoptind ++;
  103. $skipopts ++;
  104. $arg = $argv[$myoptind];
  105. }
  106. else
  107. {
  108. throw new MygetoptException("option \"$opt\" requires an argument");
  109. }
  110. }
  111. break;
  112. }
  113. else if(substr($nextarg, 0, strlen('--' . $longopt . '='))
  114. ==
  115. ('--' . $longopt . '='))
  116. {
  117. $opt = '--' . $longopt;
  118. $arg = substr($nextarg, strlen($opt . '='));
  119. if(! $hasarg)
  120. {
  121. throw new MygetoptException("option \"$opt\" does not allow an argument");
  122. }
  123. break;
  124. }
  125. }
  126. if($opt === NULL)
  127. {
  128. for($i = 0; $i < strlen($shortopts); $i ++)
  129. {
  130. $optional = false;
  131. $hasarg = false;
  132. $shortopt = substr($shortopts, $i, 1);
  133. if(substr($shortopts, $i + 1, 2) == '::')
  134. {
  135. $optional = true;
  136. $hasarg = true;
  137. $i += 2;
  138. }
  139. else if(substr($shortopts, $i + 1, 1) == ':')
  140. {
  141. $hasarg = true;
  142. }
  143. if($nextarg
  144. ==
  145. ('-' . $shortopt))
  146. {
  147. $opt = '-' . $shortopt;
  148. if($hasarg && ! $optional)
  149. {
  150. if(($myoptind + 1) < $argc)
  151. {
  152. $myoptind ++;
  153. $skipopts ++;
  154. $arg = $argv[$myoptind];
  155. }
  156. else
  157. {
  158. throw new MygetoptException("option \"$opt\" requires an argument");
  159. }
  160. }
  161. break;
  162. }
  163. else if(substr($nextarg, 0, strlen('-' . $shortopt))
  164. ==
  165. ('-' . $shortopt))
  166. {
  167. $opt = '-' . $shortopt;
  168. if($hasarg)
  169. {
  170. $arg = substr($nextarg, strlen($opt));
  171. }
  172. else
  173. {
  174. $argv[$myoptind] = '-' . substr($nextarg, strlen($opt));
  175. $myoptind --;
  176. $skipopts = 0;
  177. }
  178. }
  179. }
  180. }
  181. if($opt === NULL)
  182. {
  183. if(substr($nextarg, 0, strlen('--')) == '--')
  184. {
  185. $longopt = substr($nextarg, strlen('--'));
  186. if(strpos($longopt, '=') !== false)
  187. {
  188. $longopt = substr($longopt, 0, strpos($longopt, '='));
  189. }
  190. throw new MygetoptException("option \"--$longopt\" is not recognized");
  191. }
  192. $shortopt = substr($nextarg, strlen('-'), 1);
  193. throw new MygetoptException("option \"-$shortopt\" is not recognized");
  194. }
  195. $ret = array($opt, $arg);
  196. }
  197. if ($skipopts > 0)
  198. {
  199. for($i = 0; $i < $argc; $i ++)
  200. {
  201. if(($i < $skipopt) || ($i >= ($skipopt + $skipopts)))
  202. {
  203. $new_argv[] = $argv[$i];
  204. }
  205. }
  206. if($myoptind >= $skipopt)
  207. {
  208. $myoptind -= $skipopts;
  209. }
  210. $argv = $new_argv;
  211. $argc = count($argv);
  212. }
  213. }
  214. return $ret;
  215. }
  216. function usage($argc, $argv)
  217. {
  218. global $stdout;
  219. $stdout .= sprintf("Usage: %s [OPTIONS]... <IMAGE>\n", $argv[0]);
  220. $stdout .= sprintf("Convert IMAGE to any text based available format.\n");
  221. $stdout .= sprintf("Example : -W 80 -f html logo-caca.png\n\n", $argv[0]);
  222. $stdout .= sprintf("Options:\n");
  223. $stdout .= sprintf(" -h, --help\t\t\tThis help\n");
  224. $stdout .= sprintf(" -v, --version\t\t\tVersion of the program\n");
  225. $stdout .= sprintf(" -W, --width=WIDTH\t\tWidth of resulting image\n");
  226. $stdout .= sprintf(" -H, --height=HEIGHT\t\tHeight of resulting image\n");
  227. $stdout .= sprintf(" -x, --font-width=WIDTH\t\tWidth of output font\n");
  228. $stdout .= sprintf(" -y, --font-height=HEIGHT\t\tHeight of output font\n");
  229. $stdout .= sprintf(" -b, --brightness=BRIGHTNESS\tBrightness of resulting image\n");
  230. $stdout .= sprintf(" -c, --contrast=CONTRAST\tContrast of resulting image\n");
  231. $stdout .= sprintf(" -g, --gamma=GAMMA\t\tGamma of resulting image\n");
  232. $stdout .= sprintf(" -d, --dither=DITHER\t\tDithering algorithm to use :\n");
  233. $list = caca_get_dither_algorithm_list(caca_create_dither(imagecreate(1, 1)));
  234. foreach($list as $type => $name)
  235. {
  236. $stdout .= sprintf("\t\t\t%s: %s\n", $type, $name);
  237. }
  238. $stdout .= sprintf(" -f, --format=FORMAT\t\tFormat of the resulting image :\n");
  239. $list = caca_get_export_list();
  240. foreach($list as $type => $name)
  241. {
  242. $stdout .= sprintf("\t\t\t%s: %s\n", $type, $name);
  243. }
  244. }
  245. function version()
  246. {
  247. global $stdout;
  248. $stdout .= sprintf(
  249. "img2txt Copyright 2006-2007 Sam Hocevar and Jean-Yves Lamoureux\n" .
  250. " Copyright 2008 Benjamin C. Wiley Sittler\n" .
  251. "Internet: <sam@zoy.org> <jylam@lnxscene.org> <bsittler@gmail.com> Version: %s\n" .
  252. "\n" .
  253. "img2txt, along with its documentation, may be freely copied and distributed.\n" .
  254. "\n" .
  255. "The latest version of img2txt is available from the web site,\n" .
  256. " http://caca.zoy.org/wiki/libcaca in the libcaca package.\n" .
  257. "\n",
  258. caca_get_version());
  259. }
  260. function main()
  261. {
  262. global $file, $filename;
  263. global $argc, $argv;
  264. global $stderr;
  265. $cols = 0;
  266. $lines = 0;
  267. $font_width = 6;
  268. $font_height = 10;
  269. $format = NULL;
  270. $dither = NULL;
  271. $gamma = $brightness = $contrast = -1.0;
  272. $long_options = array(
  273. "width:" => 'W',
  274. "height:" => 'H',
  275. "font-width:" => 'x',
  276. "font-height:" => 'y',
  277. "format:" => 'f',
  278. "dither:" => 'd',
  279. "gamma:" => 'g',
  280. "brightness:" => 'b',
  281. "contrast:" => 'c',
  282. "help" => 'h',
  283. "version" => 'v'
  284. );
  285. try {
  286. while($opt_and_arg = mygetopt("W:H:f:d:g:b:c:hvx:y:", array_keys($long_options)))
  287. {
  288. $opt = $opt_and_arg[0];
  289. $arg = $opt_and_arg[1];
  290. if((substr($opt, 0, 2) == '--')
  291. &&
  292. array_key_exists(substr($opt, strlen('--')) . (($arg !== NULL) ? ':' : ''), $long_options))
  293. {
  294. $opt = '-' . $long_options[substr($opt, strlen('--')) . (($arg !== NULL) ? ':' : '')];
  295. }
  296. switch($opt)
  297. {
  298. case '-W': /* --width */
  299. $cols = intval($arg);
  300. break;
  301. case '-H': /* --height */
  302. $lines = intval($arg);
  303. break;
  304. case '-x': /* --width */
  305. $font_width = intval($arg);
  306. break;
  307. case '-y': /* --height */
  308. $font_height = intval($arg);
  309. break;
  310. case '-f': /* --format */
  311. $format = $arg;
  312. break;
  313. case '-d': /* --dither */
  314. $dither = $arg;
  315. break;
  316. case '-g': /* --gamma */
  317. $gamma = floatval($arg);
  318. break;
  319. case '-b': /* --brightness */
  320. $brightness = floatval($arg);
  321. break;
  322. case '-c': /* --contrast */
  323. $contrast = floatval($arg);
  324. break;
  325. case '-h': /* --help */
  326. usage($argc, $argv);
  327. return 0;
  328. case '-v': /* --version */
  329. version();
  330. return 0;
  331. default:
  332. return 1;
  333. }
  334. }
  335. }
  336. catch (MygetoptException $e)
  337. {
  338. $stderr .= $argv[0] . ": " . $e->getMessage() . "\n";
  339. usage($argc, $argv);
  340. return 2;
  341. }
  342. if((! $file) && ($argc == 2) && ($argv[1] == 'logo-caca.png'))
  343. {
  344. $file = 'logo-caca.png';
  345. $argc = 1;
  346. }
  347. else if($filename && $file && ($argc == 2)
  348. &&
  349. (strtolower(basename($argv[1])) == strtolower(basename($filename))))
  350. {
  351. $argc = 1;
  352. }
  353. if($argc == 2)
  354. {
  355. $stderr .= sprintf("%s: image not found\n", $argv[1]);
  356. return 1;
  357. }
  358. if($argc > 2)
  359. {
  360. $stderr .= sprintf("%s: too many arguments\n", $argv[0]);
  361. usage($argc, $argv);
  362. return 1;
  363. }
  364. if(! $file)
  365. {
  366. $stderr .= sprintf("%s: no image was provided\n", $argv[0]);
  367. usage($argc, $argv);
  368. return 1;
  369. }
  370. $cv = caca_create_canvas(0, 0);
  371. if(!$cv)
  372. {
  373. $stderr .= sprintf("%s: unable to initialise libcaca\n", $argv[0]);
  374. return 1;
  375. }
  376. $i_str = $file ? file_get_contents($file) : NULL;
  377. $i = $i_str ? imagecreatefromstring($i_str) : NULL;
  378. if(!$i)
  379. {
  380. $stderr .= sprintf("%s: unable to load %s\n", $argv[0], $filename);
  381. return 1;
  382. }
  383. /* Assume a 6×10 font */
  384. if(!$cols && !$lines)
  385. {
  386. $cols = 60;
  387. $lines = $cols * imagesy($i) * $font_width / imagesx($i) / $font_height;
  388. }
  389. else if($cols && !$lines)
  390. {
  391. $lines = $cols * imagesy($i) * $font_width / imagesx($i) / $font_height;
  392. }
  393. else if(!$cols && $lines)
  394. {
  395. $cols = $lines * imagesx($i) * $font_height / imagesy($i) / $font_width;
  396. }
  397. caca_set_canvas_size($cv, $cols, $lines);
  398. caca_set_color_ansi($cv, CACA_DEFAULT, CACA_TRANSPARENT);
  399. caca_clear_canvas($cv);
  400. $i_dither = caca_create_dither($i);
  401. if(! caca_set_dither_algorithm($i_dither, $dither?$dither:"fstein"))
  402. {
  403. $stderr .= sprintf("%s: Can't dither image with algorithm '%s'\n", $argv[0], $dither?$dither:"fstein");
  404. return -1;
  405. }
  406. if($brightness!=-1) caca_set_dither_brightness ($i_dither, $brightness);
  407. if($contrast!=-1) caca_set_dither_contrast ($i_dither, $contrast);
  408. if($gamma!=-1) caca_set_dither_gamma ($i_dither, $gamma);
  409. caca_dither_bitmap($cv, 0, 0, $cols, $lines, $i_dither, $i);
  410. $format = $format ? $format : 'html';
  411. $export = caca_export_string($cv, $format);
  412. if(!$export)
  413. {
  414. $stderr .= sprintf("%s: Can't export to format '%s'\n", $argv[0], $format);
  415. return -1;
  416. }
  417. else
  418. {
  419. $content_type_map = array(
  420. 'ansi' => 'text/plain; charset=CP437',
  421. 'utf8' => 'text/plain; charset=UTF-8',
  422. 'utf8cr' => 'text/plain; charset=UTF-8',
  423. 'html' => 'text/html; charset=UTF-8',
  424. 'html3' => 'text/html; charset=UTF-8',
  425. 'bbfr' => 'text/plain; charset=UTF-8',
  426. 'irc' => 'text/plain; charset=UTF-8',
  427. 'ps' => 'application/postscript',
  428. 'svg' => 'image/svg+xml',
  429. 'tga' => 'image/x-targa'
  430. );
  431. $download_extension_map = array(
  432. 'caca' => 'caca',
  433. 'ansi' => 'txt',
  434. 'utf8' => 'txt',
  435. 'utf8cr' => 'txt',
  436. 'irc' => 'txt',
  437. 'tga' => 'tga'
  438. );
  439. $inline_extension_map = array(
  440. 'bbfr' => 'txt',
  441. 'ps' => 'ps',
  442. 'svg' => 'svg'
  443. );
  444. if (! array_key_exists($format, $content_type_map))
  445. $content_type = 'application/octet-stream';
  446. else
  447. $content_type = $content_type_map[$format];
  448. header('Content-Type: ' . $content_type);
  449. if (array_key_exists($format, $download_extension_map))
  450. header('Content-Disposition: attachment; filename=export.' . $download_extension_map[$format]);
  451. else if (array_key_exists($format, $inline_extension_map))
  452. header('Content-Disposition: inline; filename=export.' . $inline_extension_map[$format]);
  453. echo $export;
  454. }
  455. return 0;
  456. }
  457. $ret = 1;
  458. if(isset($_REQUEST['args']) || $file)
  459. {
  460. $ret = main();
  461. }
  462. if($ret || strlen($stdout) || strlen($stderr))
  463. {
  464. header('Content-Type: text/html; charset=UTF-8');
  465. ?>
  466. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  467. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  468. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  469. <head>
  470. <title>image to text converter</title>
  471. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  472. </head>
  473. <body>
  474. <form id="img2txtform" name="img2txtform" action="#" enctype="multipart/form-data" method="post">
  475. <label for="file">Image:</label>
  476. <input id="file" name="file" type="file" />
  477. <br />
  478. <label for="args">Options:</label>
  479. <input id="args" name="args" type="text" value="<?= isset($_REQUEST['args']) ? htmlspecialchars($_REQUEST['args']) : '' ?>" size="80" />
  480. <br />
  481. <input type="submit" /> <input type="reset" />
  482. </form>
  483. <?php
  484. ;
  485. if(strlen($stderr))
  486. {
  487. ?><pre xml:space="preserve"><strong><?= htmlspecialchars($stderr) ?></strong></pre><?php
  488. ;
  489. }
  490. if(strlen($stdout))
  491. {
  492. ?><pre xml:space="preserve"><?= preg_replace('!([&]lt;)([.a-zA-Z0-9]+[@])([-.a-zA-Z0-9]+)([&]gt;)!', '$1<a href="mailto:$2$3">$2...</a>$4', preg_replace('!(\s|^)(https?://[-.:_/0-9a-zA-Z%?=&;#]+)(\s|$)!', '$1<a href="$2">$2</a>$3', htmlspecialchars($stdout))) ?></pre><?php
  493. ;
  494. }
  495. ?>
  496. </body>
  497. </html>
  498. <?php
  499. ;
  500. }
  501. ?>