<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Bubble Foundry &#187; From the Laboratory</title>
	<atom:link href="http://www.bubblefoundry.com/blog/category/from-the-laboratory/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.bubblefoundry.com</link>
	<description></description>
	<lastBuildDate>Wed, 08 Feb 2012 18:23:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
	<atom:link rel='hub' href='http://www.bubblefoundry.com/?pushpress=hub'/>
		<item>
		<title>Introducing jsFrame</title>
		<link>http://www.bubblefoundry.com/blog/2009/02/introducing-jsframe/</link>
		<comments>http://www.bubblefoundry.com/blog/2009/02/introducing-jsframe/#comments</comments>
		<pubDate>Wed, 18 Feb 2009 18:25:58 +0000</pubDate>
		<dc:creator>Peter</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[From the Laboratory]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jsFrame]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Prototype.js]]></category>
		<category><![CDATA[web application framework]]></category>

		<guid isPermaLink="false">http://www.bubblefoundry.com/?p=173</guid>
		<description><![CDATA[Over the past few months I&#8217;ve become both more comfortable with Javascript and more impressed with what is possible with the language (more on that, with an example, in a few weeks). Doing lots of work with web application frameworks, I&#8217;ve become convinced that writing a framework entirely in Javascript would be both possible and [...]]]></description>
			<content:encoded><![CDATA[<p>Over the past few months I&#8217;ve become both more comfortable with Javascript and more impressed with what is possible with the language (more on that, with an example, in a few weeks). Doing lots of work with <a href="http://en.wikipedia.org/wiki/Web_application_framework">web application frameworks</a>, I&#8217;ve become convinced that writing a framework entirely in Javascript would be both possible and useful. After meeting James Darling at <a href="http://www.ukgovweb.org/">UKGovWeb09</a> and checking out his <a href="http://coupde.com">Coup De</a> website, I started considering the idea more seriously. I had a free day last Sunday and got coding. The result is <a href="http://labs.bubblefoundry.com/jsframe/">jsFrame</a>.</p>
<p>jsFrame is a web framework built entirely upon Javascript, HTML and CSS. It makes heavy use of <a href="http://www.prototypejs.org">Prototype.js</a> and unlike some Javascript systems (such as <a href="http://github.com/james/coup-de">coup-de</a>) it uses the <a href="http://en.wikipedia.org/wiki/Model-view-controller">Model-View-Controller pattern</a> and only loads Views as requested. This means that complicated applications are quite simple to develop, though it also means that simple pages take longer to load than they would with a normal website. I am particularly proud of the simply routing system, which is able to handle <a href="http://en.wikipedia.org/wiki/Rewrite_engine">pretty URLs</a> with a simple <code>.htaccess</code> file and my Javascript code. For more information, check out the <a href="http://labs.bubblefoundry.com/jsframe/">demo site</a>.</p>
<p>Non Javascript hackers can take several things away from this: the browser is becoming more and more the basis for rich web applications, and without Flash; network connections can still be a performance bottleneck despite faster connections, particularly on mobile browsers; reasonably advanced web projects can be executed in a short period of time. Oh, and I&#8217;m pretty handy with Javascript and web frameworks, and you might want to hire me!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bubblefoundry.com/blog/2009/02/introducing-jsframe/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Typecasting Strings to Integers in PHP</title>
		<link>http://www.bubblefoundry.com/blog/2008/08/typecasting-strings-to-integers-in-php/</link>
		<comments>http://www.bubblefoundry.com/blog/2008/08/typecasting-strings-to-integers-in-php/#comments</comments>
		<pubDate>Fri, 15 Aug 2008 14:58:59 +0000</pubDate>
		<dc:creator>Peter</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[From the Laboratory]]></category>
		<category><![CDATA[integeters]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[strings]]></category>
		<category><![CDATA[typecasting]]></category>

		<guid isPermaLink="false">http://www.bubblefoundry.com/?p=75</guid>
		<description><![CDATA[PHP does some funny things when typecasting strings as integers and may not work the way you would expect (to be fair, it is documented). Here are some examples running under PHP 5.2.5 from the Mac OS X command line: php -r 'var_dump((int) "agbae");' int(0) php -r 'var_dump((int) "zzzzzzzzzzzzzzzzzzzzzzz");' int(0) php -r 'var_dump((int) "2agbae");' int(2) [...]]]></description>
			<content:encoded><![CDATA[<p>PHP does some funny things when typecasting strings as integers and may not work the way you would expect (to be fair, <a href="http://www.php.net/manual/en/language.types.string.php#language.types.string.conversion">it is documented</a>). Here are some examples running under PHP 5.2.5 from the Mac OS X command line:</p>
<pre>
php -r 'var_dump((int) "agbae");'
int(0)
</pre>
<pre>
php -r 'var_dump((int) "zzzzzzzzzzzzzzzzzzzzzzz");'
int(0)
</pre>
<pre>
php -r 'var_dump((int) "2agbae");'
int(2)
</pre>
<pre>
php -r 'var_dump((float) "42165.6agbae");'
float(42165.6)
</pre>
<p>This is important to know because PHP allows you refer characters of strings just like you would the elements of an array (and somewhat similar to C&#8217;s strings):</p>
<pre>
php -r '$s = "abcdef"; var_dump($s[2]);'
string(1) "c"
</pre>
<p>However, giving an invalid key won&#8217;t given an error, depending on how your installation of PHP is configured in <code>php.ini</code>. If you give an out-of-bounds string you get an empty string:</p>
<pre>
php -r '$s = "abcdef"; var_dump($s[45]);'
PHP Notice:  Uninitialized string offset:  45 in Command line code on line 1
string(0) ""
</pre>
<p>If you give a string key, it is always for the zeroth index, since it is typecasted to an int and typecasting works as described above:</p>
<pre>
php -r '$s = "abcdef"; var_dump($s['zzzzz']);'
PHP Notice:  Use of undefined constant zzzzz - assumed 'zzzzz' in Command line code on line 1
string(1) "a"
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.bubblefoundry.com/blog/2008/08/typecasting-strings-to-integers-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Loading Javascript Libraries When Needed</title>
		<link>http://www.bubblefoundry.com/blog/2008/06/loading-javascript-libraries-when-needed/</link>
		<comments>http://www.bubblefoundry.com/blog/2008/06/loading-javascript-libraries-when-needed/#comments</comments>
		<pubDate>Mon, 23 Jun 2008 13:27:04 +0000</pubDate>
		<dc:creator>Peter</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[From the Laboratory]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[widgets]]></category>

		<guid isPermaLink="false">http://www.bubblefoundry.com/?p=33</guid>
		<description><![CDATA[Here is a nice little Javascript function to load some Javascript libraries: function includeLibs() { var libs = [{object: 'Prototype', src: 'http://www.mobypicture.com/slideshow/prototype.js'}, {object: 'Lightbox', src: 'http://www.mobypicture.com/slideshow/lightbox.js'}]; for (var k = 0; k &#60; libs.length; k++) { try { var obj = eval(libs[k].object); } catch (err) { var obj = false; } if (obj == false) [...]]]></description>
			<content:encoded><![CDATA[<p>Here is a nice little Javascript function to load some Javascript libraries:<br />
<code><br />
function includeLibs()<br />
{<br />
var libs = [{object: 'Prototype', src: 'http://www.mobypicture.com/slideshow/prototype.js'}, {object: 'Lightbox', src: 'http://www.mobypicture.com/slideshow/lightbox.js'}];<br />
for (var k = 0; k &lt; libs.length; k++)<br />
{<br />
try<br />
{<br />
var obj = eval(libs[k].object);<br />
}<br />
catch (err)<br />
{<br />
var obj = false;<br />
}<br />
if (obj == false)<br />
{<br />
var newjs=document.createElement('script');<br />
newjs.type='text/javascript';<br />
newjs.src=libs[k].src;<br />
document.getElementsByTagName('head')[0].appendChild(newjs);<br />
}<br />
}<br />
}</code><br />
This is particularly useful if you&#8217;re writing a widget that requires external libraries but the user might already have them loaded, such as Prototype.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bubblefoundry.com/blog/2008/06/loading-javascript-libraries-when-needed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Multilink</title>
		<link>http://www.bubblefoundry.com/blog/2008/06/multilink/</link>
		<comments>http://www.bubblefoundry.com/blog/2008/06/multilink/#comments</comments>
		<pubDate>Sat, 21 Jun 2008 17:26:50 +0000</pubDate>
		<dc:creator>Peter</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[From the Laboratory]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Multilink]]></category>
		<category><![CDATA[Prototip]]></category>
		<category><![CDATA[Prototype]]></category>

		<guid isPermaLink="false">http://www.bubblefoundry.com/?p=31</guid>
		<description><![CDATA[Multilink is a very simple Javascript library that creates tooltips with multiple links per &#8216;normal&#8217; link, its simplicity due to Prototip2 and Prototype. Why have one link when you can have ten! Check out the Multilink page for an example.]]></description>
			<content:encoded><![CDATA[<p><a href="http://labs.bubblefoundry.com/multilink/">Multilink</a> is a <em>very</em> simple Javascript library that creates tooltips with multiple links per &#8216;normal&#8217; link, its simplicity due to <a href="http://www.nickstakenburg.com/projects/prototip2/">Prototip2</a> and <a href="http://www.prototypejs.org">Prototype</a>. Why have one link when you can have ten! Check out the <a href="http://labs.bubblefoundry.com/multilink/">Multilink</a> page for an example.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bubblefoundry.com/blog/2008/06/multilink/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>From the Laboratory: Closed Standards</title>
		<link>http://www.bubblefoundry.com/blog/2008/05/closed-standards/</link>
		<comments>http://www.bubblefoundry.com/blog/2008/05/closed-standards/#comments</comments>
		<pubDate>Mon, 26 May 2008 23:44:58 +0000</pubDate>
		<dc:creator>Peter</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[From the Laboratory]]></category>
		<category><![CDATA[3GPP]]></category>
		<category><![CDATA[AMR]]></category>
		<category><![CDATA[FFMPEG]]></category>
		<category><![CDATA[licenses]]></category>
		<category><![CDATA[openess]]></category>
		<category><![CDATA[patents]]></category>
		<category><![CDATA[standards]]></category>

		<guid isPermaLink="false">http://www.bubblefoundry.com/?p=29</guid>
		<description><![CDATA[Closed standards are an oxymoron and any standard that is closed is moronic. This is going to be a rant, so bear with me&#8230;. How can you call anything a standard when you don&#8217;t make the standard readily available? What is the point of a standard that no one can implement? Unfortunately, many &#8216;standardized&#8217; audio [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Closed standards are an oxymoron and any standard that is closed is moronic.</strong></p>
<p>This is going to be a rant, so bear with me&#8230;.</p>
<p>How can you call anything a <em>standard</em> when you don&#8217;t make the standard readily available? What is the point of a standard that no one can implement? Unfortunately, many &#8216;standardized&#8217; audio and video <a href="http://en.wikipedia.org/wiki/Codec">codecs</a> are encumbered by patents, trademarks, and obscenely expensive reference documents. Surprise, surprise, but many of the telco standards bodies are the worst offenders! (As an aside, the movie people, thanks to <a href="http://en.wikipedia.org/wiki/Mpeg">MPEG</a>, seem to be <em>somewhat</em> more sensible).</p>
<p><span id="more-29"></span>Let&#8217;s take <a href="http://www.3gpp.org/">3GPP</a>, the industry standards body for 3G mobile phone services. We won&#8217;t even go into their website, though needless to say it isn&#8217;t helping things. For one, it&#8217;s basically impossible to find anything, such as the all important reference libraries for their standards. As part of my work developing the new <a href="http://www.mobypicture.com">MobyPicture</a> site, I need to implement support for common mobile phone audio and video formats, including <a href="http://en.wikipedia.org/wiki/Adaptive_multi-rate_compression">AMR</a> audio and <a href="http://en.wikipedia.org/wiki/3GP">3GPP</a> video container files.</p>
<p>Like many others, I am using <a href="http://ffmpeg.mplayerhq.hu/">FFMPEG</a>, a fantastic video and audio transcoder. Various codecs and formats are enabled by compiling the relevant libraries and then compiling FFMPEG with reference to them. Great, so let&#8217;s enable AMR support! Oh, wait, where&#8217;s an AMR library we can use? Unfortunately the only real option seems to still be the reference implementation, perhaps from no fault of 3GPP, though I don&#8217;t think they&#8217;ve made <a href="http://rob.opendot.cl/index.php/category/amr/">things</a> <a href="http://wiki.multimedia.cx/index.php?title=AMR-NB">easy</a>. Fine, so let&#8217;s download it and we&#8217;re golden! But where is it? I dare you to find it just browsing the 3GPP site. So you resort to Google and you find various <a href="http://flixforums.com/archive/index.php/t-240.html">whisperings</a> of the secret URLs. But wouldn&#8217;t it be better if projects like FFMPEG just bundled the library source code or, even better, the compiled binary files?</p>
<p>Of course it would, so of course we can&#8217;t have that. For instance, the Word document file included with the reference implementation has a legal license prohibiting ALL reproduction without written authorization. For fraks sakes, it&#8217;s a document just saying what the code is doing, it&#8217;s not top secret or even trade secrets! You make the files freely (though invisibly) available on your servers! But wait, they do contain trade secrets: the reference implementation uses patented technology which people can&#8217;t, in some countries, use without a license. That means that they&#8217;re basically saying: &#8220;This is our standard and here is the code implementing it. But it has patented technology we want you to pay for. So really, to use this reference code you need to pay us money.&#8221; It&#8217;s the look-maybe-if-we-like-you-but-don&#8217;t-touch form of open source! The next best thing to precompiled libraries? A very useful but ugly work-around: write a script without the libraries, so it can be freely distributed, that will <a href="http://www.penguin.cz/~utx/amr">download and then compile them</a>, leaving the patent licensing issues to the final user or developer.</p>
<p>And unsurprisingly, as if a parody of viral licenses such as the GPL, this patented library infects the code that uses it. Enabling AMR support in FFMPEG requires me to pass &#8220;&#8211;enable-nonfree&#8221; to the configure script and means that the resulting compiled binary is technically, legally, <a href="http://archives.free.net.ph/message/20080126.132816.7f6d0063.en.html">nonredistributable</a>. It&#8217;s little surprise that FFMPEG developers <a href="http://archives.free.net.ph/thread/20080127.003734.3ebc3674.en.html">have been tempted</a> to not bother maintaining support.</p>
<p>Why would you charge people to license a standard? That is, why would you seek to have your patented technology used in a standard when you plan (on continuing) to seek royalty payments? That&#8217;s defeating the whole point of a standard, where everyone can and should follow the standard. Instead it&#8217;s pay-to-play. Of course these patent costs are chump change to the likes of Nokia and so on who are members of 3GPP (and will all license some patent or another to each other eventually) but they aren&#8217;t, actually, the best way to encourage adoption of a standard. Remember, people like mp3 format audio not because of its audio quality but because of its small file sizes and, thanks to generally liberal licensing, its implementation on just about any sort of device you could imagine.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bubblefoundry.com/blog/2008/05/closed-standards/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>From the Laboratory: IP2FireEagle</title>
		<link>http://www.bubblefoundry.com/blog/2008/05/from-the-laboratory-ip2fireeagle/</link>
		<comments>http://www.bubblefoundry.com/blog/2008/05/from-the-laboratory-ip2fireeagle/#comments</comments>
		<pubDate>Thu, 22 May 2008 23:03:00 +0000</pubDate>
		<dc:creator>Peter</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[From the Laboratory]]></category>
		<category><![CDATA[Fire Eagle]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[location]]></category>
		<category><![CDATA[status]]></category>
		<category><![CDATA[Yahoo]]></category>

		<guid isPermaLink="false">http://www.bubblefoundry.com/?p=28</guid>
		<description><![CDATA[IP2FireEagle is small PHP script I wrote which will update your location in Yahoo Fire Eagle based upon your current IP address. You can find more information on the IP2FireEagle page.]]></description>
			<content:encoded><![CDATA[<p><a href="http://labs.bubblefoundry.com/ip2fireeagle/">IP2FireEagle</a> is small PHP script I wrote which will update your location in Yahoo <a href="http://fireeagle.yahoo.net/">Fire Eagle</a> based upon your current IP address. You can find more information on the IP2FireEagle page.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bubblefoundry.com/blog/2008/05/from-the-laboratory-ip2fireeagle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>From the Laboratory: Image Resizing and Thumbnail Creation</title>
		<link>http://www.bubblefoundry.com/blog/2008/02/from-the-laboratory-image-resizing-and-thumbnail-creation/</link>
		<comments>http://www.bubblefoundry.com/blog/2008/02/from-the-laboratory-image-resizing-and-thumbnail-creation/#comments</comments>
		<pubDate>Sun, 24 Feb 2008 21:44:26 +0000</pubDate>
		<dc:creator>Peter</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[From the Laboratory]]></category>
		<category><![CDATA[Bubble Foundry Labs]]></category>
		<category><![CDATA[GD]]></category>
		<category><![CDATA[images]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PIL]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Python Imaging Library]]></category>
		<category><![CDATA[resizing]]></category>
		<category><![CDATA[thumbnails]]></category>

		<guid isPermaLink="false">http://www.bubblefoundry.com/blog/2008/02/from-the-laboratory-image-resizing-and-thumbnail-creation/</guid>
		<description><![CDATA[This is the first in a series of posts on technical issues related to web site development and making user-friendly websites. These will focus on the technical details of developing web sites and applications so will probably be interesting to only a subset of readers. Within the next few months, time permitting, we will be [...]]]></description>
			<content:encoded><![CDATA[<p><em>This is the first in a series of posts on technical issues related to web site development and making user-friendly websites. These will focus on the technical details of developing web sites and applications so will probably be interesting to only a subset of readers. Within the next few months, time permitting, we will be launching a new section of the site called Bubble Foundry Labs, where you will be able to find both technical articles and experimental web applications. For non-technical types, these demo applications may prove easier to understand than this article series. </em></p>
<p><span id="more-22"></span><br />
In this post I will discuss how to take a user-uploaded image and resize it, presumably reducing it so as to create a thumbnail. I will try to discuss the methods in language-neutral terms, though occasionally I will give examples in PHP and Python. This is an important topic, as good content management systems and other web-publishing systems should let users interact with images with a minimum of fuss.</p>
<h3>The Logic of Thumbnails</h3>
<p align="left">First, the question &#8216;Why create thumbnails at all?&#8217; must be answered. In <code>img</code> HTML tags you can set both the width and height. So you can create smaller images without creating more files! But no, the image may <em>look</em> smaller but it still is the same size (in kb) as the original, for it is the original. In doing so you have made a trade-off, and a bad one: the server saves minuscule amounts of processing time and disk space while causing increased bandwidth demands for the site, and thus web site visitors. Essentially the work of creating thumbnails is offloaded to the client&#8217;s computer and internet connection, hardly the most user friendly choice!</p>
<p align="left">The next issue to address is when to create a thumbnail. There are several different approaches: when the original image is uploaded, when the thumbnail is first requested, or every time the thumbnail is requested. There are advantages to every approach, though I generally subscribe to the first one. I will briefly highlight the advantages and disadvantages of the other methods. Creating a thumbnail when needed, either the first time or every time, reduces initial processing and disk space requirements. Generating a thumbnail when requested means that thumbnail sizes can change over time without the need to update existing thumbnails. However, outside of scientific computing there are few if any websites dealing with images that are hundreds of megabytes each. Processing time and disk space are cheap, a user&#8217;s time is not. Therefore I believe it is poor choice.</p>
<p align="left">So we come to my preferred method, creating thumbnails when the initial image is uploaded. This provides some assurance about thumbnail locations (once the image is there, it is always there) and minimizes user inconvenience. The uploading user is more tolerant of somewhat limited responsiveness because they are aware that a new image is being added to the web site.</p>
<h3>Saving an Uploaded Image</h3>
<p align="left">So, how do we actually create a thumbnail? First, we take the uploaded file and save it to our destination for original images.  In PHP the uploaded file is stored in <code>$_FILES['<em>variable_name</em>']</code>, while in the <a href="http://pylonshq.com/">Pylons</a> Python framework it is <code>request.POST['<em>variable_name</em>']</code>. In PHP I use the function <code><a href="http://nl3.php.net/manual/en/function.move-uploaded-file.php">move_uploaded_file()</a></code> to move the file from a temporary location to its destination, while in Python I open the destination file for writing (<code>permanent_image = open(<em>destination</em>, 'w')</code>) and then copy the uploaded file to it (<code>shutil.copyfileobj(image_file.file, permanent_image)</code>).</p>
<h3>Creating a Basic Thumbnail</h3>
<p align="left">Now that we have our original, full-size images saved to disk we can create the thumbnails, with <a href="http://nl3.php.net/manual/en/ref.image.php">GD</a> (PHP) and <a href="http://www.pythonware.com/library/pil/handbook/index.htm">PIL</a> (Python) respectively. What I like to do is have an array (or dictionary, in Python) of thumbnail sizes. I will loop through the sizes, creating thumbnails. Now, doing so introduces some wrinkles. On one hand it makes (graphic) designers&#8217; lives a lot easier if you can promise them that the thumbnails will conform to certain dimensions. However, two questions come up: what to do when the requested thumbnail image would actually be larger than the original image, and what to do if the image doesn&#8217;t scale nicely (ie unlike from from 1024 x 768 to 640 x 480)?</p>
<p align="left">The question of thumbnails larger than the original images is a relatively simple one: I recommend either not creating a thumbnail at all or just copying the original image. The PIL <code><a href="http://www.pythonware.com/library/pil/handbook/image.htm#Image.thumbnail">Image.thumbnail()</a></code> method makes your life easier by just preserving the original image&#8217;s dimensions. That being said, if the website design absolutely requires a thumbnail with this larger dimension, you might want to just enlarge the image. Another approach will discussed next in the consideration of different image dimensions.</p>
<p align="left">The question of how to create a thumbnail with different target dimensions or width-height ratio than the original  is a tricky one, as you can have many different situations. If your thumbnail dimensions aren&#8217;t strict, you can respect one of the dimensions, using the equation <code>thumbnail_dimension2 = thumbnail_dimension1 / original_dimension1 * original_dimension2</code> to calculate the other. In PHP we could then use the following code to create our thumbnail:<br />
<code><br />
$thumbnail_image = imagecreatetruecolor($thumbnail_width, $thumbnail_height);<br />
imagecopyresampled($thumbnail_image, $original_image, 0, 0, 0, 0, $thumbnail_width, $thumbnail_height, $original_width, $original_height);<br />
image<em>imagetype</em>($thumbnail_image, $thumbnail_location);<br />
</code><br />
Note that the PHP image library is funny, able to create the thumbnail image without being explicitly told the image type (JPEG, PNG, etc) but requires the image type in order to write it to disk.</p>
<p>And in Python:<br />
<code><br />
thumbnail_image = original_image.copy()<br />
thumbnail_image.thumbnail((thumbnail_width, thumbnail_height), Image.ANTIALIAS)<br />
thumbnail_image.save(thumbnail_location)<br />
</code><br />
Make sure to copy the original image first when using PIL, as otherwise you&#8217;ll end up reducing the size of your original file! Also, it is important that you call <code>thumbnail()</code> with the &#8216;antialias&#8217; filter. If you don&#8217;t it will default to the &#8216;nearest&#8217; filter, which creates ugly images.</p>
<p>The code and methodology above are all you need to create basic thumbnails that preserve the original image&#8217;s aspect ratio, ensuring that the thumbnail image doesn&#8217;t look stretched, pinched, or otherwise distorted.</p>
<h3>Advanced Thumbnails</h3>
<p>My strategy is in an intermediate step to shrink the original image to a placeholder image which fits within the dimensions of the target image but maintains the proper aspect ratio. Having done that, I then create the thumbnail image with a basic background (usually white, though it could be any other color or even transparent, depending on what image format you&#8217;re working with) and overlay the place-holder image on top. I make sure to center the placeholder image within the thumbnail image so that the thumbnail won&#8217;t look lopsided. That being said, if some but not all the dimensions concerned have odd numbers of pixels, the placeholder image will be 1 pixel off of the center.</p>
<p>Reversing the order of my previous examples, I will give the Python code first, as it is much simpler:<br />
<code><br />
placeholder_image = original_image.copy()<br />
placeholder_image.thumbnail(thumbnail_width, thumbnail_height)<br />
placeholder_width, placeholder_height = placeholder_image.size<br />
thumbnail_image = Image.new("RGB", (thumbnail_width, thumbnail_height), (255, 255, 255))<br />
delta_width = thumbnail_width - placeholder_width<br />
delta_height = thumbnail_height - placeholder_height<br />
offset = (int(round(float(delta_width) / float(2))), int(round(float(delta_height) / float(2))))<br />
thumbnail_image.paste(placeholder_image, offset)<br />
</code></p>
<p>As you can see, first we copy the original image and then we call <code>thumbnail()</code> on our copy. Because the <code>thumbnail()</code> function maintains the original image&#8217;s aspect ratio and in this case we assume that our thumbnail dimensions does not have the same ratio, the placeholder dimensions are not equal to the thumbnail ones. Therefore we calculate the difference between the values, giving us the delta values. Dividing the delta values in half us gives a tuple for the offset of the placeholder image from the top left corner of the final, thumbnail image. We then paste the placeholder image into the thumbnail image using this offset.</p>
<p>Unfortunately PHP does not have anything comparable to PIL&#8217;s thumbnail() function, so we will have to discover appropriate dimensions for the placeholder image ourselves. In the code below we will assume that we already know that we will need to create a placeholder image.<br />
<code><br />
if ($original_width &gt; $original_height)<br />
{<br />
$placeholder_width = $thumbnail_width;<br />
$placeholder_height = ($placeholder_width / $original_width) * $original_height;<br />
}<br />
else<br />
{<br />
$placeholder_height = $thumbnail_height;<br />
$placeholder_width = ($placeholder_height / $original_height) * $original_width;<br />
}<br />
$thumbnail_image = imagecreatetruecolor($thumbnail_width, $thumbnail_height);<br />
$white = imagecolorallocate($thumbnail_image, 255, 255, 255);<br />
imagefill($thumbnail_image, 0, 0, $white);<br />
$offset_width = round(($thumbnail_width - $placeholder_width) / 2);<br />
$offset_height = round(($thumbnail_height - $placeholder_height) / 2);<br />
imagecopyresampled($thumbnail_image, $original_image, $offset_width, $offset_width, 0, 0, $placeholder_width, $placeholder_height, $original_width, $original_height);<br />
</code><br />
Note that, unlike in Python, we do not actually create an intermediate image. In fact, the code is flexible enough that it would also work just fine if the placeholder and thumbnail values are the same, as the offset values would simply be zero, like in the previous PHP code example.</p>
<p>With the code above you should be able to always create thumbnails that both respect the original images&#8217; aspect ratios and have the final dimensions that you desire.</p>
<h3>Conclusion</h3>
<p>Resizing images and creating thumbnails are not terribly difficult, but there are several checks you need to make so as to insure that the thumbnails you are creating don&#8217;t unnecessarily distort the image or degrade its quality. Happy coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bubblefoundry.com/blog/2008/02/from-the-laboratory-image-resizing-and-thumbnail-creation/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

