dev-guide.xml 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  1. <?xml version='1.0' encoding='UTF-8'?>
  2. <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V2.0//EN"
  3. "http://forrest.apache.org/dtd/document-v20.dtd">
  4. <!--
  5. Copyright (c) 2010-2010 by Bernhard Bablok (bablokb@users.sourceforge.net)
  6. $Revision: 1.23 $
  7. $Author: bablokb $
  8. -->
  9. <document id="devguide">
  10. <header>
  11. <title>Developer's Guide</title>
  12. </header>
  13. <body>
  14. <section id="intro">
  15. <title>Introduction</title>
  16. <p>
  17. This guide is an introduction to the im4java-library. You
  18. should be familiar with java-programming and should know how
  19. to read the <a href="ext:im4javaapi">API
  20. documentation</a>. Also, this is no guide for the usage of
  21. the underlying tools (<a
  22. href="ext:imagemagick">ImageMagick</a>, <a
  23. href="ext:graphicsmagick">GraphicsMagick</a> and so on). You
  24. should be familiar with them and know how to read the
  25. respective documentation.
  26. </p>
  27. <p>
  28. The basic architecture of im4java is quite simple. It boils
  29. down to calling all underlying tools simply by using a
  30. <code>ProcessBuilder</code>-object. All the magic of im4java ist
  31. to hide the complexities. If you have just one simple call of
  32. an external tool in your program, you might be better of by
  33. hardcoding the <code>ProcessBuilder</code>-call yourself. If you
  34. don't need the simplicity or the advanced features of the
  35. im4java-library, your code will certainly be faster and more
  36. efficient.
  37. </p>
  38. </section>
  39. <section id="environment">
  40. <title>Before you begin: Setting up the Environment</title>
  41. <p>
  42. To use the im4java-library, you should add the im4java-jarfile
  43. to you classpath. This is the first part of the setup. The
  44. second part is optional and only necessary, if the <a
  45. href="../tools/index.html">tools</a> you want to use
  46. (e.g. <code>convert</code> or <code>exiftool</code>) are not
  47. on your <em>PATH</em>. This is typically a problem on
  48. Windows-systems.
  49. </p>
  50. <p>
  51. To setup your searchpath for the tools you have three options:
  52. </p>
  53. <ul>
  54. <li>
  55. Set the environment-variable
  56. <em>IM4JAVA_TOOLPATH</em>. This variable should contain a
  57. list of directories to search for your tools separated by
  58. your platform-pathdelemiter (on *NIX typically ":", on
  59. Windows ";").
  60. </li>
  61. <li>
  62. Globally set the searchpath from within your java-progam:
  63. <source>
  64. String myPath="C:\\Programs\\ImageMagick;C:\\Programs\\exiftool";
  65. ProcessStarter.setGlobalSearchPath(myPath);
  66. </source>
  67. This will override any values set with
  68. <em>IM4JAVA_TOOLPATH</em>.
  69. </li>
  70. <li>
  71. Set the search path for an individual command:
  72. <source>
  73. String imPath="C:\\Programs\\ImageMagick";
  74. ConvertCmd cmd = new ConvertCmd();
  75. cmd.setSearchPath(imPath);
  76. </source>
  77. This will override any values set with
  78. <em>IM4JAVA_TOOLPATH</em> or with
  79. <code>ProcessStarter.setGlobalSearchPath()</code>.
  80. </li>
  81. </ul>
  82. <warning>
  83. Note that I also encountered a problem using OpenJDK with a
  84. language-setting of <em>LANG=de_DE.UTF-8</em>. With
  85. <em>LANG=C</em> everything worked fine. With SUN's JDK, there
  86. were no problems regardless of the language-setting.
  87. </warning>
  88. </section>
  89. <section id="simpleUse">
  90. <title>Simple Use</title>
  91. <p>
  92. Basically, to use im4java, you need objects of two classes: an
  93. <code>ImageCommand</code> like <code>ConvertCmd</code>, and an
  94. <code>Operation</code> like <code>IMOperation</code>. The
  95. <code>ImageCommand</code> is more or less static, you would
  96. create an instance once and reuse it for the lifetime of your
  97. program. Exceptions to this rule are more advanced use
  98. cases, see the section below about parallel processing. In
  99. contrast, the <em>Operation</em> is the object
  100. wrapping all the commandline options you intend to pass to the
  101. given command. So you would typically create one
  102. <code>Operation</code> for every action (resizing, conversion)
  103. you intend to do.
  104. </p>
  105. <p>
  106. As an example, consider resizing an image:
  107. </p>
  108. <source>
  109. // create command
  110. ConvertCmd cmd = new ConvertCmd();
  111. // create the operation, add images and operators/options
  112. IMOperation op = new IMOperation();
  113. op.addImage("myimage.jpg");
  114. op.resize(800,600);
  115. op.addImage("myimage_small.jpg");
  116. // execute the operation
  117. cmd.run(op);
  118. </source>
  119. </section>
  120. <section id="imageCommands">
  121. <title>About ImageCommand</title>
  122. <p>
  123. All command-classes subclass <code>ImageCommand</code>, which
  124. itself subclasses
  125. <code>org.im4java.process.ProcessStarter</code>. The latter
  126. class wraps <code>java.lang.ProcessBuilder</code>, handles
  127. input and output streams and supports <a
  128. href="#asynchronousExecution">asynchronous execution</a>.
  129. </p>
  130. <p>
  131. The <code>ImageCommand</code> class adds methods useful for
  132. all command-classes, things like support for <a
  133. href="#reusingOperations">reusing operations</a> or for <a
  134. href="#dynamicOperations">dynamic operations</a>.
  135. </p>
  136. <p>
  137. Note that <code>ImageCommand</code> is not stateless. In the
  138. default setting, it captures everything written to stderr. It
  139. also holds an internal <em>process ID</em> (unrelated to any
  140. operating system PID) via
  141. <code>ProcessStarter</code>. Nevertheless, if you only use the
  142. <code>ImageCommand</code> in synchronous mode, you can reuse
  143. the instance.
  144. </p>
  145. </section>
  146. <section id="graphicsMagick">
  147. <title>Using GraphicsMagick</title>
  148. <p>
  149. <a href="ext:graphicsmagick">GraphicsMagick</a> is a fork of
  150. <a href="ext:imagemagick">ImageMagick</a>. GraphicsMagick has
  151. a number of advantages compared to ImageMagick, the most
  152. prominent is it's superior performance. Since the fork
  153. ImageMagick has improved the expressive power of it's
  154. command-line syntax, therefore, an ImageMagick commandline is
  155. not necessarely compatible with GraphicsMagick. But for most
  156. single-operation conversions it still is.
  157. </p>
  158. <p>
  159. With im4java, you have three options if you want to use
  160. GraphicsMagick:
  161. </p>
  162. <ul>
  163. <li>
  164. use GraphicsMagick explicitely, passing the command at
  165. object-creation: <code>GraphicsMagickCmd cmd = new
  166. GraphicsMagickCmd("convert");</code>.
  167. </li>
  168. <li>
  169. use GraphicsMagick explicitely, using wrapper classes:
  170. <code>ConvertCmd cmd = new ConvertCmd(true);</code>.
  171. </li>
  172. <li>
  173. decide at runtime: setting the system-property
  174. <em>im4java.useGM</em> to true will select GraphicsMagick
  175. at runtime. You can use this feature to compare the
  176. results and timings of both toolsets, provided that the
  177. commandline is compatible.
  178. </li>
  179. </ul>
  180. </section>
  181. <section id="reusingOperations">
  182. <title>Reusing Operations</title>
  183. <p>
  184. In the example <a href="#simpleUse">above</a>, image-names
  185. were hard-coded. The
  186. im4java-library supports an alternative use. Instead of
  187. hard-coding the image-names, you just add placeholders and
  188. resolve the image-names at execution time. This allows the
  189. reuse of operations for example within a loop.
  190. </p>
  191. <p>
  192. The following example extends the example of the first section
  193. and loops over all images passed as method parameters:
  194. </p>
  195. <source>
  196. public void resizeImages(String... pImageNames) {
  197. // create command
  198. ConvertCmd cmd = new ConvertCmd();
  199. // create the operation, add images and operators/options
  200. IMOperation op = new IMOperation();
  201. op.addImage();
  202. op.resize(800,600);
  203. op.addImage();
  204. for (String srcImage:pImageNames) {
  205. int lastDot = srcImage.lastIndexOf('.');
  206. String dstImage =
  207. srcImage.substring(1,lastDot-1)+"_small.jpg";
  208. cmd.run(op,srcImage,dstImage);
  209. }
  210. }
  211. </source>
  212. <p>
  213. You can pass an arbitrary
  214. number of image-names to <code>cmd.run()</code>, you can even
  215. pass an array of image-names. In the latter case you have to
  216. cast the array to <code>Object[]</code>,
  217. e.g. <code>cmd.run(op,(Object[]) imgNames)</code>.
  218. </p>
  219. <p>
  220. Note that <code>op.addImage()</code> is actually a short form
  221. for <code>op.addImage(Operation.IMG_PLACEHOLDER)</code>. You
  222. can also add more than one placeholder at the same time with
  223. <code>op.addImage(int count)</code>.
  224. </p>
  225. <p>
  226. The <code>op.addImage(String... images)</code>-method also
  227. supports ImageMagick's <em>read-modifiers</em>. Adding a
  228. read-modifier for hard-coded images is of course
  229. straightforward (you just add it to the argument string). For
  230. placeholders, you add only the read-modifier. The following
  231. two lines of code therefore have the same effect:
  232. </p>
  233. <source>
  234. op.addImage("[300x200]");
  235. op.addImage(Operation.IMG_PLACEHOLDER+"[300x200]");
  236. </source>
  237. <p>
  238. The test-case class <code>org.im4java.test.TestCase7</code>
  239. uses read-modifiers to crop the source-images prior to
  240. composing them:
  241. </p>
  242. <source>
  243. IMOperation op = new IMOperation();
  244. op.blend(50);
  245. op.addImage("[300x200+0+0]"); // read and crop first image
  246. op.addImage("[300x200+0+0]"); // read and crop second image
  247. op.addImage(); // output image
  248. CompositeCmd composite = new CompositeCmd();
  249. composite.run(op,"rose1.jpg","rose2.jpg",outfile);
  250. </source>
  251. </section>
  252. <section id="AddingOperations">
  253. <title>Adding Operations to Operations</title>
  254. <p>
  255. Im4java supports a second variant of operation-reuse. You can
  256. define one <code>Operation</code> and just add it to another
  257. one. The following snippet defines a
  258. <em>rotate-resize-frame</em>-operation and adds it to another
  259. operation:
  260. </p>
  261. <source>
  262. IMOperation frame = new IMOperation();
  263. frame.rotate("90");
  264. frame.resize(640);
  265. frame.border(10,10);
  266. IMOperation row = new IMOperation();
  267. row.addImages(3);
  268. row.add(frame);
  269. row.p_append();
  270. </source>
  271. <p>
  272. Adding operations as just described is valid for all
  273. supported im4java-tools. <a
  274. href="ext:imagemagick">ImageMagick</a> additionally supports
  275. options and operations within parenthesis thus limiting the
  276. effect of settings and operators on everything within the
  277. parenthesis. You add parenthesis with the methods
  278. <code>op.openOperation()</code> and
  279. <code>op.closeOperation()</code>:
  280. </p>
  281. <source>
  282. IMOperation frame = new IMOperation();
  283. frame.openOperation();
  284. frame.rotate("90");
  285. frame.resize(640);
  286. frame.border(10,10);
  287. frame.closeOperation();
  288. </source>
  289. <p>
  290. An alternatative way of coding this is:
  291. </p>
  292. <source>
  293. IMOperation frame = new IMOperation();
  294. frame.rotate("90");
  295. frame.resize(640);
  296. frame.border(10,10);
  297. IMOperation row = new IMOperation();
  298. row.addImages(3);
  299. row.addSubOperation(frame);
  300. row.p_append();
  301. </source>
  302. <p>
  303. The <code>op.addSubOperation()</code>-method just adds the
  304. surrounding parenthesis.
  305. </p>
  306. </section>
  307. <section id="dynamicOperations">
  308. <title>Dynamic Operations</title>
  309. <p>
  310. <em>Dynamic Operations</em> are an advanced
  311. technique. Sometimes you only want to apply some operations to
  312. images fulfilling some requirements. <a
  313. href="ext:imagemagick">ImageMagick</a> itself has some
  314. special option-flags for this purpose, e.g. an image is only
  315. scaled (down) if it has a larger size than the
  316. target-size. For special cases not directly supported by
  317. ImageMagick, you can make use of im4java's <em>Dynamic
  318. Operations</em>. Basically, you implement the interface
  319. <code>org.im4java.core.DynamicOperation</code>, which has
  320. exactly one method <em>resolveOperation()</em>. At execution
  321. time, this method gets all argument images passed as
  322. parameters, and it must return an <code>Operation</code>. The
  323. returned object could also be <em>null</em>, in this case no
  324. <code>Operation</code> is added.
  325. </p>
  326. <p>
  327. The test-case class <code>org.im4java.test.TestCase11</code>
  328. shows an example of dynamic operations. In this case, the
  329. <code>despeckle()</code> method is only added for images with
  330. a high iso-noise level.
  331. </p>
  332. </section>
  333. <section id="capturingOutput">
  334. <title>Capturing Output</title>
  335. <p>
  336. The default behaviour of all <code>ImageCommand</code>s is to
  337. pass all output of the wrapped commands to stdout, and to
  338. capture everything from stderr in an
  339. <code>CommandException</code>-object. You can change this
  340. behaviour with the methods
  341. <code>ImageCommand.setOutputConsumer(OutputConsumer oc)</code>
  342. and <code>ImageCommand.setErrorConsumer(ErrorConsumer
  343. ec)</code>. Both <code>OutputConsumer</code> and
  344. <code>ErrorConsumer</code> are interfaces in the
  345. <code>org.im4java.process</code>-package with single methods
  346. (<code>consumeOutput()</code> and
  347. <code>consumeError()</code>). These methods just read
  348. everything from the argument <code>InputStream</code>.
  349. </p>
  350. <p>
  351. In the process-package there is an utility-class called
  352. <code>ArrayListOutputConsumer</code> which collects all lines
  353. of output in a String-array.
  354. </p>
  355. </section>
  356. <section id="piping">
  357. <title>Piping</title>
  358. <p>
  359. Most commandline tools allow piping of input or output. With
  360. the im4java-library you can create instances of
  361. <code>org.im4java.process.Pipe</code> to mimic this
  362. behaviour. This class implements the
  363. <code>OutputConsumer</code> and
  364. <code>ErrorConsumer</code>-interfaces mentioned above and are
  365. useful for
  366. piping the output of a commandline tool to an
  367. <code>OutputStream</code> (e.g. a network-socket). To use the
  368. pipe, instantiate it with an <code>OutputStream</code> and use
  369. the method <code>ImageCommand.setOutputConsumer(pipe)</code>.
  370. </p>
  371. <p>
  372. If you want to provide input to stdin of a commandline tool,
  373. you have to create a pipe-object initialized with an
  374. <code>InputStream</code> and use the method
  375. <code>ImageCommand.setInputProvider(pipe)</code>. The pipe
  376. will read from the <code>InputStream</code> and write to the
  377. stdin of the respective <code>ImageCommand</code>.
  378. </p>
  379. <p>
  380. The test-case <code>org.im4java.test.TestCase10</code>
  381. features pipes, reading from one image and writing to
  382. another. In real-life, you would of course process the files
  383. directly, but the example just wants to demonstrate what to do:
  384. </p>
  385. <source>
  386. IMOperation op = new IMOperation();
  387. op.addImage("-"); // read from stdin
  388. op.addImage("tif:-"); // write to stdout in tif-format
  389. // set up pipe(s): you can use one or two pipe objects
  390. FileInputStream fis = new FileInputStream(iImageDir+"ipomoea.jpg");
  391. FileOutputStream fos = new FileOutputStream(iImageDir+"ipomoea.tif");
  392. // Pipe pipe = new Pipe(fis,fos);
  393. Pipe pipeIn = new Pipe(fis,null);
  394. Pipe pipeOut = new Pipe(null,fos);
  395. // set up command
  396. ConvertCmd convert = new ConvertCmd();
  397. convert.setInputProvider(pipeIn);
  398. convert.setOutputConsumer(pipeOut);
  399. convert.run(op);
  400. fis.close();
  401. fos.close();
  402. </source>
  403. </section>
  404. <section id="bufferedImages">
  405. <title>Using BufferedImages</title>
  406. <p>
  407. A <code>BufferedImage</code> is in a way the <em>java
  408. native</em> representation of an image-object. No
  409. commandline tool can deal directly with a
  410. <code>BufferedImage</code>. The good news is that im4java uses
  411. objects of type <code>BufferedImage</code> transparently, if
  412. you use pass these objects at invocation time:
  413. </p>
  414. <source>
  415. IMOperation op = new IMOperation();
  416. op.addImage(); // input
  417. op.blur(2.0).paint(10.0);
  418. op.addImage(); // output
  419. ConvertCmd convert = new ConvertCmd();
  420. BufferedImage img = ...;
  421. String outfile = ...;
  422. ...
  423. convert.run(op,img,outfile);
  424. </source>
  425. <p>
  426. Note that the above use of <code>BufferedImage</code>s
  427. works fine for input-images.
  428. If you need to write to a <code>BufferedImage</code>, you must
  429. pipe the output of the commandline-tool to stdout,
  430. create an instance of the class
  431. <code>org.im4java.core.Stream2BufferedImage</code> and set it
  432. as the <code>OutputConsumer</code> of the command:
  433. </p>
  434. <source>
  435. IMOperation op = new IMOperation();
  436. op.addImage(); // input
  437. ....
  438. op.addImage("png:-"); // output: stdout
  439. ...
  440. images = ...;
  441. // set up command
  442. ConvertCmd convert = new ConvertCmd();
  443. Stream2BufferedImage s2b = new Stream2BufferedImage();
  444. convert.setOutputConsumer(s2b);
  445. // run command and extract BufferedImage from OutputConsumer
  446. convert.run(op,(Object[]) images);
  447. BufferedImage img = s2b.getImage();
  448. </source>
  449. </section>
  450. <section id="asynchronousExecution">
  451. <title>Asynchronous Execution</title>
  452. <p>
  453. Long running operations belong into a seperate thread,
  454. especially in graphical applications. The im4java-library
  455. supports asynchronous execution with and without callbacks.
  456. </p>
  457. <p>
  458. The latter case is simple (fire-and-forget). Befor you start the
  459. command, you just set the aynchronous-mode to true:
  460. </p>
  461. <source>
  462. ConvertCmd cmd = new ConvertCmd();
  463. cmd.setAsyncMode(true);
  464. ...
  465. cmd.run(op);
  466. </source>
  467. <p>
  468. In this case, you will know nothing about success or
  469. failure. If you need feedback (e.g. because you want to
  470. asynchronously convert a file and load the result into a
  471. window), you must write a class implementing the interface
  472. <code>org.im4java.process.ProcessEventListener</code>. This
  473. interface defines three methods:
  474. <code>processInitiated()</code>, <code>processStarted()</code>
  475. and <code>processTerminated()</code>. The first method is
  476. called synchronously from the original thread calling the
  477. run-method, the latter two methods are callbacks from the
  478. asynchronous thread. See
  479. <code>org.im4java.test.TestCase16</code> for a complete example.
  480. </p>
  481. <p>
  482. With <code>cmd.setAsyncMode(true)</code> you only need minimal
  483. code-changes for asynchronous execution. If you prefer to
  484. control the flow of execution yourself, you could use some
  485. standard methods from <code>java.util.concurrent</code> to
  486. control execution:
  487. </p>
  488. <source>
  489. ProcessTask pt = cmd.getProcessTask(op);
  490. ExecutorService exec = Executors.newSingleThreadExecutor();
  491. exec.execute(pt);
  492. exec.shutdown();
  493. </source>
  494. <p>
  495. The test-case 16a will give you a complete example. The third
  496. variant, test-case 16b replaces the standard executor returned
  497. by <code>Executors.newSingleThreadExecutor()</code> with an
  498. instance of class
  499. <code>org.im4java.process.ProcessExecutor</code>. For a
  500. discussion of this class, proceed to the next section.
  501. </p>
  502. </section>
  503. <section id="parallelProcessing">
  504. <title>Parallel Processing</title>
  505. <p>
  506. The use case described above is fine for typical graphical
  507. applications with one asynchronous thread. In contrast, if you
  508. want to convert a number of files asynchronously, additional
  509. problems arise. Consider the following piece of code:
  510. </p>
  511. <source>
  512. // load images into an array, e.g. from a directoy
  513. ArrayList&lt;String&gt; images = load(myDir);
  514. // convert all images
  515. ConvertCmd cmd = new ConvertCmd();
  516. cmd.setAsyncMode(true);
  517. Operation op = ...;
  518. for (String img:images) {
  519. String outfile = ...;
  520. cmd.run(op,img,outfile);
  521. }
  522. </source>
  523. <p>
  524. Although this will run perfectly fine, this code will flood
  525. your system with parallel convert-processes, making your
  526. system unusable for a while. So one of the issues is
  527. <em>ressource management</em>. Another issue is that you don't
  528. know when you are finished. In addition, you don't know which
  529. of your conversions succeeded and which failed.
  530. </p>
  531. <p>
  532. The following sections deal with these three issues. This is
  533. advanced stuff, and you might not even need it. If you have to
  534. convert multiple images, you could first try to use the class
  535. <code>org.im4java.utils.BatchConverter</code>, which uses the
  536. building blocks described below. The class
  537. <code>BatchConverter</code> is covered <a
  538. href="#BatchConverter">here</a>.
  539. </p>
  540. <section id="processExecutor">
  541. <title>The ProcessExecutor</title>
  542. <p>
  543. The classes in <code>java.util.concurrent</code> address
  544. these issues. All classes returned by the factory class
  545. <code>java.util.concurrent.Executors</code> operate on
  546. threads. They provide methods to queue and start requests up
  547. to a given limit, and also allow you to stop the queue and
  548. destroy running threads.
  549. </p>
  550. <p>
  551. There is one big drawback with these thread-based
  552. executors. Once an <code>ImageCommand</code> is running
  553. within a java-thread, the thread will not be killable due to
  554. the active process. Therefore you should not use any of the
  555. standard executors, but use an instance of the class
  556. <code>org.im4java.process.ProcessExecutor</code>. A basic
  557. usage is very simple, the example above then looks like
  558. this:
  559. </p>
  560. <source>
  561. // load images into an array, e.g. from a directoy
  562. ArrayList&lt;String&gt; images = load(myDir);
  563. // convert all images
  564. ProcessExecutor exec = new ProcessExecutor();
  565. Operation op = ...;
  566. for (String img:images) {
  567. String outfile = ...;
  568. ConvertCmd cmd = new ConvertCmd();
  569. ProcessTask pt = cmd.getProcessTask(op,img,outfile);
  570. exec.execute(pt);
  571. }
  572. exec.shutdown();
  573. </source>
  574. <p>
  575. The default constructor of <code>ProcessExecutor</code> will
  576. query the number of processors on the system and limit the
  577. number of parallel running processes to that number. You can
  578. also pass an integer to the constructor if you want to set
  579. the limit yourself.
  580. </p>
  581. <p>
  582. The class <code>ProcessTask</code> extends
  583. <code>java.util.concurrent.FutureTask</code>. You can use
  584. all the standard methods of this class, e.g. to query
  585. results or to wait for termination.
  586. </p>
  587. </section>
  588. <section id="processTermination">
  589. <title>Waiting for process termination</title>
  590. <p>
  591. It is usually important to know when your processes have
  592. finished, maybe to give feedback to a user by updating a
  593. progress bar or to start some follow-up activity. If the
  594. processes take too long, you might also consider killing
  595. them.
  596. </p>
  597. <p>
  598. Since <code>ProcessExecutor</code> extends
  599. <code>java.util.concurrent.ThreadPoolExecutor</code>, you
  600. can use the standard methods provided by this class. If you
  601. want to block until your processes terminate, you would use
  602. the following code snippet (this one extends the example above):
  603. </p>
  604. <source>
  605. ProcessExecutor exec = new ProcessExecutor();
  606. for (String img:images) {
  607. ...
  608. }
  609. exec.shutdown();
  610. if (exec.awaitTermination(10,TimeUnit.SECONDS)) {
  611. System.err.println("processes terminated on their own");
  612. } else {
  613. System.err.println("trying to cancel all running processes ...");
  614. exec.shutdownNow();
  615. }
  616. </source>
  617. <p>
  618. As an alternative to the blocking
  619. <code>awaitTermination()</code>-call you could also subclass
  620. <code>ProcessExecutor</code> and implement it's
  621. <code>terminated()</code>-method. Then you will receive a
  622. callback once all processes have terminated.
  623. </p>
  624. <p>
  625. One final warning: the code implementing the parallel
  626. processing of commands is new and therefore untested in the
  627. wild. During development, a number of race-conditions came
  628. up (and were solved), but feedback on stability,
  629. functionality and implementation is highly welcome.
  630. </p>
  631. </section>
  632. <section id="processControl">
  633. <title>Exit status of finished asynchronous processes</title>
  634. <p>
  635. The last issue with asynchronous processes is the exit
  636. status. For a single asynchronous process this is quite
  637. simple, you would implement a
  638. <code>ProcessEventListener</code> and use it's
  639. <code>processTerminated()</code>-method (see the section <a
  640. href="#asynchronousExecution">Asynchronous Execution</a> above).
  641. </p>
  642. <p>
  643. For multiple parallel process the situation is a bit more
  644. complicated. You have to link the processTerminated-event
  645. with the correct process. The class
  646. <code>ProcessEvent</code> implements a number of methods
  647. which help to identify the process. One is
  648. <code>ProcessEvent.getPID()</code>. The <em>PID</em> is an
  649. internal field of each <code>ImageCommand</code>. You can
  650. set this field explicitly overriding the PID set during
  651. object-creation. You can also query the
  652. <code>ImageCommand</code> object itself with
  653. <code>ProcessEvent.getProcessStarter()</code> (remenber that
  654. <code>ProcessStarter</code> is the base-class of
  655. <code>ImageCommand</code>).
  656. </p>
  657. <p>
  658. For a complete example using these methods, see the class
  659. <code>org.im4java.test.TestCase21</code>.
  660. </p>
  661. </section>
  662. </section>
  663. <section id="utils">
  664. <title>Utilities</title>
  665. <p>
  666. This section describes a number of utility-classes which
  667. facilitate the coding.
  668. </p>
  669. <section id="Info">
  670. <title>Image Information</title>
  671. <p>
  672. If you only want to query image-information (e.g. width and
  673. height), you could typically use the class
  674. <code>IdentifyCmd</code>, wrapping ImageMagick's
  675. <em>identify</em>-command. Instead of using this class
  676. directly, you could instead use the <code>Info</code> class. The
  677. following code-snippet demonstrates its use:
  678. </p>
  679. <source>
  680. Info imageInfo = new Info(filename,true);
  681. System.out.println("Format: " + imageInfo.getImageFormat());
  682. System.out.println("Width: " + imageInfo.getImageWidth());
  683. System.out.println("Height: " + imageInfo.getImageHeight());
  684. System.out.println("Geometry: " + imageInfo.getImageGeometry());
  685. System.out.println("Depth: " + imageInfo.getImageDepth());
  686. System.out.println("Class: " + imageInfo.getImageClass());
  687. </source>
  688. <p>
  689. The second parameter (<em>true</em>) in the example requests
  690. <em>basic</em>-information. This is a bit faster than
  691. requesting and parsing the
  692. complete (verbose) output of the class
  693. <code>IndentifyCmd</code>. See the test-case class
  694. <code>org.im4java.test.TestCase8</code> for a complete example.
  695. </p>
  696. <p>
  697. Prior to version 1.3.0 the implementation of the
  698. <code>Info</code>-class was severely flawed. It did not take
  699. into account that there are image-formats like TIF or GIF
  700. that support multiple images (ImageMagick calls them
  701. <em>scenes</em>) within a single file. As a consequence, the
  702. method
  703. </p>
  704. <source>
  705. imageInfo.getImageWidth()
  706. </source>
  707. <p>
  708. returns the image-width of the <em>first</em> scene (from
  709. basic-information), whereas the method
  710. </p>
  711. <source>
  712. imageInfo.getProperty("Width")
  713. </source>
  714. <p>
  715. will return the image-width of the <em>last</em>
  716. scene (from complete information). Starting with version
  717. 1.3.0, there are new methods with an additional parameter,
  718. the scene-number, e.g.
  719. </p>
  720. <source>
  721. imageInfo.getImageWidth(3)
  722. imageInfo.getProperty("Width",3)
  723. </source>
  724. <p>
  725. To query the number of scenes use the method
  726. <code>getSceneCount()</code>. Note that information about
  727. multiple scenes is only available with complete-information.
  728. </p>
  729. <p>
  730. Note that parsing the output of <code>identify
  731. -verbose</code> is inherently flawed, since this output is
  732. meant to be human-readable and not an an interface for computer
  733. programs. The parser makes a number of assumptions about the
  734. output, some of them are known to be incorrect in special
  735. situations (e.g. multi-line attribute-values with embedded
  736. colons). Also note that basic-information should always be
  737. correct, since it uses a different method to aquire the
  738. information. As an alternative to the
  739. <code>Info</code>-class you might consider using the wrapper
  740. class <code>ExiftoolCmd</code> for <code>exiftool</code>.
  741. </p>
  742. </section>
  743. <section id="FilenameLoader">
  744. <title>FilenameLoader</title>
  745. <p>
  746. The class <code>org.im4java.utils.FilenameLoader</code> is
  747. useful for batch-processing a number of files from a
  748. directory. The core method is <code> public
  749. List&lt;String&gt; loadFilenames(String pDir)</code>. It
  750. loads all files from the given directory into a list of
  751. strings.
  752. </p>
  753. <p>
  754. The constructor accepts an <code>ExtensionFilter</code>. You
  755. can instantiate your own filter as in the example below or
  756. use one of the predefined filters of the
  757. ExtensionFilter-class.
  758. </p>
  759. <source>
  760. ExtensionFilter filter = new ExtensionFilter("jpg");
  761. filter.setRecursion(true);
  762. filter.ignoreDotDirs(true);
  763. FilenameLoader loader = new FilenameLoader(filter);
  764. List&lt;String&gt; files = loader.loadFilenames(mydir);
  765. </source>
  766. <p>
  767. As always, you should check the <a
  768. href="ext:im4javaapi">API-documentation</a> for all the
  769. features of this class.
  770. </p>
  771. </section>
  772. <section id="FilenamePatternResolver">
  773. <title>FilenamePatternResolver</title>
  774. <p>
  775. When converting multiple files, the target filename usually
  776. depends on the source filename. For example a standard
  777. conversion from jpg to tif would keep the filename and just
  778. change the extension. Or all converted files should
  779. additionally go to a separate directory.
  780. </p>
  781. <p>
  782. This is where the class
  783. <code>org.im4java.utils.FilenamePatternResolver</code> is
  784. useful. The following snippet will convert all
  785. argument-files to tif.
  786. </p>
  787. <source>
  788. // define operation and command
  789. IMOperation op = new IMOperation();
  790. op.addImage(); // input-file
  791. op.addImage(); // output-file
  792. ConvertCmd cmd = new ConvertCmd();
  793. // load files
  794. ExtensionFilter filter = new ExtensionFilter("jpg");
  795. FilenameLoader loader = new FilenameLoader(filter);
  796. List&lt;String&gt; files = loader.loadFilenames(mydir);
  797. // create the resolver
  798. FilenamePatternResolver resolver =
  799. new FilenamePatternResolver("%P/%f.tif");
  800. // now iterate over all files
  801. for (String img:files) {
  802. cmd.run(op,img,resolver.createName(img));
  803. }
  804. </source>
  805. <p>
  806. The FilenamePatternResolver recognizes the following
  807. escape-sequences within it's pattern:
  808. </p>
  809. <ul>
  810. <li>%P: full pathname of source-image (i.e. the directory)</li>
  811. <li>%p: last component of %P</li>
  812. <li>%F: full filename without directory part</li>
  813. <li>%f: filename without directory part and extension</li>
  814. <li>%e: only the extension</li>
  815. <li>%D: drive-letter (on windows systems). Not
  816. available for source-files with an UNC-name.</li>
  817. </ul>
  818. </section>
  819. <section id="BatchConverter">
  820. <title>BatchConverter</title>
  821. <p>
  822. The class <code>org.im4java.utils.BatchConverter</code> is a
  823. utility-class for client-applications. It will convert a
  824. given list of files in parallel making use of all available processors
  825. to speed up execution. It is not well suited for
  826. web-applications, since you don't want a single request to use
  827. up all of your ressources.
  828. </p>
  829. <p>
  830. Usage of this utility-class is straightforward. First you load
  831. your files into a <code>List</code>. This could be from a
  832. GUI-application where a user selects multiple files. Or the
  833. list could contain all files from a given directory (see the
  834. section <a href="#FilenameLoader">FilenameLoader</a> above).
  835. </p>
  836. <source>
  837. ExtensionFilter filter = new ExtensionFilter("jpg");
  838. filter.setRecursion(false);
  839. FilenameLoader loader = new FilenameLoader(filter);
  840. List&lt;String&gt; images=loader.loadFilenames(dir);
  841. </source>
  842. <p>
  843. After you have the list, you create your
  844. <code>BatchConverter</code> and use it's
  845. <code>run()</code>-method to process the images:
  846. </p>
  847. <source>
  848. // create a simple thumbnail operation
  849. op = new IMOperation();
  850. op.size(80);
  851. op.addImage(); // placeholder input filename
  852. op.thumbnail(80);
  853. op.addImage(); // placeholder output filename
  854. // create a template for the output-files:
  855. // we put them in targetDir with the same filename as the original
  856. // images
  857. String template=targetDir+"%F";
  858. // create instance of BatchConverter and convert images
  859. BatchConverter bc = new BatchConverter(BatchConverter.Mode.PARALLEL);
  860. bc.run(op,images,targetDir+"%F");
  861. </source>
  862. <p>
  863. Since <code>BatchConverter</code> extends
  864. <code>ProcessExecutor</code>, you can use the methods
  865. described in the section about <a
  866. href="#processTermination">process termination</a> to wait
  867. for the termination of the command (note that the
  868. <code>shutdown()</code>-method is called automatically).
  869. </p>
  870. <p>
  871. The class <code>BatchConverter</code> knows three modes of
  872. operation: <code>BatchConverter.SEQUENTIAL</code>,
  873. <code>BatchConverter.PARALLEL</code> and
  874. <code>BatchConverter.BATCH</code>. The first mode is more or
  875. less for benchmarking the other two, it converts the images
  876. one after another sequentially. The second mode uses
  877. parallel processing, it runs in it's default setting on all
  878. available processors. The last mode uses convert's ability
  879. to process more than one image at the same time:
  880. </p>
  881. <source>
  882. convert image1.jpg image2.jpg target_%d.tif
  883. mv target_1.tif image1.tif
  884. mv target_2.tif image2.tif
  885. </source>
  886. <p>
  887. On modern computers with more than one processor
  888. <code>BatchConverter.PARALLEL</code> should be the
  889. fastest. If only one (real) processor is available,
  890. <code>BatchConverter.BATCH</code> should make the game.
  891. </p>
  892. <p>
  893. For a complete example see <code>TestCase22</code>. This
  894. test-case subclasses <code>BatchConverter</code> and uses the
  895. <code>terminated()</code>-method to receive a callback after
  896. termination. After termination, the callback-methods uses
  897. the <code>getFailedConversions()</code>-method of
  898. <code>BatchConverter</code> to query a list of
  899. <code>BatchConverter.ConvertException</code>-objects. These
  900. objects wrap the cause and the index of the image
  901. responsible of the failure.
  902. </p>
  903. </section>
  904. </section>
  905. <section id="debug">
  906. <title>Debugging</title>
  907. <p>
  908. Since version 1.0 im4java has a new method
  909. <code>ImageCommand.createScript()</code> to aid in debugging:
  910. </p>
  911. <source>
  912. IMOperation op = new IMOperation();
  913. ...
  914. ConvertCmd cmd = new ConvertCmd();
  915. cmd.createScript("myscript.sh",op);
  916. </source>
  917. <p>
  918. This will dump your command and operation to a
  919. script-file. You should change the execution-permission of the
  920. file and try the script to make sure that you in fact generate
  921. the commandline you intend to use.
  922. </p>
  923. <p>Note that on windows-platforms,
  924. <code>createScript()</code>-method will automatically add the
  925. extension <code>.cmd</code> to the filename passed to the
  926. method.
  927. </p>
  928. </section>
  929. </body>
  930. </document>