<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Dan Byström's Bwain</title>
	<atom:link href="http://danbystrom.se/feed/" rel="self" type="application/rss+xml" />
	<link>http://danbystrom.se</link>
	<description>Blog without an interesting name</description>
	<lastBuildDate>Tue, 16 Feb 2010 17:40:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='danbystrom.se' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://0.gravatar.com/blavatar/ab5810f6fffe86ee8f337fdf8a1437bb?s=96&#038;d=http://s2.wp.com/i/buttonw-com.png</url>
		<title>Dan Byström's Bwain</title>
		<link>http://danbystrom.se</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://danbystrom.se/osd.xml" title="Dan Byström&#039;s Bwain" />
	<atom:link rel='hub' href='http://danbystrom.se/?pushpress=hub'/>
		<item>
		<title>WTF???</title>
		<link>http://danbystrom.se/2009/11/30/wtf/</link>
		<comments>http://danbystrom.se/2009/11/30/wtf/#comments</comments>
		<pubDate>Mon, 30 Nov 2009 10:21:19 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://danbystrom.se/2009/11/30/wtf/</guid>
		<description><![CDATA[Ekeforshus<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=331&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://translate.google.se/#sv|en|tidsbokning"><img class="aligncenter size-full wp-image-330" title="Google Translate" src="http://danbystrom.files.wordpress.com/2009/11/googletranslate.jpg?w=675&#038;h=353" alt="" width="675" height="353" /></a>  <a href="http://www.vdsoft.se"><span style="color:#ffffff;">Ekeforshus</span></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/331/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=331&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2009/11/30/wtf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>

		<media:content url="http://danbystrom.files.wordpress.com/2009/11/googletranslate.jpg" medium="image">
			<media:title type="html">Google Translate</media:title>
		</media:content>
	</item>
		<item>
		<title>Thumbnails with glass table reflection in GDI+</title>
		<link>http://danbystrom.se/2009/01/12/thumbnails-with-glass-table-reflection-in-gdi/</link>
		<comments>http://danbystrom.se/2009/01/12/thumbnails-with-glass-table-reflection-in-gdi/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 09:04:47 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[GDI+]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://danbystrom.se/?p=260</guid>
		<description><![CDATA[I&#8217;ve been playing around with image processing lately and since my last post about loading thumbnail images from files I couldn&#8217;t help myself from trying to roll my own &#8220;Web 2.0 reflection effect&#8221; directly in .NET 2.0 with no 3D support whatsoever. Actually, I think was more inspired by Windows Vista&#8217;s thumbnails (to the right) [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=260&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-294" title="vistathumbnails" src="http://danbystrom.files.wordpress.com/2009/01/vistathumbnails.jpg?w=160&#038;h=112" alt="vistathumbnails" width="160" height="112" />I&#8217;ve been playing around with image processing lately and since my last post about loading thumbnail images from files I couldn&#8217;t help myself from trying to roll my own &#8220;Web 2.0 reflection effect&#8221; directly in .NET 2.0 with no 3D support whatsoever. Actually, I think was more inspired by Windows Vista&#8217;s thumbnails (to the right) than the web.</p>
<p>This is what I eventually came up with:</p>
<p><img class="alignnone size-full wp-image-281" title="reflectionsamples1" src="http://danbystrom.files.wordpress.com/2009/01/reflectionsamples1.jpg?w=695&#038;h=241" alt="reflectionsamples1" width="695" height="241" /></p>
<p>Although this is all easy &#8211; since there were a few things that couldn&#8217;t be done in &#8220;pure&#8221; GDI+ and then some uncommon approaches involved in my solution, I think that there may be some people out there who don&#8217;t find this totally trivial. So I thought that it might be worth writing this down.</p>
<p>From the original picture I work through four steps:</p>
<p><img class="alignnone size-full wp-image-287" title="reflectionsteps2" src="http://danbystrom.files.wordpress.com/2009/01/reflectionsteps2.jpg?w=393&#038;h=288" alt="reflectionsteps2" width="393" height="288" /></p>
<p><span style="font-size:x-large;">1.</span> The first step merely shrinks the original picture to the desired size and puts a frame around it. This is trivial:</p>
<pre class="brush: csharp;">
	protected virtual Bitmap createFramedBitmap( Bitmap bmpSource, Size szFull )
	{
		Bitmap bmp = new Bitmap( szFull.Width, szFull.Height );
		using ( Graphics g = Graphics.FromImage( bmp ) )
		{
			g.FillRectangle( FrameBrush, 0, 0, szFull.Width, szFull.Height );
			g.DrawRectangle( BorderPen, 0, 0, szFull.Width - 1, szFull.Height - 1 );
			g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
			g.DrawImage(
				bmpSource,
				new Rectangle( FrameWidth, FrameWidth, szFull.Width - FrameWidth * 2, szFull.Height - FrameWidth * 2 ),
				new Rectangle( Point.Empty, bmpSource.Size ),
				GraphicsUnit.Pixel );
		}
		return bmp;
	}
</pre>
<p>(Note the InterpolationMode property. It is important in order to resize the image with good quality!)</p>
<p><span style="font-size:x-large;">2.</span> The second step is substantially more involved. It takes the result from step 1 and does this, all in one go:</p>
<ol>
<li>Flip the image upside down (omitting the upper and lower parts of frame, since we don&#8217;t want them to be present in the reflection).</li>
<li>Apply a <a href="http://en.wikipedia.org/wiki/Gaussian_blur">Gaussian blur</a> convolution effect to make the image look&#8230;, well, blurred&#8230; <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
<li>Wash out some color to make the reflection a little bit grayish.</li>
<li>Apply an alpha blend fall out.</li>
</ol>
<p>Flipping the image and the color wash-out can both be done directly in GDI+. Flip either with Bitmap.RotateFlip or with a transformation matrix and use a ColorMatrix to alter the colors. But since neither a blur effect nor an alpha blend can be done without direct pixel manipulation I did it all in one go. For the blur effect, see Christian Graus excellent article series <a href="http://www.codeproject.com/KB/GDI-plus/csharpfilters.aspx">Image Processing for Dummies with C# and GDI+</a>. I&#8217;ve blogged earlier on how to perform alpha blending previously by drawing the blend using a PathGradientBrush or a LinearGradientBrush in <a href="http://danbystrom.se/2008/08/24/soft-edged-images-in-gdi/">Soft edged images in GDI+</a>. This time I will calculate the alpha value instead. The calculation is done once for every scan line and is located in a virtual function so that this formula can be overridden.</p>
<p>All four &#8220;effects&#8221; are handled in this loop:</p>
<pre class="brush: csharp;">
	for ( int y = height-1 ; y &gt;= 0 ; y-- )
	{
		byte alpha = (byte)(255 * calculateAlphaFallout( (double)(height - y) / height ));
		Pixel* pS = (Pixel*)bdS.Scan0.ToPointer() + bdS.Width * (bdS.Height - y - FrameWidth - 1);
		Pixel* pD = (Pixel*)bdD.Scan0.ToPointer() + bdD.Width * y;
		for ( int x = bdD.Width ; x &gt; 0 ; x--, pD++, pS++ )
		{
			int R = gaussBlur( &amp;pS-&gt;R, nWidthInPixels );
			int G = gaussBlur( &amp;pS-&gt;G, nWidthInPixels );
			int B = gaussBlur( &amp;pS-&gt;B, nWidthInPixels );
			pD-&gt;R = (byte)((R * 3 + G * 2 + B * 2) / 7);
			pD-&gt;G = (byte)((R * 2 + G * 3 + B * 2) / 7);
			pD-&gt;B = (byte)((R * 2 + G * 2 + B * 3) / 7);
			pD-&gt;A = alpha;
		}
	}
</pre>
<p>Flipping happens on line 4, blurring on lines 8-10 (the gaussBlur function is just a one-liner). Color wash-out is done on lines 11-13 and the alpha fall-out on lines 3 and 14.</p>
<p>The very observant reader will notice that I let the blurring wrap from one edge to another. This is a hack, but it works since the left and right edges are always exactly identical. In production code, it might be a good idea to make the blurring optional (or even to provide a user-defined convolution matrix) and also to do the same from the color wash-out which currently uses hard-coded values.</p>
<p><span style="font-size:x-large;">3.</span> Create the &#8220;half sheared&#8221; bitmap:</p>
<p>This transform cannot be accomplished using a linear transformation, but (after taking quite a a detour on this) I realized that it can be done embarrassingly simple:</p>
<pre class="brush: csharp;">
	using ( Graphics g = Graphics.FromImage( Thumbnail ) )
		for ( int x = 0 ; x &lt; sz.Width ; x++ )
			g.DrawImage(
				bmpFramed,
				new RectangleF( x, 0, 1, sz.Height - Skew * (float)(sz.Width - x) / sz.Width ),
				new RectangleF( x, 0, 1, sz.Height ),
				GraphicsUnit.Pixel );
</pre>
<p>I simply use DrawImage to draw each column by its own, transferring one column from the framed image from step 1 to a column of different height. Note that it is extremely important that we pass <strong>float</strong>s and not <strong>int</strong>s &#8211; in the latter case the result will be a disaster.</p>
<p><span style="font-size:x-large;">4.</span> Draw the reflection image through a shear transform, like this:</p>
<pre class="brush: csharp;">
	using ( Graphics g = Graphics.FromImage( Thumbnail ) )
	{
		System.Drawing.Drawing2D.Matrix m = g.Transform;
		m.Shear( 0, (float)Skew / sz.Width);
		m.Translate( 0, sz.Height - Skew - 1 );
		g.Transform = m;
		g.DrawImage( bmpReflection, Point.Empty );
	}
 </pre>
<p><a href="http://www.visual-design.se/blog/reflectedthumbnaildemo.zip">Download demo source code</a></p>
<h2>A Lesson Learned</h2>
<p>At first, I tried to do the shearing in both step 3 &amp; 4 myself using code similar to this (still one column at a time):</p>
<pre class="brush: csharp;">
	// this was a bad idea
	private static void paintRowWithResize(
		BitmapData bdDst,
		BitmapData bdSrc,
		int nDstColumn,
		int nSrcColumn,
		int nDstRow,
		double dblSrcRow,
		int nRows,
		double dblStep )
	{
		unchecked
		{
			unsafe
			{
				Pixel* pD = (Pixel*)bdDst.Scan0.ToPointer() + nDstColumn + nDstRow * bdDst.Width;
				Pixel* pS = (Pixel*)bdSrc.Scan0.ToPointer() + nSrcColumn;
				while ( nRows -- &gt; 0 )
				{
					int nYSrc = (int)dblSrcRow;
					Pixel p1 = pS[nYSrc * bdSrc.Width];
					Pixel p2 = p2 = pS[(nYSrc + 1) * bdSrc.Width];
					double frac2 = dblSrcRow - nYSrc;
					double frac1 = 1.0 - frac2;
					pD-&gt;R = (byte)(p1.R * frac1 + p2.R * frac2);
					pD-&gt;G = (byte)(p1.G * frac1 + p2.G * frac2);
					pD-&gt;B = (byte)(p1.B * frac1 + p2.B * frac2);
					pD-&gt;A = (byte)(p1.A * frac1 + p2.A * frac2);

					dblSrcRow += dblStep;
					pD += bdDst.Width;
				}
			}
		}
	}
</pre>
<p>The result looked perfectly good, but after thinking about it for awhile I realized that this piece of code actually is completely and utterly wrong in the general case: it only works when the alpha values of the two adjacent pixels are very close. In other cases the result will be poor.</p>
<p>Perhaps the easiest way to see this is to think about what happens when we want a 50% mix of a completely transparent pixel and a completely opaque while pixel. Intuitively I think it&#8217;s clear that we want the result to be a white pixel with 50% transparency. However, if we represent the transparent pixel with (0,0,0,0) (the most common value I&#8217;d guess, although (0,x,x,x) is transparent regardless of the value of x) we get a <strong>gray</strong> half transparent pixel instead (127,127,127,127). Not right at all. The reason I thought my attempt looked good in the first place was just because I had a gray border around the images!</p>
<p>So how <strong>do</strong> we mix pixels with alpha values? Obviously &#8220;normal&#8221; <a href="http://en.wikipedia.org/wiki/Alpha_Blend">alpha blending</a> is not sufficient when we have alpha values on <strong>both</strong> pixels&#8230; after thinking about this for a few minutes,  I said to myself &#8220;why not ask someone who knows instead?&#8221;. That someone is of course Graphics.DrawImage, and so I ended up with much cleaner code. And although I never bothered to figure out how to mix and blend pixels when both pixels contain alpha values I ended up realizing this:</p>
<p style="padding-left:30px;"><em>Graphics.DrawImage has quite a bit of work to do when we draw a 32-bit bitmap on top of another. If we have some a-priori knowledge of the nature of the bitmaps we&#8217;re working with (are any of them totally opaque?) then it is actually possible to do this ourselves much faster than Graphics.DrawImage has a chance to, because it is forced to work with the general case: both bitmaps may be semi-transparent.</em></p>
<p>I will get back on how we in some cases can outperform Graphics.DrawImage (when it comes to speed), and hopefully a real life case when we actually bother. Stay tuned. <a href="http://www.vdsoft.se"><span style="color:#ffffff;">Ekeforshus</span></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/260/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=260&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2009/01/12/thumbnails-with-glass-table-reflection-in-gdi/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>

		<media:content url="http://danbystrom.files.wordpress.com/2009/01/vistathumbnails.jpg" medium="image">
			<media:title type="html">vistathumbnails</media:title>
		</media:content>

		<media:content url="http://danbystrom.files.wordpress.com/2009/01/reflectionsamples1.jpg" medium="image">
			<media:title type="html">reflectionsamples1</media:title>
		</media:content>

		<media:content url="http://danbystrom.files.wordpress.com/2009/01/reflectionsteps2.jpg" medium="image">
			<media:title type="html">reflectionsteps2</media:title>
		</media:content>
	</item>
		<item>
		<title>Jeff Minter is back</title>
		<link>http://danbystrom.se/2009/01/12/jeff-minter-is-back/</link>
		<comments>http://danbystrom.se/2009/01/12/jeff-minter-is-back/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 07:59:15 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://danbystrom.se/?p=314</guid>
		<description><![CDATA[The man who once brought us Metagalactic Llamas Battle at the Edge of Time, Sheep in Space and Revenge of the Mutant Camals has returned with: Space Giraffe That feels good to know. Ekeforshus<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=314&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>The man who once brought us Metagalactic Llamas Battle at the Edge of Time, Sheep in Space and Revenge of the Mutant Camals has returned with:</p>
<p style="padding-left:30px;"><a href="http://www.llamasoft.co.uk/games/space-giraffe">Space Giraffe</a></p>
<p>That feels good to know. <a href="http://www.vdsoft.se"><span style="color:#ffffff;">Ekeforshus</span></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/314/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=314&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2009/01/12/jeff-minter-is-back/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>
	</item>
		<item>
		<title>Image.GetThumbnailImage and beyond</title>
		<link>http://danbystrom.se/2009/01/05/imagegetthumbnailimage-and-beyond/</link>
		<comments>http://danbystrom.se/2009/01/05/imagegetthumbnailimage-and-beyond/#comments</comments>
		<pubDate>Mon, 05 Jan 2009 11:09:53 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[GDI+]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://danbystrom.se/?p=187</guid>
		<description><![CDATA[Once I tried to use Image.GetThumbnailImage because I wanted to fire up small thumbnails as fast as possible. So I tried: // totally and completely, utterly useless private Bitmap getThumbnailImage( string filename, int width, int height ) { using ( Image img = Image.FromFile( filename ) ) return (Bitmap)img.GetThumbnailImage( width, height, null, IntPtr.Zero ); } [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=187&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>Once I tried to use <strong>Image.GetThumbnailImage</strong> because I wanted to fire up small thumbnails as fast as possible. So I tried:</p>
<pre class="brush: csharp;">
	// totally and completely, utterly useless
	private Bitmap getThumbnailImage( string filename, int width, int height )
	{
		using ( Image img = Image.FromFile( filename ) )
			return (Bitmap)img.GetThumbnailImage( width, height, null, IntPtr.Zero );
	}
</pre>
<p>This turned out to be completely useless, since <strong>Image.FromFile</strong> first loads the full image so that no performance is gained whatsoever. Trying to google after a solution only resulted in tons of articles saying that <strong>Image.GetThumbnailImage</strong> is pretty useless and shouldn&#8217;t be used. So I dropped it and solved my problem in a completely different way. Now I just stumbled across an overloaded version <strong>Image.FromStream</strong> which I haven&#8217;t noticed before:</p>
<p><a href="http://msdn.microsoft.com/en-us/library/21zw9ah6(VS.80).aspx">Image.FromStream( Stream stream, bool useEmbeddedColorManagement, bool validateImageData )</a></p>
<p>This opens up for some interesting usages. For example it means that we really can get a thumbnail fast:</p>
<pre class="brush: csharp;">
	// way, way faster, but still pretty useless
	private Bitmap getThumbnailImage( string filename, int width, int height )
	{
		using ( FileStream fs = new FileStream( filename, FileMode.Open ) )
		using ( Image img = Image.FromStream( fs, true, false ) )
			return (Bitmap)img.GetThumbnailImage( width, height, null, IntPtr.Zero );
	}
</pre>
<p>This is still pretty useless, since this way we really don&#8217;t know how to get a proportional thumbnail. This is something that seems to be lacking in GDI+: an easy way to rescale images proportionally. Quite frankly: how often are we interested in non-proportional rescales? Not that often, I&#8217;d say! Here&#8217;s a better version:</p>
<pre class="brush: csharp;">
	// actually works...
	private Bitmap getThumbnailImage( string filename, int width )
	{
		using ( FileStream fs = new FileStream( filename, FileMode.Open ) )
		using ( Image img = Image.FromStream( fs, true, false ) )
			return (Bitmap)img.GetThumbnailImage(
				width,
				width * img.Height / img.Width,
				null,
				IntPtr.Zero );
	}
</pre>
<p>But if we arm ourselves with a way to rescale images proportionally, something Microsoft apparently decided to leave as an exercise for each and every programmer who wants to do even the simplest things with images in GDI+:</p>
<pre class="brush: csharp;">
	public static Size adaptProportionalSize(
		Size szMax,
		Size szReal )
	{
		int nWidth;
		int nHeight;
		double sMaxRatio;
		double sRealRatio;

		if ( szMax.Width &lt; 1 || szMax.Height &lt; 1 || szReal.Width &lt; 1 || szReal.Height &lt; 1 )
			return Size.Empty;

		sMaxRatio = (double)szMax.Width / (double)szMax.Height;
		sRealRatio = (double)szReal.Width / (double)szReal.Height;

		if ( sMaxRatio &lt; sRealRatio )
		{
			nWidth = Math.Min( szMax.Width, szReal.Width );
			nHeight = (int)Math.Round( nWidth / sRealRatio );
		}
		else
		{
			nHeight = Math.Min( szMax.Height, szReal.Height );
			nWidth = (int)Math.Round( nHeight * sRealRatio );
		}

		return new Size( nWidth, nHeight );
	}
</pre>
<p>With that, we can fire up a thumbnail image fast, with a given maximum allowed size while still proportional:</p>
<pre class="brush: csharp;">
	// even better...
	private Bitmap getThumbnailImage( string filename, Size szMax )
	{
		using ( FileStream fs = new FileStream( filename, FileMode.Open ) )
		using ( Image img = Image.FromStream( fs, true, false ) )
		{
			Size sz = adaptProportionalSize( szMax, img.Size );
			return (Bitmap)img.GetThumbnailImage(
				sz.Width,
				sz.Height,
				null,
				IntPtr.Zero );
		}
	}
</pre>
<p>So, it appears that <strong>Image.GetThumbnailImage</strong> had its use after all! But there&#8217;s more we can do with this.</p>
<p>Even though we managed to load thumbnail images fast and proportionally, the quality isn&#8217;t particularly good. That&#8217;s seems to be the main concern among those who advocate not using Image.GetThumbnailImage at all. If a thumbnail is found in the image file it has already been resized once, and resizing a resized image once more certainly won&#8217;t improve the quality, especially if a crappy resizing algorithm is being used. Let&#8217;s see what we can do about this. If we&#8217;re working with JPG images coming from a digital camera, we can most probably find the &#8220;real&#8221; thumbnail image like this:</p>
<pre class="brush: csharp;">
	private Bitmap getExifThumbnail( string filename )
	{
		using ( FileStream fs = new FileStream( filename, FileMode.Open ) )
		using ( Image img = Image.FromStream( fs, true, false ) )
		{
			foreach ( PropertyItem pi in img.PropertyItems )
				if ( pi.Id == 20507 )
					return (Bitmap)Image.FromStream( new MemoryStream( pi.Value ) );
		}
		return null;
	}
</pre>
<p>If we can retrieve a thumbnail this way, it will be in its original size and so we can skip an implicit resize. If we want to rescale it anyway, we can do it in a high quality fashion. I don&#8217;t know if this is something everybody knows &#8211; I had worked with GDI+ for quite some time before I found it &#8211; but fact is that resizing an image like this give good performance but crappy result:</p>
<pre class="brush: csharp;">
	// poor image quality
	Bitmap bmpResized = new Bitmap( bmpOriginal, newWidth, newHeight );
</pre>
<p>Instead, try the following:</p>
<pre class="brush: csharp;">
	// superior image quality
	Bitmap bmpResized = new Bitmap( newWidth, newHeight );
	using ( Graphics g = Graphics.FromImage( bmpResized ) )
	{
		g.InterpolationMode = InterpolationMode.HighQualityBicubic;
		g.DrawImage(
			bmpOriginal,
			new Rectangle( Point.Empty, bmpResized.Size ),
			new Rectangle( Point.Empty, bmpOriginal.Size ),
			GraphicsUnit.Pixel );
	}
</pre>
<p>With these code pieces glued together I can now get a thumbnail from a JPG image both faster and with better quality than with my original Image.ImageFromThumbnail attempt!</p>
<p><strong>UPDATE</strong>: This technique is used &#8220;live&#8221; in the demo source code accompanying this post: <a href="http://danbystrom.se/2009/01/12/thumbnails-with-glass-table-reflection-in-gdi/">Thumbnails with glass table reflection in GDI+</a>.</p>
<p>Finally, one more thing that I just come to think of while I was typing this. I have complained in earlier posts that <strong>Image.FromFile</strong> for some obscure reason keeps the file locked until disposed of. I just realized that there is an easy way around his:</p>
<pre class="brush: csharp;">
	using ( FileStream fs = new FileStream( filename, FileMode.Open ) )
		bmp = (Bitmap)Image.FromStream( fs );
</pre>
<p>Behold &#8211; now the image is loaded and the file is NOT locked! <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  <a href="http://www.vdsoft.se"><span style="color:#ffffff;">Ekeforshus</span></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/187/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=187&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2009/01/05/imagegetthumbnailimage-and-beyond/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>
	</item>
		<item>
		<title>Optimizing away II.3</title>
		<link>http://danbystrom.se/2009/01/01/optimizing-away-ii3/</link>
		<comments>http://danbystrom.se/2009/01/01/optimizing-away-ii3/#comments</comments>
		<pubDate>Thu, 01 Jan 2009 19:26:47 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://danbystrom.se/?p=206</guid>
		<description><![CDATA[Oh, the pain, the pain and the embarrassment&#8230; I just came to realize that although a &#8220;long&#8221; in C# is 64 bits, in C++ it is still 32 bits. In order to get a 64 bit value in MSVC++ you must type either &#8220;long long&#8221; or &#8220;__int64&#8243;. I didn&#8217;t know that. This means that although [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=206&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>Oh, the pain, the pain and the embarrassment&#8230;</p>
<p>I just came to realize that although a &#8220;long&#8221; in C# is 64 bits, in C++ it is still 32 bits. In order to get a 64 bit value in MSVC++ you must type either &#8220;long long&#8221; or &#8220;__int64&#8243;. I didn&#8217;t know that. <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> </p>
<p>This means that although the assembler function I just <a href="http://danbystrom.se/2008/12/22/optimizing-away-ii/">presented </a>correctly calculates a 64 bit value, it will be truncated to 32 bits because the surrounding C++ function is declared as a long.</p>
<p>This in turn means that for bitmaps larger than 138 x 138 pixels &#8211; the correct result cannot be guaranteed. (With 64 bit values, the bitmap can instead be 9724315 x 9724315 pixels in size before an overflow can occur.)</p>
<p>Unfortunately, although I had unit test to verify the correctness of the function, I only tested with small bitmaps.</p>
<p>I have <a href="http://www.visual-design.se/blog/fic.zip">uploaded a new version</a>. <a href="http://www.vdsoft.se"><span style="color:#ffffff;">Ekeforshus</span></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/206/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/206/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/206/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/206/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/206/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/206/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/206/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/206/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/206/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/206/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/206/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/206/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/206/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/206/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=206&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2009/01/01/optimizing-away-ii3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>
	</item>
		<item>
		<title>Optimizing away II.2</title>
		<link>http://danbystrom.se/2008/12/30/optimizing-away-ii2/</link>
		<comments>http://danbystrom.se/2008/12/30/optimizing-away-ii2/#comments</comments>
		<pubDate>Tue, 30 Dec 2008 13:20:58 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://danbystrom.se/?p=197</guid>
		<description><![CDATA[I was asked to upload the source and binary for my last post.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=197&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>I was asked to upload the <a href="http://www.visual-design.se/blog/fic.zip">source and binary</a> for my <a href="http://danbystrom.se/2008/12/22/optimizing-away-ii/">last post</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/197/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=197&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2008/12/30/optimizing-away-ii2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>
	</item>
		<item>
		<title>Optimizing away II</title>
		<link>http://danbystrom.se/2008/12/22/optimizing-away-ii/</link>
		<comments>http://danbystrom.se/2008/12/22/optimizing-away-ii/#comments</comments>
		<pubDate>Mon, 22 Dec 2008 11:17:39 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://danbystrom.se/?p=172</guid>
		<description><![CDATA[Continued from Optimizing away. Ok, now I have worked up the courage. Prepare yourself for a major disappointment. I really do not know how to tweak that C#-loop to run a nanosecond faster. But I can do the same calculation much faster. How? Just my old favorite party trick. It goes like this: 1. Add [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=172&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>Continued from <a href="http://danbystrom.se/2008/12/16/optimizing-away/">Optimizing away</a>. Ok, now I have worked up the courage.</p>
<p>Prepare yourself for a major disappointment. I really do not know how to tweak that C#-loop to run a nanosecond faster. But I can do the same calculation much faster. How? Just my old favorite party trick. It goes like this:</p>
<p>1. Add a new project to your solution</p>
<p>2. Chose Visual C++ / CLR / Class Library</p>
<p>3. Insert the following managed class:</p>
<pre class="brush: csharp;">
	public ref class FastImageCompare
	{
	public:
		static double compare( void* p1, void* p2, int count )
		{
			return NativeCode::fastImageCompare( p1, p2, count );
		}
		static double compare( IntPtr p1, IntPtr p2, int count )
		{
			return NativeCode::fastImageCompare( p1.ToPointer(), p2.ToPointer(), count );
		}
	};
</pre>
<p>4. Insert the following function into an unmanaged class (which I happened to call NativeCode):</p>
<pre class="brush: csharp;">
unsigned long long NativeCode::fastImageCompare( void* p1, void* p2, int count )
{
	int high32 = 0;

	_asm
	{
		push	ebx
		push	esi
		push	edi

		mov		esi, p1
		mov		edi, p2
		xor		eax, eax
again:
		dec		count
		js		done

		movzx	ebx, [esi]
		movzx	edx, [edi]
		sub		edx, ebx
		imul	edx, edx

		movzx	ebx, [esi+1]
		movzx	ecx, [edi+1]
		sub		ebx, ecx
		imul	ebx, ebx
		add		edx, ebx

		movzx	ebx, [esi+2]
		movzx	ecx, [edi+2]
		sub		ebx, ecx
		imul	ebx, ebx
		add		edx, ebx

		add		esi, 4
		add		edi, 4

		add		eax, edx
		jnc		again

		inc		high32
		jmp		again
done:
		mov		edx, high32

		pop		edi
		pop		esi
		pop		ebx
	}

}
</pre>
<p>Yeah. That&#8217;s it. Hand tuned assembly language within a .NET Assembly. <strong>UPDATE </strong>2009-01-01: return type of the function changed from &#8220;unsigned long&#8221; to &#8220;unsigned long long&#8221;, <a href="http://danbystrom.se/2009/01/01/optimizing-away-ii3/">see here</a>.</p>
<p>I guess that&#8217;s almost cheating. And we will be locked inside the Intel platform. Most people won&#8217;t mind I guess, but other may have very strong feelings about it. If we really would like to exploit this kind of optimizations while still be portable (to Mono/Mac for example) one possibility would be to load the assembly with native code dynamically. If it fails we could fall back to an alternative version written in pure managed code.</p>
<p>(I know from experience that some people with lesser programming skills react to this with a &#8220;what? it must be a crappy compiler if you can write faster code by yourself&#8221;. Let me assure you that this is not the case. On the contrary: I&#8217;m amazed about the quality of the code emitted by the C# + .NET JIT compilers.)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/172/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/172/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/172/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/172/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/172/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/172/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/172/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/172/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/172/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/172/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/172/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/172/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/172/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/172/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=172&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2008/12/22/optimizing-away-ii/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>
	</item>
		<item>
		<title>Optimizing away</title>
		<link>http://danbystrom.se/2008/12/16/optimizing-away/</link>
		<comments>http://danbystrom.se/2008/12/16/optimizing-away/#comments</comments>
		<pubDate>Tue, 16 Dec 2008 11:57:45 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://danbystrom.se/?p=161</guid>
		<description><![CDATA[Follow-up on Improving performance&#8230;  and Genetic Programming: Evolution of Mona Lisa. I just tested that I can optimize this loop: unchecked { unsafe { fixed ( Pixel* psourcePixels = sourcePixels ) { Pixel* p1 = (Pixel*)bd.Scan0.ToPointer(); Pixel* p2 = psourcePixels; for ( int i = sourcePixels.Length ; i &#62; 0 ; i--, p1++, p2++ ) [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=161&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>Follow-up on <a href="http://danbystrom.se/2008/12/14/improving-performance/">Improving performance&#8230;</a>  and <a href="http://rogeralsing.com/2008/12/07/genetic-programming-evolution-of-mona-lisa/">Genetic Programming: Evolution of Mona Lisa</a>.<br />
I just tested that I can optimize this loop:</p>
<pre class="brush: csharp;">
unchecked
{
    unsafe
    {
        fixed ( Pixel* psourcePixels = sourcePixels )
        {
            Pixel* p1 = (Pixel*)bd.Scan0.ToPointer();
            Pixel* p2 = psourcePixels;
            for ( int i = sourcePixels.Length ; i &gt; 0 ; i--, p1++, p2++ )
            {
                int r = p1-&gt;R - p2-&gt;R;
                int g = p1-&gt;G - p2-&gt;G;
                int b = p1-&gt;B - p2-&gt;B;
                error += r * r + g * g + b * b;
            }
        }
    }
}
</pre>
<p>so that it runs even 60% faster. Don’t dare to tell you how, however.</p>
<p>EDIT: <a href="http://danbystrom.se/2008/12/22/optimizing-away-ii/">Continued here</a>  <a href="http://www.vdsoft.se"><span style="color:#ffffff;">Ekeforshus</span></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/161/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=161&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2008/12/16/optimizing-away/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>
	</item>
		<item>
		<title>Besserwisser post on EvoLisa</title>
		<link>http://danbystrom.se/2008/12/14/besserwisser-blog/</link>
		<comments>http://danbystrom.se/2008/12/14/besserwisser-blog/#comments</comments>
		<pubDate>Sun, 14 Dec 2008 18:42:50 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://danbystrom.se/?p=131</guid>
		<description><![CDATA[As you are all probably already familiar with, Roger Alsing got this really really cool idea earlier this week. In short: would it be possible to construct a vector version of some image by overlaying just a few semi-transparent polygons? And if so, how do you figure out how these polygons would look like? I [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=131&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>As you are all probably already familiar with, <a href="http://rogeralsing.com">Roger Alsing</a> got this really really <a href="http://rogeralsing.com/2008/12/07/genetic-programming-evolution-of-mona-lisa/">cool idea</a> earlier this week.</p>
<p>In short: would it be possible to construct a vector version of some image by overlaying just <em><strong>a few semi-transparent polygons</strong></em>? And if so, how do you figure out how these polygons would look like?</p>
<p>I can&#8217;t figure out how he got this idea. If someone had asked me if it could be done I&#8217;m afraid I&#8217;d just answered &#8220;Heck, no. No way. No use even trying.&#8221;. Therefore; a <em><strong>brilliant </strong></em>idea I must say!</p>
<p>Some people saw it as a proof of evolution. Some people saw it as proof of creationism. Some people saw it as an image compression algorithm. Some people saw it as a cool but useless toy. I guess some other people didn&#8217;t know what to think.</p>
<p>I guess I saw it as a powerful demonstration of a technique to use when you really have no idea how to attack a really complicated problem. I wounder if someone know how to construct an algorithm that directly converges towards the desired image without using randomness? The word &#8220;tricky&#8221; really sounds like an understatement!</p>
<p>Out of curiosity, I looked at the fitness function. That is, the piece of code that tries to compare how similar/different two images are. Then I noticed that since Roger apparently had been under much pressure to reveal his quick and dirty hack to the public, he hadn&#8217;t had the time to optimize that code. So I couldn&#8217;t resist doing just that.</p>
<p>And behold: the performance increase was a whopping <em><strong>25 times</strong></em>! Yeah,a 25 time speed increase is like cruising in 50 km/h compared to breaking the sound barrier. Pretty cool, eh?</p>
<p>So, <a href="http://danbystrom.se/2008/12/14/improving-performance/">here is how I did just that</a>. <a href="http://www.vdsoft.se"><span style="color:#ffffff;">Ekeforshus</span></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/131/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=131&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2008/12/14/besserwisser-blog/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>
	</item>
		<item>
		<title>Improving performance&#8230;</title>
		<link>http://danbystrom.se/2008/12/14/improving-performance/</link>
		<comments>http://danbystrom.se/2008/12/14/improving-performance/#comments</comments>
		<pubDate>Sun, 14 Dec 2008 18:41:11 +0000</pubDate>
		<dc:creator>danbystrom</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[GDI+]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://danbystrom.se/?p=117</guid>
		<description><![CDATA[&#8230;of the fitness function in the EvoLisa project. In case you managed to miss it, EvoLisa is an already world famous project created by Roger Alsing earlier this week. Continued from this post. With just a few changes, we can actually make the original fitness function run 25 times faster. I&#8217;ll start by presenting the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=117&subd=danbystrom&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>&#8230;of the fitness function in the <a href="http://rogeralsing.com/2008/12/11/genetic-programming-mona-lisa-source-code-and-binaries/">EvoLisa</a> project. In case you managed to miss it, <a href="http://rogeralsing.com/2008/12/11/genetic-gallery/">EvoLisa</a> is an already <a href="http://rogeralsing.com/2008/12/13/this-week-on-c9-oxite-mona-lisa-pool-hacks-and-coding4fun-gifts/">world famous</a> project created by <a href="http://rogeralsing.com">Roger Alsing</a> earlier this week.</p>
<p>Continued from <a href="http://danbystrom.se/2008/12/14/besserwisser-blog/">this post</a>.</p>
<p>With just a few changes, we can actually make the original fitness function run 25 times faster. I&#8217;ll start by presenting the original code and then directly the improved version. After that I&#8217;ll discuss my reasoning behind each one of the changes.</p>
<p>Original code:</p>
<pre class="brush: csharp;">
	public static class FitnessCalculator
	{
		public static double GetDrawingFitness( DnaDrawing newDrawing, Color[,] sourceColors )
		{
			double error = 0;

			using ( var b = new Bitmap( Tools.MaxWidth, Tools.MaxHeight, PixelFormat.Format24bppRgb ) )
			using ( Graphics g = Graphics.FromImage( b ) )
			{
				Renderer.Render(newDrawing, g, 1);

				BitmapData bmd1 = b.LockBits(
					new Rectangle( 0, 0, Tools.MaxWidth, Tools.MaxHeight ),
					ImageLockMode.ReadOnly,
					PixelFormat.Format24bppRgb );

				for ( int y = 0 ; y &lt; Tools.MaxHeight ; y++ )
				{
					for ( int x = 0 ; x &lt; Tools.MaxWidth ; x++ )
					{
						Color c1 = GetPixel( bmd1, x, y );
						Color c2 = sourceColors[x, y];

						double pixelError = GetColorFitness( c1, c2 );
						error += pixelError;
					}
				}

				b.UnlockBits( bmd1 );
			}

			return error;
		}

		private static unsafe Color GetPixel( BitmapData bmd, int x, int y )
		{
			byte* p = (byte*)bmd.Scan0 + y * bmd.Stride + 3 * x;
			return Color.FromArgb( p[2], p[1], p[0] );
		}

		private static double GetColorFitness( Color c1, Color c2 )
		{
			double r = c1.R - c2.R;
			double g = c1.G - c2.G;
			double b = c1.B - c2.B;

			return r * r + g * g + b * b;
		}

	}
</pre>
<p>Optimized code, 25 times as fast:</p>
<pre class="brush: csharp;">
	public struct Pixel
	{
		public byte B;
		public byte G;
		public byte R;
		public byte A;
	}

	public class NewFitnessCalculator : IDisposable
	{
		private Bitmap _bmp;
		private Graphics _g;

		public NewFitnessCalculator()
		{
			_bmp = new Bitmap( Tools.MaxWidth, Tools.MaxHeight );
			_g = Graphics.FromImage( _bmp );
		}

		public void Dispose()
		{
			_g.Dispose();
			_bmp.Dispose();
		}

		public double GetDrawingFitness( DnaDrawing newDrawing, Pixel[] sourcePixels )
		{
			double error = 0;

			Renderer.Render(newDrawing, g, 1);

			BitmapData bd = _bmp.LockBits(
				new Rectangle( 0, 0, Tools.MaxWidth, Tools.MaxHeight ),
				ImageLockMode.ReadOnly,
				PixelFormat.Format32bppArgb );

			unchecked
			{
				unsafe
				{
					fixed ( Pixel* psourcePixels = sourcePixels )
					{
						Pixel* p1 = (Pixel*)bd.Scan0.ToPointer();
						Pixel* p2 = psourcePixels;
						for ( int i = sourcePixels.Length ; i &gt; 0 ; i--, p1++, p2++ )
						{
							int r = p1-&gt;R - p2-&gt;R;
							int g = p1-&gt;G - p2-&gt;G;
							int b = p1-&gt;B - p2-&gt;B;
							error += r * r + g * g + b * b;
						}
					}
				}
			}
			_bmp.UnlockBits( bd );

			return error;
		}

	}
</pre>
<p>First of all we notice that each time the fitness function is called, a new bitmap is constructed, used and then destroyed. This is fine for a function that seldom gets called. But for a function that is repeatedly called, we&#8217;ll be far better off if we reuse the same Bitmap and Graphics objects over and over.</p>
<p>Therefore I have changed the class from being static into one that muct be instantiated. Of course, that requires some minor changes to the consumer of this class, but in my opinion this will only be for the better. Although convenient, static methods (and/or singletons) are very hostile to unit testing and mocking, so I&#8217;m trying to move away from them anyway.</p>
<p>To my surprise, this first optimization attempt only buys us a few percent performance increase. I&#8217;m somewhat surprised at this, but anyway, it&#8217;s a start, and now it will get better. Read on.</p>
<p>So, once we&#8217;ve added a constructor to create the bitmap and graphics objects once and for all (as we&#8217;ll as making the class disposable so that the two GDI+ objects can be disposed) we move on to the real performance issues:</p>
<pre class="brush: csharp;">
	for ( int y = 0 ; y &lt; Tools.MaxHeight ; y++ )
	{
		for ( int x = 0 ; x &lt; Tools.MaxWidth ; x++ )
		{
			Color c1 = GetPixel( bmd1, x, y );
			Color c2 = sourceColors[x, y];

			double pixelError = GetColorFitness( c1, c2 );
			error += pixelError;
		}
	}
</pre>
<p>This code looks pretty innocent, eh? It is not.</p>
<p>Even for a moderately sized bitmap, say 1,000 by 1,000 pixels, the code in the inner loop is executed 1,000,000 times. Thats a pretty big number. This means that each tiny little &#8220;error&#8221;, performance-wise, is multiplied by 1,000,000 so every little tiny tiny thing will count in the end.</p>
<p>So for example, just each method call will consume time compared to having the method&#8217;s code inline within the loop. Above we find two method calls GetPixel and GetColorFitness which will be far better off moved inside the loop, but as I will end up explaining is that the worst performance hog here is really the innocent looking line &#8220;Color c2 = sourceColors[x, y];&#8221;. Anyway, off we go:</p>
<pre class="brush: csharp;">
			unchecked
			{
				unsafe
				{
					for ( int y = 0 ; y &lt; Tools.MaxHeight ; y++ )
					{
						for ( int x = 0 ; x &lt; Tools.MaxWidth ; x++ )
						{
							byte* p = (byte*)bmd1.Scan0 + y * bmd1.Stride + 3 * x;
							Color c1 = Color.FromArgb( p[2], p[1], p[0] );
							Color c2 = sourceColors[x, y];

							int R = c1.R - c2.R;
							int G = c1.G - c2.G;
							int B = c1.B - c2.B;

							error += R * R + G * G + B * B;
						}
					}
				}
			}
</pre>
<p>The above changes, including changing the variables R, G &amp; B from double into int will buy us approximately a 30% speed increase. Ain&#8217;t much compared to 25 times but still we&#8217;re moving on. Then we can look at the &#8220;Color c1&#8243; and notice that we can get rid of it completely by simply changing the inner code like so:</p>
<pre class="brush: csharp;">
			byte* p = (byte*)bmd1.Scan0 + y * bmd1.Stride + 3 * x;
			Color c2 = sourceColors[x, y];

			int R = p[2] - c2.R;
			int G = p[1] - c2.G;
			int B = p[0] - c2.B;

			error += R * R + G * G + B * B;
</pre>
<p>Now we actually have code that executes TWICE as fast as our original code. And now we must turn our attention to the first two. The rest I don&#8217;t think we can do much about.</p>
<p>Think about it. What we want to to is loop over each and every pixel in the image. Why then do we need to <em><strong>calculate </strong></em>the memory address for <em><strong>each pixel</strong></em> when we want to move to the <em><strong>next pixel</strong></em>? For each pixel we do completely unnecessary calculations. First &#8220;(byte*)bmd1.Scan0 + y * bmd1.Stride + 3 * x&#8221;; this contains four variables, two additions and two multiplications when really a single increment is all we need.</p>
<p>Then &#8220;sourceColors[x, y]&#8220;. Fast enough and nothing we can improve here, right? No, no no, this is far WORSE! It looks completely harmless, but not only is a <strong>similar formula as the previous one</strong> taking place behind the scenes; for each pixel, the <em><strong>x and y parameters are being bounds checked</strong></em>, ensuring that we do not pass illegal values to the array-lookup!!!</p>
<p>So this innocent-looking expression will cause someting like this to happen somewhere around a million times for each fitness calculation:</p>
<pre class="brush: csharp;">
			// pseudo-code
			if ( x &lt; sourceColors.GetLowerBound( 0 ) || y &lt; sourceColors.GetLowerBound( 1 ) || x &gt; sourceColors.GetUpperBound( 0 ) || y &gt; sourceColors.GetUpperBound( 1 ) )
				throw new IndexOutOfRangeException( &quot;(Index was outside the bounds of the array.&quot; );
			Color c2 = *( &amp;sourceColors + x * ( sourceColors.GetUpperBound( 1 ) + 1 ) + y );
</pre>
<p>Now we&#8217;re in for a little heavier refactoring. Unfortunately the sourcePixel matrix is laid out column-by-row instead of row-by-column which would have been better, so in order to solve this issue I&#8217;ll even change it into a vector of type &#8220;Pixel&#8221; instead. This requires change to the method signature and to the construction of the the matrix/vector itself of course, but once in place:</p>
<pre class="brush: csharp;">
			unchecked
			{
				unsafe
				{
					fixed ( Pixel* psourceColors = sourceColors )
					{
						Pixel* pc = psourceColors;
						for ( int y = 0 ; y &lt; Tools.MaxHeight ; y++ )
						{
							byte* p = (byte*)bmd1.Scan0 + y * bmd1.Stride;
							for ( int x = 0 ; x &lt; Tools.MaxWidth ; x++, p += 3, pc++ )
							{
								int R = p[2] - pc-&gt;R;
								int G = p[1] - pc-&gt;G;
								int B = p[0] - pc-&gt;B;

								error += R * R + G * G + B * B;
							}
						}
					}
				}
			}
</pre>
<p>we´re actually in for a performance improvement of 15 times!!!</p>
<p>Yeah, that&#8217;s actually how bad (performance-wise) the innocent looking line &#8220;Color c2 = sourceColors[x, y];&#8221; was. Bet some of you didn&#8217;t know that!!! <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>In order to change sourceColors from a matrix of Color into a vector of Pixel (declared as in the second code window above) I did this:</p>
<pre class="brush: csharp;">
		public static Pixel[] SetupSourceColorMatrix( Bitmap sourceImage )
		{
			if ( sourceImage == null )
				throw new NotSupportedException( &quot;A source image of Bitmap format must be provided&quot; );

			BitmapData bd = sourceImage.LockBits(
			new Rectangle( 0, 0, Tools.MaxWidth, Tools.MaxHeight ),
			ImageLockMode.ReadOnly,
			PixelFormat.Format32bppArgb );
			Pixel[] sourcePixels = new Pixel[Tools.MaxWidth * Tools.MaxHeight];
			unsafe
			{
				fixed ( Pixel* psourcePixels = sourcePixels )
				{
					Pixel* pSrc = (Pixel*)bd.Scan0.ToPointer();
					Pixel* pDst = psourcePixels;
					for ( int i = sourcePixels.Length ; i &gt; 0 ; i-- )
						*( pDst++ ) = *( pSrc++ );
				}
			}
			sourceImage.UnlockBits( bd );

			return sourcePixels;
		}
</pre>
<p>Probably a little overkill&#8230; but what the heck&#8230; Now I guess many people who are familiar with LockBits and direct pixel manipulation will cry out HEY YOU CAN&#8217;T DO THAT! YOU MUST TAKE THE &#8220;STRIDE&#8221; INTO ACCOUNT WHEN YOU MOVE TO A NEW SCAN LINE.</p>
<p>Well, yes&#8230; and no. Not when I use the PixelFormat.Format32bppArgb! Go figure! <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>So our new changes means that we process each ROW in the bitmap blindingly fast, as compared to the original version and combined with our caching of the bitmap we have gained a performance boost of 20 times!</p>
<p>Now for my final version I have rendered the drawing in PixelFormat.Format32bppArgb, which is the default format for bitmaps in GDI+. In that format each pixel will be exactly four bytes in size, which in turn means that GDI+ places no &#8220;gap&#8221; between the last pixel in one row and the first pixel in the next row and so we are actually able to treat the whole image as a single vector, processing it all in one go.</p>
<p>To conclude: in c# we can use unsafe code and pointer arithmetic to access an array far faster than the normal indexer, because we short-circuit the bounds checking. If we iterate over several consecutive elements in the array our gain is even larger, because we just increment the pointer instead of recalculating the memory address of the cells of the array over and over.</p>
<p>Normally we don&#8217;t want to bother with this because the gain of safe and managed code is bigger than the performance gain. But when it comes to image processing this perspective may not be as clear.</p>
<p>BTW, I wrote a post on a similar topic a few months ago: <a href="http://danbystrom.se/2008/08/24/soft-edged-images-in-gdi/">Soft Edged Images in GDI+</a>.</p>
<p><strong>EDIT</strong>: <a href="http://danbystrom.se/2008/12/16/optimizing-away/">Continued here</a> <a href="http://www.vdsoft.se"><span style="color:#ffffff;">Ekeforshus</span></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/danbystrom.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/danbystrom.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/danbystrom.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/danbystrom.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/danbystrom.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/danbystrom.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/danbystrom.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/danbystrom.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/danbystrom.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/danbystrom.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/danbystrom.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/danbystrom.wordpress.com/117/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/danbystrom.wordpress.com/117/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/danbystrom.wordpress.com/117/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=danbystrom.se&blog=2755780&post=117&subd=danbystrom&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://danbystrom.se/2008/12/14/improving-performance/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d518503a8b459ab2066d1623872e94bd?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">danbystrom</media:title>
		</media:content>
	</item>
	</channel>
</rss>