Nick Sieger: Tag image tag:blog.nicksieger.com,2005:Typo Typo 2008-03-27T21:39:23+00:00 Nick Sieger urn:uuid:3b535c66-18f9-4ae5-9e37-79757d8b7a32 2008-03-27T21:39:23+00:00 2008-03-27T21:39:23+00:00 ImageVoodoo 0.1 Released <h2>Introducing ImageVoodoo</h2> <p>I just pushed out the first release of ImageVoodoo, a nifty little image manipulation library conceived as a quick hack by <a href="http://www.bloglines.com/blog/ThomasEEnebo" title="Tom's Ruminations - Powered By Bloglines">Tom</a>. It&#8217;s a play-on-words of <a href="http://seattlerb.rubyforge.org/ImageScience.html" title="ImageScience">ImageScience</a>, of course, the quick, lightweight imaging library for Ruby. To get it,</p> <pre><code>jruby -S gem install image_voodoo </code></pre> <p>What&#8217;s cool about ImageVoodoo (other than the name) is that we were able to make it API-compatible with ImageScience. In fact, ImageVoodoo&#8217;s <code>image_science.rb</code> simply looks like this:</p> <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">require</span> <span class="punct">'</span><span class="string">image_voodoo</span><span class="punct">'</span> <span class="comment"># HA HA...let the pin-pricking begin</span> <span class="constant">ImageScience</span> <span class="punct">=</span> <span class="constant">ImageVoodoo</span></code></pre></div> <p>So, you can use it pretty much anywhere you might use ImageScience, and it should <em>just work</em>. At work, we&#8217;re using it with <a href="http://github.com/technoweenie/attachment_fu/tree/master">attachment_fu</a>, and it works great. ImageVoodoo even steals and uses ImageScience&#8217;s unit tests (which all run successfully, too). Speed-wise, it&#8217;s about twice as slow as ImageScience running on MatzRuby, but still plenty fast enough for most cases.</p> <p>But we wouldn&#8217;t be having fun unless we embraced and extended a little bit, right? So I added a couple of extra features you might find useful.</p> <h2>Preview</h2> <p>Since ImageVoodoo is just leveraging the Java Platform&#8217;s imaging libraries, image rendering can be easily tied into a simple preview frame. This code:</p> <div class="typocode"><pre><code class="typocode_ruby "><span class="constant">ImageVoodoo</span><span class="punct">.</span><span class="ident">with_image</span><span class="punct">(&quot;</span><span class="string">samples/checkerboard.jpg</span><span class="punct">&quot;)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">img</span><span class="punct">|</span> <span class="ident">img</span><span class="punct">.</span><span class="ident">preview</span> <span class="keyword">end</span></code></pre></div> <p>Will pop up a little frame like this:</p> <p><img src="/files/image_voodoo_preview.png" alt="preview" title="preview"/></p> <p>The code that displays the preview frame is nice and compact, and shows off how nicely you can write clean swing GUI code using JRuby&#8217;s java integration features.</p> <div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">ImageVoodoo</span> <span class="keyword">class </span><span class="class">JImagePanel</span> <span class="punct">&lt;</span> <span class="ident">javax</span><span class="punct">.</span><span class="ident">swing</span><span class="punct">.</span><span class="ident">JPanel</span> <span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span><span class="ident">image</span><span class="punct">,</span> <span class="ident">x</span><span class="punct">,</span> <span class="ident">y</span><span class="punct">)</span> <span class="keyword">super</span><span class="punct">()</span> <span class="attribute">@image</span><span class="punct">,</span> <span class="attribute">@x</span><span class="punct">,</span> <span class="attribute">@y</span> <span class="punct">=</span> <span class="ident">image</span><span class="punct">,</span> <span class="ident">x</span><span class="punct">,</span> <span class="ident">y</span> <span class="keyword">end</span> <span class="keyword">def </span><span class="method">paintComponent</span><span class="punct">(</span><span class="ident">graphics</span><span class="punct">)</span> <span class="ident">graphics</span><span class="punct">.</span><span class="ident">drawImage</span><span class="punct">(</span><span class="attribute">@image</span><span class="punct">,</span> <span class="attribute">@x</span><span class="punct">,</span> <span class="attribute">@y</span><span class="punct">,</span> <span class="constant">nil</span><span class="punct">)</span> <span class="keyword">end</span> <span class="keyword">end</span> <span class="keyword">class </span><span class="class">WindowClosed</span> <span class="keyword">def </span><span class="method">initialize</span><span class="punct">(</span><span class="ident">block</span> <span class="punct">=</span> <span class="constant">nil</span><span class="punct">)</span> <span class="attribute">@block</span> <span class="punct">=</span> <span class="ident">block</span> <span class="punct">||</span> <span class="ident">proc</span> <span class="punct">{</span> <span class="ident">java</span><span class="punct">.</span><span class="ident">lang</span><span class="punct">.</span><span class="ident">System</span><span class="punct">.</span><span class="ident">exit</span><span class="punct">(</span><span class="number">0</span><span class="punct">)</span> <span class="punct">}</span> <span class="keyword">end</span> <span class="keyword">def </span><span class="method">method_missing</span><span class="punct">(</span><span class="ident">meth</span><span class="punct">,*</span><span class="ident">args</span><span class="punct">);</span> <span class="keyword">end</span> <span class="keyword">def </span><span class="method">windowClosing</span><span class="punct">(</span><span class="ident">event</span><span class="punct">);</span> <span class="attribute">@block</span><span class="punct">.</span><span class="ident">call</span><span class="punct">;</span> <span class="keyword">end</span> <span class="keyword">end</span> <span class="keyword">def </span><span class="method">preview</span><span class="punct">(&amp;</span><span class="ident">block</span><span class="punct">)</span> <span class="ident">frame</span> <span class="punct">=</span> <span class="ident">javax</span><span class="punct">.</span><span class="ident">swing</span><span class="punct">.</span><span class="ident">JFrame</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(&quot;</span><span class="string">Preview</span><span class="punct">&quot;)</span> <span class="ident">frame</span><span class="punct">.</span><span class="ident">add_window_listener</span> <span class="constant">WindowClosed</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="ident">block</span><span class="punct">)</span> <span class="ident">frame</span><span class="punct">.</span><span class="ident">set_bounds</span> <span class="number">0</span><span class="punct">,</span> <span class="number">0</span><span class="punct">,</span> <span class="ident">width</span> <span class="punct">+</span> <span class="number">20</span><span class="punct">,</span> <span class="ident">height</span> <span class="punct">+</span> <span class="number">40</span> <span class="ident">frame</span><span class="punct">.</span><span class="ident">add</span> <span class="constant">JImagePanel</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span><span class="attribute">@src</span><span class="punct">,</span> <span class="number">10</span><span class="punct">,</span> <span class="number">10</span><span class="punct">)</span> <span class="ident">frame</span><span class="punct">.</span><span class="ident">visible</span> <span class="punct">=</span> <span class="constant">true</span> <span class="keyword">end</span> <span class="keyword">end</span></code></pre></div> <h2>Command-line</h2> <p>As I was <a href="http://twitter.com/nicksieger/statuses/778203542">fixing a bug in ImageVoodoo&#8217;s file saving</a> I whipped up a little command-line utility to aid debugging. It allows you to string along several image manipulation actions on a single command-line. For example,</p> <pre><code>jruby -S image_voodoo --push --resize 50x50 --preview --save t1.jpg \ --pop --resize 40x40 --preview --save t2.jpg \ --pop --resize 30x30 --preview --save t3.jpg image.jpg </code></pre> <p>This will resize <code>image.jpg</code> into three smaller images, <code>t[1-3].jpg</code>, but will pop up a preview frame at each step of the way. Simply close the preview frame to continue to the next action, or quit out of the application to abort.</p> <h2>Summary</h2> <p>And so, another functional area, image manipulation, becomes as easy on JRuby as it is on MatzRuby. Now that fancy social networking application you&#8217;ve been working on should have one less reason to be able to run unmodified on JRuby!</p>