<?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>I _Really_ Don&#039;t Know &#187; .Net Technical</title>
	<atom:link href="http://dynamicorange.com/category/net-technical/feed/" rel="self" type="application/rss+xml" />
	<link>http://dynamicorange.com</link>
	<description>A low-frequency blog by Rob Styles</description>
	<lastBuildDate>Mon, 11 Apr 2011 09:43:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Random NUnit Tip</title>
		<link>http://dynamicorange.com/2004/06/02/random-nunit-tip/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=random-nunit-tip</link>
		<comments>http://dynamicorange.com/2004/06/02/random-nunit-tip/#comments</comments>
		<pubDate>Wed, 02 Jun 2004 14:48:52 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[.Net Technical]]></category>

		<guid isPermaLink="false">http://dynamicorange.com/wpblog/2004/06/02/random-nunit-tip/</guid>
		<description><![CDATA[Often when writing NUnit tests I find myself wanting to output some stuff to the Console in order to make sense of a failing test. But, you don&#8217;t want the console window filling up with rubbish when the test is &#8230; <a href="http://dynamicorange.com/2004/06/02/random-nunit-tip/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Often when writing NUnit tests I find myself wanting to output some stuff to the Console in order to make sense of a failing test. But, you don&#8217;t want the console window filling up with rubbish when the test is passing, so instead of doing this&#8230;</p>
<div class="code">
[Test]<br />
public void DoesSomething()<br />
{<br />
string expected = &#8220;some expected result&#8221;;<br />
object someObject = new SomeObject();<br />
string actual = someObject.DoesSomething();<br />
Console.WriteLine(expected);<br />
Console.WriteLine(&#8220;&#8212;-&#8221;);<br />
Console.WriteLine(actual);<br />
AssertEquals(&#8220;SomeObject should do something&#8221;, expected, actual);<br />
}
</div>
<p>you can do this&#8230;</p>
<div class="code">
[Test]<br />
public void DoesSomething()<br />
{<br />
string expected = &#8220;some expected result&#8221;;<br />
object someObject = new SomeObject();<br />
string actual = someObject.DoesSomething();<br />
try<br />
{<br />
AssertEquals(&#8220;SomeObject should do something&#8221;, expected, actual);<br />
}<br />
catch(AssertionException)<br />
{<br />
Console.WriteLine(expected);<br />
Console.WriteLine(&#8220;&#8212;-&#8221;);<br />
Console.WriteLine(actual);<br />
throw;<br />
}<br />
}
</div>
<p>Then the Console output only shows up when the test fails. Nice.</p>
]]></content:encoded>
			<wfw:commentRss>http://dynamicorange.com/2004/06/02/random-nunit-tip/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Excel&#8230;lent</title>
		<link>http://dynamicorange.com/2004/04/18/excellent/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=excellent</link>
		<comments>http://dynamicorange.com/2004/04/18/excellent/#comments</comments>
		<pubDate>Sun, 18 Apr 2004 20:46:31 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[.Net Technical]]></category>

		<guid isPermaLink="false">http://dynamicorange.com/wpblog/2004/04/18/excellent/</guid>
		<description><![CDATA[Generating an Excel file from .Net should be easy right? MS have good reason to have you using their formats as the de-facto standard and make it easy, huh. Nope. Not really. It&#8217;s a bit trickier than you might think. &#8230; <a href="http://dynamicorange.com/2004/04/18/excellent/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Generating an Excel file from .Net should be easy right? MS have good reason to have you using their formats as the de-facto standard and make it easy, huh.</p>
<p>Nope. Not really.</p>
<p>It&#8217;s a bit trickier than you might think.</p>
<p><span id="more-48"></span><br />
Obviously with Office XP onwards, Excel supports XML and rendering the workbook as xml is fairly trivial, but I want to support aged machines running Excel 97. This means the BIFF binary format.</p>
<p>Starting with MSDN you find the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnoxpta/html/odc_oxppias.asp">obvious articles on using the Office Primary Interop Assemblies</a> to interact with the Excel object model and create a workbook that way. <a href="http://www.google.com/search?num=50&#038;hl=en&#038;lr=lang_en&#038;ie=UTF-8&#038;oe=UTF-8&#038;newwindow=1&#038;safe=off&#038;q=excel+generate+c%23+code+tlbimp">Other articles out on the web suggest creating your own interop assemblies</a>&#8230; Good Plan. I wonder why MS went to all the trouble of writing the PIAs then?</p>
<p>The PIA approach works and the code is simple enough, but because it&#8217;s COM Interop you get objects passed back out rather than the types you want, which means you have to cast stuff to what you&#8217;re expecting. This makes the code messier to read, it&#8217;s distracting and more importantly it moves type checking from a compile time task to a runtime task making it harder to find bugs.</p>
<p>The big issue, though, is performance. The interop is slow. My tests tasks were to produce a roughly 100 line spreadsheet with some basic formatting of just a few cells and then write it out to disk. That shouldn&#8217;t take more than oooh, TWENTY ONE SECONDS :-O and that&#8217;s after I&#8217;ve taken out the seven seconds it takes to construct the Excel object.</p>
<p>There has to be a better way, or even just another way! Which, of course, there is.</p>
<p>There are a handful of commercial products:</p>
<p><a href="http://www.aspose.com/">Aspose.Excel</a>;<br />
<a href="http://www.syncfusion.com/">SyncFusion&#8217;s ExcelRW</a>;<br />
<a href="http://www.softartisans.com/">SoftArtisan&#8217;s ExcelWriter5</a>.<br />
to name just the ones I shortlisted.</p>
<p>And they are all pretty good. There are performance differences, with Syncfusion coming in at around one second to generate the test workbook and Aspose.Excel coming in fastest at 91mS with very little variation.</p>
<p>But some of the programming interfaces are quirky. ExcelWriter exposes a whole load of interesting stuff when referenced, such as a load of nums all starting with __MIDL and a load of com.sun.java.collections classes that suggest it wasn&#8217;t written entirely for .Net.</p>
<p>Again, Aspose worked the best for me as they chose to index the sheet, row, column and cell indices from 0, yep zero, just like everything else in C#. Syncfusion, on the other hand indexed them all from 1. :-/</p>
<p>But I&#8217;m still looking for a good free, open-source, C# implementation to use. I found a <a href="http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=2246&#038;lngWId=10">little VB6 version, ported to VB.Net</a> on Planet Source Code, but it isn&#8217;t very well written; it swallows exceptions and one or two other things. It also exposes the details of BIFF8 format a little too literally for my liking. Oh, and I couldn&#8217;t get it to do formatting, but that&#8217;s probably just me being dumb.</p>
<p>So, for the project I&#8217;m on we&#8217;ll probably buy one, but maybe I should offer some time to <a href="http://sourceforge.net/projects/koogra/">koogra</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://dynamicorange.com/2004/04/18/excellent/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jet Brains ReSharper</title>
		<link>http://dynamicorange.com/2004/02/25/jet-brains-resharper/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=jet-brains-resharper</link>
		<comments>http://dynamicorange.com/2004/02/25/jet-brains-resharper/#comments</comments>
		<pubDate>Wed, 25 Feb 2004 13:02:42 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[.Net Technical]]></category>

		<guid isPermaLink="false">http://dynamicorange.com/wpblog/2004/02/25/jet-brains-resharper/</guid>
		<description><![CDATA[Another C# refactoring tool crossed my browser windows today&#8230; JetBrains ReSharper The Jetbrains C# plugin for Visual Studio EAP program is open: http://www.jetbrains.net/resharper The username and password are both &#8216;eapuser&#8217;. I haven&#8217;t tried it yet.]]></description>
			<content:encoded><![CDATA[<p>Another C# refactoring tool crossed my browser windows today&#8230;</p>
<p>JetBrains ReSharper The Jetbrains C# plugin for Visual Studio EAP program is open: http://www.jetbrains.net/resharper The username and password are both &#8216;eapuser&#8217;.</p>
<p>I haven&#8217;t tried it yet.</p>
]]></content:encoded>
			<wfw:commentRss>http://dynamicorange.com/2004/02/25/jet-brains-resharper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building a simple CMS XML Placeholder</title>
		<link>http://dynamicorange.com/2004/02/12/building-a-simple-cms-xml-placeholder/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=building-a-simple-cms-xml-placeholder</link>
		<comments>http://dynamicorange.com/2004/02/12/building-a-simple-cms-xml-placeholder/#comments</comments>
		<pubDate>Thu, 12 Feb 2004 20:19:11 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[.Net Technical]]></category>

		<guid isPermaLink="false">http://dynamicorange.com/wpblog/2004/02/12/building-a-simple-cms-xml-placeholder/</guid>
		<description><![CDATA[I&#8217;ve just been down to see some guys in the middle of nowhere&#8230; Beautiful little office on a deer park, with views over fields and so incredibly quiet. A company called Torchbox who are getting up-to-speed with MS CMS. While &#8230; <a href="http://dynamicorange.com/2004/02/12/building-a-simple-cms-xml-placeholder/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just been down to see some guys in the middle of nowhere&#8230; Beautiful little office on a deer park, with views over fields and so incredibly quiet. A company called Torchbox who are getting up-to-speed with MS CMS.</p>
<p>While I was there the big question was why one of their placeholders wasn&#8217;t working, which I think we figured, but I also put together a very basic XML Placeholder control to act as a base for them. I thought it would be worth dropping it up here for the record.</p>
<p><span id="more-28"></span></p>
<div class="code">
using Microsoft.ContentManagement.Publishing.Extensions.Placeholders;<br />
using Microsoft.ContentManagement.WebControls;<br />
using System.Web;<br />
using System.Web.UI.WebControls;</p>
<p>namespace Foo.ContentManagementServer.Extensions<br />
{<br />
public class SimpleXmlPlaceholderControl : BasePlaceholderControl<br />
{<br />
public SimpleXmlPlaceholderControl()<br />
{<br />
EnableViewState = false;<br />
}</p>
<p>protected Literal PresentationControl;<br />
protected TextBox AuthoringControl;</p>
<p>protected XmlPlaceholder BoundXmlPlaceholder<br />
{<br />
get<br />
{<br />
return BoundPlaceholder as XmlPlaceholder;<br />
}<br />
}</p>
<p>protected override void CreatePresentationChildControls(<br />
BaseModeContainer presentationContainer)<br />
{<br />
PresentationControl = new Literal();<br />
PresentationControl.ID = &#8220;PresentationControl&#8221;;<br />
Controls.Add(PresentationControl);<br />
}</p>
<p>protected override void CreateAuthoringChildControls(<br />
BaseModeContainer authoringContainer)<br />
{<br />
AuthoringControl = new TextBox();<br />
AuthoringControl.ID = &#8220;AuthoringControl&#8221;;<br />
Controls.Add(AuthoringControl);<br />
}</p>
<p>protected override void LoadPlaceholderContentForPresentation(<br />
PlaceholderControlEventArgs e)<br />
{<br />
EnsureChildControls();<br />
PresentationControl.Text = HttpUtility.HtmlEncode(<br />
BoundXmlPlaceholder.XmlAsString);<br />
}</p>
<p>protected override void LoadPlaceholderContentForAuthoring(<br />
PlaceholderControlEventArgs e)<br />
{<br />
EnsureChildControls();<br />
AuthoringControl.Text = BoundXmlPlaceholder.XmlAsString;<br />
}</p>
<p>protected override void SavePlaceholderContent(<br />
PlaceholderControlSaveEventArgs e)<br />
{<br />
EnsureChildControls();<br />
BoundXmlPlaceholder.XmlAsString = AuthoringControl.Text;<br />
}<br />
}<br />
}
</p></div>
<p><a href="http://www.dynamicorange.com/blog/archives/code/SimpleXmlPlaceholderControl.cs">Download file</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dynamicorange.com/2004/02/12/building-a-simple-cms-xml-placeholder/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XP Toolset for .Net</title>
		<link>http://dynamicorange.com/2003/08/25/xp-toolset-for-net/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=xp-toolset-for-net</link>
		<comments>http://dynamicorange.com/2003/08/25/xp-toolset-for-net/#comments</comments>
		<pubDate>Mon, 25 Aug 2003 12:58:23 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[.Net Technical]]></category>

		<guid isPermaLink="false">http://dynamicorange.com/wpblog/2003/08/25/xp-toolset-for-net/</guid>
		<description><![CDATA[We&#8217;ve started doing TDD and Continuous Integration a bit more formally and have brought together a toolset to support this on the .Net platform. For reference this is currently: Visual Studio.Net &#8211; IDE Visual SourceSafe &#8211; Configuration Management nUnit &#8211; &#8230; <a href="http://dynamicorange.com/2003/08/25/xp-toolset-for-net/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve started doing TDD and Continuous Integration a bit more formally and have brought together a toolset to support this on the .Net platform. For reference this is currently:</p>
<p>Visual Studio.Net &#8211; IDE<br />
Visual SourceSafe &#8211; Configuration Management<br />
nUnit &#8211; Unit Test Framework<br />
CruiseControl.Net &#8211; Continuous Integration Process<br />
nAnt &#8211; .Net Build Tool<br />
FXCop &#8211; Coding Standards validator<br />
DevPartner Profiler &#8211; Performance Analysis and Test Coverage</p>
]]></content:encoded>
			<wfw:commentRss>http://dynamicorange.com/2003/08/25/xp-toolset-for-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Morgan&#039;s Images</title>
		<link>http://dynamicorange.com/2003/05/25/morgans-images/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=morgans-images</link>
		<comments>http://dynamicorange.com/2003/05/25/morgans-images/#comments</comments>
		<pubDate>Sun, 25 May 2003 12:59:05 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[.Net Technical]]></category>

		<guid isPermaLink="false">http://dynamicorange.com/wpblog/2003/05/25/morgans-images/</guid>
		<description><![CDATA[Morgan Skinner&#8217;s written up some nice stuff on color quantization, mapping using both a palette based approach and an octree based algorithm which is also very nice. This follows on from work I did with him back in 2002, and &#8230; <a href="http://dynamicorange.com/2003/05/25/morgans-images/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/colorquant.asp">Morgan Skinner&#8217;s written up some nice stuff on color quantization</a>, mapping using both a palette based approach and an octree based algorithm which is also very nice.</p>
<p>This follows on from <a href="http://www.dynamicorange.com/blog/archives/000029.html">work I did with him back in 2002</a>, and adds to it.</p>
]]></content:encoded>
			<wfw:commentRss>http://dynamicorange.com/2003/05/25/morgans-images/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dynamic Image Generation</title>
		<link>http://dynamicorange.com/2002/05/22/dynamic-image-generation/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=dynamic-image-generation</link>
		<comments>http://dynamicorange.com/2002/05/22/dynamic-image-generation/#comments</comments>
		<pubDate>Wed, 22 May 2002 12:48:58 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[.Net Technical]]></category>

		<guid isPermaLink="false">http://dynamicorange.com/wpblog/2002/05/22/dynamic-image-generation/</guid>
		<description><![CDATA[The .Net Framework has, like many frameworks and class libraries before it, some natty little features for drawing images and for saving or streaming them in different formats. As part of getting to grips with C# I decided to put &#8230; <a href="http://dynamicorange.com/2002/05/22/dynamic-image-generation/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The .Net Framework has, like many frameworks and class libraries before it, some natty little features for drawing images and for saving or streaming them in different formats.</p>
<p>As part of getting to grips with C# I decided to put together some image generation routines for web based buttons, but discovered that it was not all as simple as it should be.</p>
<p><span id="more-14"></span><br />
The main problem lies here: There are two types of image format relevant to this problem &#8211; 8 bit per pixel (8bpp) images, these use a palette of colors and each pixels byte of data is an index into that palette, hence the 256 color limit; the other type is a true color image at either 24bpp (RGB) or 32bpp (ARGB).</p>
<p><img alt="Diagram of 8 bit per pixel palette based image" src="http://www.dynamicorange.com/blog/archives/diagrams/images/8bpp-palette-image.gif" width="300" height="100" border="0" /><br />
Diagram of 8 bit per pixel palette based image</p>
<p><img alt="Diagram of 24 bit per pixel true color image" src="http://www.dynamicorange.com/blog/archives/diagrams/images/24bpp-truecolor-image.gif" width="350" height="100" border="0" /><br />
Diagram of 24 bit per pixel true color image</p>
<p>The limitation is this &#8211; you can get a drawing context and, therefore, draw onto a true color image but you cannot draw onto an indexed image; you can save an indexed image as a gif with a custom palette, but a true color image is always dithered to the web palette for you.</p>
<p>As I want to use large blocks of solid colors that are not in the web palette I&#8217;m left with two choices&#8230; Jpeg, and have the jpeg artefacts visible on the image or gif and dither to the web palette, neither of which is acceptable.</p>
<p><img alt="Nice logo, showing the brand compliant and very lovely jpeg artefacts." src="http://www.dynamicorange.com/blog/archives/diagrams/images/logo-with-visible-jpeg-arte.jpg" width="300" height="100" border="0" /><br />
Nice logo, showing the brand compliant and very lovely jpeg artefacts.</p>
<p><img alt="Nice logo, showing the rather attractive standard pattern dither to web palette." src="http://www.dynamicorange.com/blog/archives/diagrams/images/logo-with-visible-pattern-d.gif" width="300" height="100" border="0" /><br />
Nice logo, showing the rather attractive standard pattern dither to web palette.</p>
<p>This could be solved, you might think, by streaming them out as PNG format images. There&#8217;s a little bug in doing that though, you end up with an undefined GDI+ exception. After a little digging I found that the GDI libraries for PNG don&#8217;t like the network stream, so you have to use a memory stream instead.</p>
<div class="code">
using System.Drawing.Imaging;<br />
using System.IO;</p>
<p>public void StreamImage(System.Web.HttpResponse Response)<br />
{<br />
Response.ContentType = &#8220;image/png&#8221;;<br />
MemoryStream memoryStream = new MemoryStream();<br />
yourBitmap.Save(memoryStream, ImageFormat.Png);<br />
memoryStream.WriteTo(Response.OutputStream);<br />
}
</p></div>
<p>But I was disappointed with this, as often the background colors on the images, which should match the HTML background color of a CSS style were being rendered differently by the browser despite them being the same RGB value when checked with Photoshop.</p>
<p>So, GIF it has to be.</p>
<p>The end result is to use two bitmaps &#8211; one at 24 or 32 bpp to draw your image onto and then a second 8bpp bitmap the same size, with your chosen palette. I call these the canvas and the output respectively. You have to copy one to the other before streaming out the final image.</p>
<p>The algorithm I started with simply used GetPixel and SetPixel to iterate through the two bitmaps, but it became very obvious that the interop code between .net and GDI+ was not going to cope with that. A simple, 200&#215;200 square image was taking several seconds to map.</p>
<p>A fiddle with unsafe code and pointers was needed and resulted, after much optimisation, in this.</p>
<div class="code">
private void CopyCanvasToOutput(Bitmap canvasBitmap,<br />
Bitmap outputBitmap)<br />
{<br />
BitmapData canvasData = LockBitmap(canvasBitmap);<br />
try<br />
{<br />
BitmapData outputData = LockBitmap(outputBitmap);<br />
try<br />
{<br />
// Get the height and width of the image in pixels<br />
GraphicsUnit unit = GraphicsUnit.Pixel;<br />
RectangleF bounds = canvasBitmap.GetBounds(ref unit);<br />
int sizeX = (int) bounds.Width;<br />
int sizeY = (int) bounds.Height;</p>
<p>// Get some pointers to the data in memory<br />
Byte* pOutputBase = (Byte*) outputData.Scan0.ToPointer();<br />
Byte* pCanvasBase = (Byte*) canvasData.Scan0.ToPointer();<br />
Byte* pOutputRow = pOutputBase;<br />
Byte* pCanvasRow = pCanvasBase;<br />
PixelDataFor8bppIndexed* pOutputPixel;<br />
PixelDataFor32bppARGB* pCanvasPixel =<br />
(PixelDataFor32bppARGB*) pCanvasBase;<br />
PixelDataFor32bppARGB* pPreviousCanvasPixel =<br />
(PixelDataFor32bppARGB*) pCanvasBase;</p>
<p>// Get the closest colour of the first pixel.<br />
int paletteIndex = ClosestMatch(pCanvasPixel);</p>
<p>// Loop through each row<br />
for (int y = 0; y < sizeY; y++)<br />
{<br />
// Set the current pixels to the start of the row<br />
pOutputPixel = (PixelDataFor8bppIndexed*) pOutputRow;<br />
pCanvasPixel = (PixelDataFor32bppARGB*) pCanvasRow;</p>
<p>// Loop through each column<br />
for (int x = 0; x < sizeX; x++, pOutputPixel++, pCanvasPixel++)<br />
{<br />
if (*((int*) pPreviousCanvasPixel) != *((int*) pCanvasPixel))<br />
{<br />
// If the current pixel is different to<br />
// the previous pixel then find the closest<br />
// match and remember where we were.<br />
paletteIndex = ClosestMatch(pCanvasPixel);<br />
pPreviousCanvasPixel = pCanvasPixel;<br />
}<br />
pOutputPixel->Index = (Byte) paletteIndex;<br />
}</p>
<p>// Increment the row pointers by<br />
// the byte length of a row (Stride)<br />
pOutputRow += outputData.Stride;<br />
pCanvasRow += canvasData.Stride;<br />
}<br />
}<br />
finally<br />
{<br />
outputBitmap.UnlockBits(outputData);<br />
}<br />
}<br />
finally<br />
{<br />
canvasBitmap.UnlockBits(canvasData);<br />
}<br />
}</p>
<p>private BitmapData LockBitmap(Bitmap bitmapToLock)<br />
{<br />
GraphicsUnit unit = GraphicsUnit.Pixel;<br />
RectangleF boundsF = canvasBitmap.GetBounds(ref unit);<br />
Rectangle bounds = new Rectangle((int) boundsF.X,<br />
(int) boundsF.Y,<br />
(int) boundsF.Width,<br />
(int) boundsF.Height);<br />
return bitmapToLock.LockBits(bounds,<br />
ImageLockMode.ReadOnly,<br />
bitmapToLock.PixelFormat);<br />
}</p>
<p>[StructLayout(LayoutKind.Sequential)]<br />
private struct PixelDataFor32bppARGB<br />
{<br />
//in memory byte sequence is BGRA, i.e. backwards.<br />
public byte blue;<br />
public byte green;<br />
public byte red;<br />
public byte alpha;<br />
}</p>
<p>[StructLayout(LayoutKind.Sequential)]<br />
private struct PixelDataFor8bppIndexed<br />
{<br />
public byte Index;<br />
}
</p></div>
<p>Color matching was also a challenge as copying from true color to a palette you have to match RGB values to the closest entry in the palette. The algorithm I&#8217;ve produced doesn&#8217;t do any dithering or anything as the intention was to avoid any pattern or diffusion, and just map to the closest colors.</p>
<div class="code">
private static Hashtable _paletteHashtable = new Hashtable();</p>
<p>private int ClosestMatch(PixelDataFor32bppARGB* pCanvasPixel)<br />
{<br />
byte alpha = pCanvasPixel->alpha;<br />
byte red = pCanvasPixel->red;<br />
byte green = pCanvasPixel->green;<br />
byte blue = pCanvasPixel->blue;</p>
<p>int index = 0;</p>
<p>// Check the alpha<br />
if (alpha < 128)<br />
{<br />
index = 255;<br />
}<br />
else<br />
{<br />
// Look for an exact match<br />
int key = alpha << 24 | red << 16 | green << 8 | blue;<br />
Object paletteValue = _paletteHashtable[key];<br />
if (paletteValue != null)<br />
{<br />
index = (int) paletteValue;<br />
}<br />
else<br />
{<br />
// Look for a closest match<br />
int redDistance;<br />
int greenDistance;<br />
int blueDistance;<br />
int totalDistance;<br />
int minDistance = int.MaxValue;<br />
int loopIndex = 0;<br />
foreach (Color color in outputBitmap.Palette.Entries)<br />
{<br />
redDistance = color.R - red;<br />
greenDistance = color.G - green;<br />
blueDistance = color.B - blue;<br />
// The squaring done here allows us to attach<br />
// more importance to values further away.<br />
totalDistance = (redDistance * redDistance) +<br />
(greenDistance * greenDistance) +<br />
(blueDistance * blueDistance);<br />
if (totalDistance < minDistance)<br />
{<br />
minDistance = totalDistance;<br />
index = loopIndex;<br />
}<br />
loopIndex++;<br />
}<br />
// Add it to the _paletteHashtable<br />
// lock it first and test in case anyone else<br />
// added the index to _paletteHashtable while<br />
// we were still computing the closest match.<br />
lock (_paletteHashtable)<br />
{<br />
if (!_paletteHashtable.ContainsKey(key))<br />
{<br />
_paletteHashtable.Add(key, index);<br />
}<br />
}<br />
}<br />
}<br />
return index;<br />
}
</div>
]]></content:encoded>
			<wfw:commentRss>http://dynamicorange.com/2002/05/22/dynamic-image-generation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>.Net Reflector</title>
		<link>http://dynamicorange.com/2002/03/06/net-reflector/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=net-reflector</link>
		<comments>http://dynamicorange.com/2002/03/06/net-reflector/#comments</comments>
		<pubDate>Wed, 06 Mar 2002 12:44:15 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[.Net Technical]]></category>

		<guid isPermaLink="false">http://dynamicorange.com/wpblog/2002/03/06/net-reflector/</guid>
		<description><![CDATA[Morgan Skinner put me onto a very nice little toy today called .Net Reflector. Basically, it uses reflection to scan through assemblies and list the namespaces, classes, methods and properties therein. Incredibly useful for scanning through the framework classes and &#8230; <a href="http://dynamicorange.com/2002/03/06/net-reflector/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Morgan Skinner put me onto a very nice little toy today called .Net Reflector.</p>
<p>Basically, it uses reflection to scan through assemblies and list the namespaces, classes, methods and properties therein. Incredibly useful for scanning through the framework classes and finding the bits you need.</p>
<p><a href="http://aisto.com/roeder/">http://aisto.com/roeder/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dynamicorange.com/2002/03/06/net-reflector/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

