<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www.atalasoft.com/cs/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Steve's Tech Talk</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/default.aspx</link><description>Ruminations on technology, software and philosophy.
</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Why It Helps to Understand Pixel Formats</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx</link><pubDate>Tue, 16 Mar 2010 15:53:27 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:20343</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/20343.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=20343</wfw:commentRss><description>&lt;p&gt;A pixel format in dotImage is a description of the depth, color space and layout of the memory used to represent a pixel.&amp;#160; Mathematically, there are an infinite number of possible pixel formats as color space is as much a space as Cartesian space.&amp;#160; You can create any number of &lt;a href="http://en.wikipedia.org/wiki/Basis_%28linear_algebra%29"&gt;basis sets&lt;/a&gt; that map onto any particular color space.&amp;#160; However, only a small subset are actually useful.&amp;#160; In dotImage we represent 12 formats, 3 paletted, 3 gray, and the rest color.&lt;/p&gt;  &lt;p&gt;It helps to understand the meaning of pixel formats in terms of &lt;strong&gt;&lt;em&gt;quantity&lt;/em&gt;&lt;/strong&gt; of information rather than quality of information.&amp;#160; Having this understanding will help you in avoiding possible problems when processing images or converting from one format to another.&lt;/p&gt;  &lt;p&gt;All ImageCommand classes in dotImage advertise a list of all PixelFormats that they operate in.&amp;#160; The property SupportedPixelFormats gives you this list.&amp;#160; You can also call IsPixelFormatSupported() to ask if a specific format is supported.&lt;/p&gt;  &lt;p&gt;I would like to say that IsPixelFormatSupported returns true if and only if an ImageCommand natively supports a given PixelFormat.&amp;#160; In most cases this is true, but some older commands (before I got my hands on them) were written to operate on some formats as a convenience, but without letting the caller know.&amp;#160; They still behave exactly as before for compatibility.&amp;#160; ScribbleCommand is an example of this – it will strip out the alpha channel into a temporary image, before performing the operation.&lt;/p&gt;  &lt;p&gt;What is true, is that every implementation of SupportedPixelFormats will return the “best” pixel format for the command as the first entry in the list.&amp;#160; This is by convention, but we enforce it strictly.&amp;#160; There’s a reason for this: all ImageCommands have the ability to operate on any pixel format.&amp;#160; This is done by setting the property ApplyToAnyPixelFormat to true.&amp;#160; Then, when the command is executed, if the source image is not in SupportedPixelFormats, the command will create a new version of the image in a better PixelFormat for the command.&amp;#160; This is done internally by the command by calling SelectBestAlternatePixelFormat.&amp;#160; The default implementation is to return the 0th entry in SupportedPixelFormats.&lt;/p&gt;  &lt;p&gt;In short, if ApplyToAnyPixelFormat is true, the command will create a new image in the pixel format SupportedPixelFormats[0].&amp;#160; The default value for ApplyToAnyPixelFormat is false.&lt;/p&gt;  &lt;p&gt;Wait a minute – this sounds like a tremendously useful feature!&amp;#160; Why would we have it off by default?&lt;/p&gt;  &lt;p&gt;There are two reasons: (1) backwards compatibility – where possible we try to assure that all commands in new versions of dotImage operate as they did in the past. (2) “Do No Harm” – changing the PixelFormat of an image may be a lossy operation.&amp;#160; If the amount of information in the source image’s pixel format is greater than the amount of information in the target pixel format, then information has to be discarded in the translation.&amp;#160; How that information is discarded makes all the difference in the world, and the choice that is made should be dependent on the source image domain.&amp;#160; That is, if the image is a photograph, you should use one technique (dithering or another type of halftoning) and if it is a document, you should use another (dynamic or adaptive threshold).&lt;/p&gt;  &lt;p&gt;When ApplyToAnyPixelFormat is turned on, ImageCommands will use AtalaImage.GetChangedPixelFormat() to create the new image.&amp;#160; By default (and again, to match legacy behavior), when dotImage reduces a image to 1-bit per pixel, it uses either dithering or color quantization to generate the target image.&amp;#160; This is fine for photographic images, but lousy for documents.&amp;#160; Fortunately, &lt;a href="http://www.atalasoft.com/cs/blogs/stevehawley/archive/2006/06/05/10102.aspx"&gt;you can change how this change will happen&lt;/a&gt;.&amp;#160; &lt;/p&gt;  &lt;p&gt;How can I know if changing a pixel format would be lossy?&lt;/p&gt;  &lt;p&gt;You can do that by comparing the number of bits per pixel:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; IsPixelFormatChangeLossy(PixelFormat source, PixelFormat target)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; PixelFormatUtilities.BitsPerPixel(source) &amp;gt;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        PixelFormatUtilities.BitsPerPixel(target);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;and while the accuracy of this predicate is arguable, it will be good enough for most cases.&amp;#160; For the nit pickers, conversion from color to 8 or 16 bpp gray, while lossy is well-defined enough to let it go – although you should be aware that the color conversion is done through a &lt;a href="http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/01/25/never-forget-floating-point-sucks.aspx"&gt;perceptual model&lt;/a&gt;, rather than a linear model.&amp;#160; Also, conversions of 24 bit color to 8 bit paletted may be lossless in some cases, but that is more computationally and memory intensive than I’d like to put in such a simple predicate.&lt;/p&gt;

&lt;p&gt;As a side node, PixelFormatUtilities is my favorite grab bag of useful functions and predicates based around PixelFormats.&amp;#160; They are akin to the functions in the C routines defined in ctype.h in that they are almost always table driven and operate in constant time.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx&amp;amp;;subject=Why+It+Helps+to+Understand+Pixel+Formats" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx&amp;amp;;title=Why+It+Helps+to+Understand+Pixel+Formats" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx&amp;amp;title=Why+It+Helps+to+Understand+Pixel+Formats" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx&amp;amp;;title=Why+It+Helps+to+Understand+Pixel+Formats" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx&amp;amp;;title=Why+It+Helps+to+Understand+Pixel+Formats&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/16/why-it-helps-to-understand-pixel-formats.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=20343" width="1" height="1"&gt;</description></item><item><title>When Optimization Pays Off</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx</link><pubDate>Fri, 12 Mar 2010 21:38:48 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:20331</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/20331.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=20331</wfw:commentRss><description>&lt;blockquote&gt;   &lt;p&gt;“&lt;strong&gt;We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil&lt;/strong&gt;” – Don Knuth&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If you are doing image processing, you are firmly in that remaining 3%.&amp;#160; I had some code that I had factored into two major cases: 1 bit per pixel and n bits per pixel (where n is a multiple of 8).&amp;#160; Each chunk of code was more or less parallel in that it did something along the lines of this:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; PredicateInRow(BYTE *imagePtr, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; x, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; bytesPerPixel, fPredicate predicate, &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; *predicateData)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    BYTE *pixelPtr = imagePtr + x * bytesPerPixel;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; predicate(pixelPtr, bytesPerPixel, predicateData);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ProcessRange(BYTE *imagePtr, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; height, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; width, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; bytesPerPixel, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; bytesPerRow, fPredicate predicate, &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; *predicateData)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; y=0; y &amp;lt; height; y++) {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; x=0; x &amp;lt; width; x++) {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (PredicateInRow(imagePtr, x, bytesPerPixel, predicate, predicateData)) {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#008000;"&gt;// perform processing&lt;/span&gt;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        imagePtr += bytesPerRow;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;This does some image processing across the whole image based on a predicate using the current pixel’s data.&amp;#160; The predicate has to be vectored out to other code instead of being done inline (technically, there are other ways I can do this, but way of doing it avoids a lot of duplication of effort).&amp;#160; I liked the factoring in that it made the code fairly easy to read, but I knew when I wrote it that I would regret this decision.&lt;/p&gt;

&lt;p&gt;After noting that client code of this routine was slower than I preferred it to be, I fired up a profiler and found that PredicateInRow was chewing up a fair amount of the total time and it was being called 50 million times over the comparatively short life of my test application.&lt;/p&gt;

&lt;p&gt;I refactored it to this instead:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ProcessRange(BYTE *imagePtr, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; height, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; width, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; bytesPerPixel, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; bytesPerRow, fPredicate predicate, &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; *predicateData)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; y=0; y &amp;lt; height; y++) {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        BYTE *pixelPtr = imagePtr;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; x=0; x &amp;lt; width; x++) {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (predicate(pixelPtr, bytesPerPixel, predicateData)) {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#008000;"&gt;// perform processing&lt;/span&gt;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            pixelPtr += bytesPerPixel;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        imagePtr += bytesPerRow;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;I’ve now lost the PredicateInRow routine, took a hit in readability but the code runs &lt;strong&gt;twice as fast&lt;/strong&gt; now that I eliminated 50 million function calls and 50 million multiplies.&lt;/p&gt;

&lt;p&gt;I should note that I tried inlining PredicateInRow which resulted in a negligible increase in performance.&amp;#160; In my actual code, the structure of ProcessRange is much more complex – there are three small state machines that run inside of the y-based for loop and each state machine ended up looking at rows above and below in addition to the current row.&amp;#160; The refactoring was more complicated than the example above, which resulted in two bugs, both of which I found by reading the code closely.&lt;/p&gt;

&lt;p&gt;The code of a multiply is tiny, but when you multiply it by 50 million, it becomes significant.&amp;#160; When I wrote this, I &lt;em&gt;knew&lt;/em&gt; that the per-pixel accessing was going to slow it down.&amp;#160; Nonetheless, I took the high road of “make it work, then make it fast(er)”.&lt;/p&gt;

&lt;p&gt;If need be, I will change the code the work with specific byte per pixel values, removing the predicate call entirely, but that will take a 2x duplication of code (1-bit and n-bit) and turn it into a pentiplication (1 bit, 8 bit, 16 bit, 24 bit, 32 bit)&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx&amp;amp;;subject=When+Optimization+Pays+Off" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx&amp;amp;;title=When+Optimization+Pays+Off" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx&amp;amp;title=When+Optimization+Pays+Off" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx&amp;amp;;title=When+Optimization+Pays+Off" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx&amp;amp;;title=When+Optimization+Pays+Off&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/12/when-optimization-pays-off.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=20331" width="1" height="1"&gt;</description></item><item><title>Solving Problems, aka, Nobody Codes Like This Anymore</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx</link><pubDate>Wed, 10 Mar 2010 22:04:24 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:20315</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/20315.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=20315</wfw:commentRss><description>&lt;p&gt;When I was in college, I had a class in machine architecture/assembly language.&amp;#160; At the time that I took it, I knew 6502 already and had published two video games for the Apple II written entirely in assembly.&amp;#160; I love the drunken power of having access to the entire machine and making it do things it wasn’t precisely designed for – so the class was easy to me.&amp;#160; We started off with a fake Von Neumann architecture machine called MANIAC.&amp;#160; MANIAC was a basic accumulator-model machine – not too different from the 6502, so coding for it was familiar ground.&lt;/p&gt;  &lt;p&gt;We then transitioned to VAX assembly and were writing code to run directly on the machine.&amp;#160; Compared to the barren wasteland of 6502, VAX was like stepping into Paris.&amp;#160; 16 registers?&amp;#160; What the hell am I going to do with them all?&amp;#160; Multiply?&amp;#160; Divide?&amp;#160; Floating point?&amp;#160; SOBGTR (subtract one and branch on greater)?&amp;#160; There was even an instruction to insert into a queue.&amp;#160; Yikes.&lt;/p&gt;  &lt;p&gt;In class, the final assignment was to write a program to maintain a family tree.&amp;#160; The program needed to read a line and parse out a set of commands:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;CREATE &lt;em&gt;name&lt;/em&gt; – create a new person named &lt;em&gt;name&lt;/em&gt;&lt;/li&gt;    &lt;li&gt;MARRY &lt;em&gt;name1 name2&lt;/em&gt; – mark persons named &lt;em&gt;name1&lt;/em&gt; and &lt;em&gt;name2&lt;/em&gt; as married&lt;/li&gt;    &lt;li&gt;CHILD &lt;em&gt;name1 name2&lt;/em&gt; – mark person named &lt;em&gt;name1&lt;/em&gt; as a child of &lt;em&gt;name2&lt;/em&gt;&lt;/li&gt;    &lt;li&gt;GRANDCHILDREN &lt;em&gt;name&lt;/em&gt; – prints a list of &lt;em&gt;name’&lt;/em&gt;s grandchildren&lt;/li&gt;    &lt;li&gt;COUSIN &lt;em&gt;name1 name2&lt;/em&gt; – prints TRUE if person named &lt;em&gt;name1&lt;/em&gt; is a cousin of &lt;em&gt;name2&lt;/em&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I looked at this task and thought, family tree?&amp;#160; Really?&amp;#160; In assembly?&amp;#160; No.&amp;#160; Wrong approach.&lt;/p&gt;  &lt;p&gt;So I first wrote it in Pascal and got it working.&amp;#160; Then I hand compiled each procedure (I didn’t know how compilers worked yet, but I had a pretty good idea).&amp;#160; I noted that many of my peers were struggling with the argument passing in VAX, so I avoided the whole problem and adopted register passing as the protocol where the caller, not the callee was responsible for saving registers.&amp;#160; Every subroutine was clear what it used as arguments and I set aside some registers that were free to be destroyed.&lt;/p&gt;  &lt;p&gt;Once I had my “architecture” in place, it was a matter of writing little subroutines that matched the Pascal.&amp;#160; I even included the Pascal in the source as documentation.&amp;#160; The only documentation.&amp;#160; Why would you need more?&lt;/p&gt;  &lt;p&gt;It wasn’t without bugs, but it eventually worked just fine and I was done well before most of my peers, even though I technically wrote the program twice.&lt;/p&gt;  &lt;p&gt;So, nobody really writes code like this anymore.&amp;#160; Compilers are good enough that unless you doing something like image processing, you don’t really need to drop to the machine level.&amp;#160; That doesn’t mean that we can’t learn something from the process.&lt;/p&gt;  &lt;p&gt;This particular problem lent itself to being solved in a particular language domain – Pascal (or your favorite procedural or OOP language).&amp;#160; So much so that writing it in another language was trivial.&amp;#160; It became divide and conquer to factor the tasks out to reasonable pieces: a simple parser, a &lt;a href="http://en.wikipedia.org/wiki/Read-eval-print_loop"&gt;REPL&lt;/a&gt;, a structure definition, and five procedures.&amp;#160; Then I picked a mapping strategy to go from my problem language domain into my solution language domain and followed through on it.&amp;#160; This is still a valid way to solve problems, even though this particular solution language domain is obsolete.&amp;#160; This particular approach is how we end up with domain specific languages and small virtual machines to run them.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx&amp;amp;;subject=Solving+Problems%2c+aka%2c+Nobody+Codes+Like+This+Anymore" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx&amp;amp;;title=Solving+Problems%2c+aka%2c+Nobody+Codes+Like+This+Anymore" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx&amp;amp;title=Solving+Problems%2c+aka%2c+Nobody+Codes+Like+This+Anymore" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx&amp;amp;;title=Solving+Problems%2c+aka%2c+Nobody+Codes+Like+This+Anymore" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx&amp;amp;;title=Solving+Problems%2c+aka%2c+Nobody+Codes+Like+This+Anymore&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/10/solving-problems-aka-nobody-codes-like-this-anymore.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=20315" width="1" height="1"&gt;</description></item><item><title>Writing a Composite ImageCommand – Gamma Corrected Resampling</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx</link><pubDate>Wed, 03 Mar 2010 16:05:52 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:20289</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/20289.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=20289</wfw:commentRss><description>&lt;p&gt;We have a customer who expressed some concern over how our resample command works (and how many similar commands work, in general).&amp;#160; He pointed us to &lt;a href="http://www.4p8.com/eric.brasseur/gamma.html"&gt;an article here&lt;/a&gt; which describes the problem.&amp;#160; The short of it is that the energy in a pixel is an expression of power (Watts) over the area of the pixel and although the scale of the pixel component intensities is represented as linear, it is really exponential.&amp;#160; Averaging a set of power measurements linearly produces results which don’t effectively represent the average power.&amp;#160; The trick is compensate for this is to make the power scale linear by applying an inverse gamma function to the image, then resampling it and finally applying the original gamma function to restore it.&lt;/p&gt;  &lt;p&gt;The gamma function looks like this:&lt;/p&gt;  &lt;p align="center"&gt;&lt;font size="5"&gt;&lt;font face="Times New Roman"&gt;pv’ = pv&lt;sup&gt;γ&lt;/sup&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;where pv is the normalized value for the channel of a pixel – this means it is a value between 0 and 1 inclusive.&amp;#160; γ is a value &amp;gt; 0, typically 2.2 for most monitors.&amp;#160; So the typical process of converting an 8-bit per channel pixel is something like this:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; pixel
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;   &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; channel
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; normalizedChannel = channel / 255.0;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; channelPrime = Math.Exp(normalizedChannel, gamma);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        channel = Math.Floor(channelPrime * 255);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;DotImage has an ImageCommand for performing this transformation efficiently.&amp;#160; We can do the transformation I’ve described as a sequence of steps, but I thought it would be nice to combine everything into one command.&lt;/p&gt;

&lt;p&gt;The first thing to do is to make a subclass of ImageCommand.&amp;#160; ImageCommand is an abstract class which is, more or less the a collection of GoF &lt;a href="http://en.wikipedia.org/wiki/Template_method_pattern"&gt;template methods&lt;/a&gt;.&amp;#160; This is to make it easy to implement ImageCommands from scratch.&amp;#160; We’re not doing that – we’re making a composite command.&amp;#160;&amp;#160; We’ll implement the abstract methods, but they won’t be needed.&amp;#160; So let’s start off with an outline of what we want:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; GammaResampleCommand : ImageCommand
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    GammaCommand _gammaCommand = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; GammaCommand();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    ResampleCommand _resampleCommand = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ResampleCommand();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; GammaResampleCommand()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; GammaResampleCommand(&lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; gammaLevel, Size destSize, ResampleMethod method)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        GammaLevel = gammaLevel;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;       DestSize = destSize;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        Method = method;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; AtalaImage PerformActualCommand(AtalaImage source, AtalaImage dest, System.Drawing.Rectangle imageArea, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; ImageResults results)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; NotImplementedException();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; PixelFormat[] SupportedPixelFormats
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _gammaCommand.SupportedPixelFormats; }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; VerifyProperties(AtalaImage image)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;       ImageCommand.ProxyVerifyProperties(_gammaCommand, image);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        ImageCommand.ProxyVerifyProperties(_resampleCommand, image);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; GammaLevel
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _gammaCommand.GammaLevel; }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt; { _gammaCommand.GammaLevel = &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;; }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Size DestSize
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _resampleCommand.DestSize; }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt; { _resampleCommand.DestSize = &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;; }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ResampleMethod Method
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _resampleCommand.Method; }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt; { _resampleCommand.Method = &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;; }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;You’ll note that rather than implement the properties or VerifyProperties, we’re just acting as a &lt;a href="http://en.wikipedia.org/wiki/Proxy_pattern"&gt;proxy&lt;/a&gt; to existing instances of GammaCommand and ResampleCommand.&amp;#160; This means we don’t need to implement error checking on the properties – that will happen for free.&amp;#160; In fact, to implement VerifyProperties, we’re taking advantage of a feature of ImageCommand – ImageCommand has a set of methods named Proxy&lt;em&gt;XXXX&lt;/em&gt;, which will call the method &lt;em&gt;XXXX&lt;/em&gt; for us, even though it is protected.&amp;#160; This breaks encapsulation, but it is there just for this purpose – creating composite commands.&amp;#160; Finally, you’ll note that PerformActualCommand throws an exception.&amp;#160; That’s OK – we’re going to ensure that it is never called.&lt;/p&gt;

&lt;p&gt;What remains is to do the actual work, and for that we’ll override the method Apply().&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; ImageResults Apply(AtalaImage image)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (AtalaImage gammaCorrected = image.Clone() &lt;span style="color:#0000ff;"&gt;as&lt;/span&gt; AtalaImage)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; gamma = _gammaCommand.GammaLevel;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt; inverseGamma = 1 / gamma;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            GammaLevel = inverseGamma;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _gammaCommand.Apply(gammaCorrected);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            AtalaImage finalImage = _resampleCommand.Apply(gammaCorrected).Image;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            GammaLevel = gamma;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _gammaCommand.Apply(finalImage);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ImageResults(finalImage, &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;GammaCommand is InPlaceProcessing = true, which means that it side-effects the source image.&amp;#160; I don’t want this, so I’ll make a copy of the source image using Clone, then apply the inverse gamma to the source, resample it, then apply the normal gamma.&lt;/p&gt;

&lt;p&gt;Here is some quick test code for this:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (AtalaImage image = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; AtalaImage(@&amp;quot;&lt;span style="color:#8b0000;"&gt;..\..\gamma_dalai_lama_gray.jpg&lt;/span&gt;&amp;quot;))
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;     GammaResampleCommand resampler = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; GammaResampleCommand(2.2,
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;           &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Size(image.Width / 2, image.Height / 2),
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;           ResampleMethod.LanczosFilter);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;     &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (AtalaImage smaller = resampler.Apply(image).Image)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;     {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;         smaller.Save(&amp;quot;&lt;span style="color:#8b0000;"&gt;dalailama.jpg&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; JpegEncoder(), &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;     }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;The input file is this:&lt;/p&gt;
&lt;img src="http://www.4p8.com/eric.brasseur/gamma_dalai_lama_gray.jpg" /&gt; 

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;and the subsequent output is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/stevehawley/dalailama_624DC89B.jpg"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="dalailama" border="0" alt="dalailama" src="http://www.atalasoft.com/cs/blogs/stevehawley/dalailama_thumb_6900D21E.jpg" width="129" height="111" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx&amp;amp;;subject=Writing+a+Composite+ImageCommand+%e2%80%93+Gamma+Corrected+Resampling" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx&amp;amp;;title=Writing+a+Composite+ImageCommand+%e2%80%93+Gamma+Corrected+Resampling" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx&amp;amp;title=Writing+a+Composite+ImageCommand+%e2%80%93+Gamma+Corrected+Resampling" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx&amp;amp;;title=Writing+a+Composite+ImageCommand+%e2%80%93+Gamma+Corrected+Resampling" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx&amp;amp;;title=Writing+a+Composite+ImageCommand+%e2%80%93+Gamma+Corrected+Resampling&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/03/03/writing-a-composite-imagecommand-gamma-corrected-resampling.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=20289" width="1" height="1"&gt;</description></item><item><title>Libpng – You’re Doing It Wrong</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx</link><pubDate>Tue, 23 Feb 2010 17:24:28 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:20239</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/20239.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=20239</wfw:commentRss><description>&lt;p&gt;I took a three day hiatus from developing DotImage 9.0 to work on an experiment: how would a 100% managed PNG decoder perform, compared to libpng?&lt;/p&gt;  &lt;p&gt;Using only C#, I knocked together a very basic chunk of code that has a very strong .NET feel/smell to it to decode PNG images.&amp;#160; Internally, I build a map of the available chunks in the file and then I ask for them by type.&amp;#160; This is different from most PNG consuming code – the spec encourages you to read chunks in possible expected order, which requires a very state machiney layout.&amp;#160; State machines aren’t bad, per se, but they do lead to code that is not always easy to read or maintain.&amp;#160; So instead of waiting for a chunk of the right type to arrive, I just ask for it by name.&lt;/p&gt;  &lt;p&gt;For the required zlib compression, I used &lt;a href="http://dotnetzip.codeplex.com/"&gt;DotNetZip&lt;/a&gt;, in particular the Zlib assembly.&amp;#160; The main reason for this choice was that Ionics implementation is a filter stream.&amp;#160; I give their stream another stream to work with and it will decompress it while I read from it.&amp;#160; This is awesome, because I don’t need to worry about the underlying implementation.&lt;/p&gt;  &lt;p&gt;Well, that’s actually a lie.&amp;#160; I do have to worry about it.&amp;#160; PNG allows compressed image data to be spread across multiple PNG chunks in the file.&amp;#160; So I created a ChunkStream that give a stream a List&amp;lt;ChunkDescriptors&amp;gt; that describe where image data chunks reside, it will read/seek through the chunks as needed.&lt;/p&gt;  &lt;p&gt;In sum, my reading model for image data is this Stream-&amp;gt;ChunkStream-&amp;gt;ZLibStream.&lt;/p&gt;  &lt;p&gt;So here is my code for decoding a non-interlaced PNG image:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;List&amp;lt;ChunkDescriptor&amp;gt; chunks = _chunkMap[ChunkType.IDAT];
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;ChunkStream chunkstm = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ChunkStream(_stm, chunks);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;ZlibStream stm = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ZlibStream(chunkstm, CompressionMode.Decompress);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; y = 0; y &amp;lt; Header.Height; y++)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; filter = stm.ReadByte();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (filter &amp;lt; 0)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Exception(&amp;quot;&lt;span style="color:#8b0000;"&gt;unexpected EOF&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (!FilterIsValid(filter))
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Exception(&amp;quot;&lt;span style="color:#8b0000;"&gt;invalid filter&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; count = stm.Read(currLine, 0, bytesPerLine);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    Unfilter(currLine, prevLine, (PngAdaptiveFilter)filter, bytesPerLine);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    OnScanlineRead(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ScanlineEventArgs(y, currLine));
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;byte&lt;/span&gt;[] temp = prevLine;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    prevLine = currLine;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    currLine = temp;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;That’s all that it takes – this code is easy to read, easy to maintain, and nicely abstracted.&amp;#160; Do you see the &lt;em&gt;total lack&lt;/em&gt; of special case handling?&amp;#160; All that is wrapped up in the stream model and instead, I can concentrate on the decoding.&lt;/p&gt;

&lt;p&gt;I did some testing and found that compared with a libpng, this code takes a little less than twice as long.&amp;#160; With some tweaking, I can make it better.&amp;#160; In my case, the bottleneck is not where I expected.&amp;#160; It’s not in I/O.&amp;#160; It’s not in reordering color channels.&amp;#160; It’s not in using an event driven model for reporting scanlines read.&amp;#160; It’s not in mapping out the chunks at the start.&amp;#160; In my particular test case, the bottleneck is the &lt;a href="http://gnupdf.org/PNG_and_TIFF_Predictors_Filter"&gt;Paeth predictor&lt;/a&gt; that was used on the test file to improve compression.&lt;/p&gt;

&lt;p&gt;Here is the Paeth predictor as I originally implemented it:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; PaethPredictor(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; a, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; b, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; c)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; p = a + b - c;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; pa = Math.Abs(p - a);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; pb = Math.Abs(p - b);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; pc = Math.Abs(p - c);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (pa &amp;lt;= pb &amp;amp;&amp;amp; pa &amp;lt;= pc)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; a;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (pb &amp;lt;= pc)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; b;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; c;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;This is very simple code, so it’s hard to imagine how you might make it better.&amp;#160; I took this approach:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; PaethPredictor(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; a, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; b, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; c)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; bmc = b - c;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; pa = bmc &amp;lt; 0 ? -bmc : bmc;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; amc = a - c;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; pb = amc &amp;lt; 0 ? -amc : amc;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; apbmcmc = a + b - c - c;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; pc = apbmcmc &amp;lt; 0 ? -apbmcmc : apbmcmc;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (pa &amp;lt;= Math.Min(pa, pc))
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; a;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (pb &amp;lt;= pc)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; b;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; c;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;I eliminated the calls to Math.Abs, which helps a little.&amp;#160; I also broke apart the expression p which also helped a little bit.&amp;#160; When I say “a little”, I mean that it shaves off maybe a few hundredths of a second.&amp;#160; To read my source image 100 times took 1500ms and after these basic rearrangements, I got it down to 1100ms.&amp;#160; These tiny changes help because the Paeth Predictor gets called 7.5 million times in my test code.&amp;#160; If I inline it (seriously hurting readability), the result is slightly faster.&amp;#160; At this point the pure managed code runs at 1.5x libpng, which is way better than I expected.&lt;/p&gt;

&lt;p&gt;I looked at the image decoding in libpng and while the authors clearly went to a great deal of effort to handle errors and special cases and to make the code as readable as possible, ultimately I think they’re doing it wrong.&amp;#160; My code is memory efficient, easy to read, easy to maintain, and will never leak memory&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx&amp;amp;;subject=Libpng+%e2%80%93+You%e2%80%99re+Doing+It+Wrong" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx&amp;amp;;title=Libpng+%e2%80%93+You%e2%80%99re+Doing+It+Wrong" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx&amp;amp;title=Libpng+%e2%80%93+You%e2%80%99re+Doing+It+Wrong" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx&amp;amp;;title=Libpng+%e2%80%93+You%e2%80%99re+Doing+It+Wrong" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx&amp;amp;;title=Libpng+%e2%80%93+You%e2%80%99re+Doing+It+Wrong&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=20239" width="1" height="1"&gt;</description></item><item><title>DataMatrix Described</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx</link><pubDate>Tue, 09 Feb 2010 16:33:50 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:20176</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/20176.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=20176</wfw:commentRss><description>&lt;p&gt;Saw this &lt;a href="http://www.ams.org/featurecolumn/archive/data-matrix.html"&gt;great description of Datamatrix encoding&lt;/a&gt; via &lt;a href="http://chneukirchen.org/trivium/"&gt;Trivium&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Very good your us visual thinkers.&lt;/p&gt;  &lt;p&gt;And if you need it, Atalasoft has tools for both &lt;a href="http://www.atalasoft.com/products/dotimage/barcode/"&gt;reading&lt;/a&gt; and &lt;a href="http://www.atalasoft.com/products/dotimage/barcode-writer/"&gt;writing&lt;/a&gt; Datamatrix 2D barcodes (and other barcodes as well).&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx&amp;amp;;subject=DataMatrix+Described" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx&amp;amp;;title=DataMatrix+Described" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx&amp;amp;title=DataMatrix+Described" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx&amp;amp;;title=DataMatrix+Described" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx&amp;amp;;title=DataMatrix+Described&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/09/datamatrix-described.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=20176" width="1" height="1"&gt;</description></item><item><title>What is /?</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx</link><pubDate>Fri, 05 Feb 2010 21:21:01 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:20138</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/20138.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=20138</wfw:commentRss><description>&lt;p&gt;I learned something today about the humble slash character: /.&lt;/p&gt;  &lt;p&gt;First, let me say that to me, / is always pronounced ‘slash’.&amp;#160; This is due to my first encountering of this character as a path separator in UNIX when I worked at Bell Labs.&amp;#160;&amp;#160;&amp;#160; The other slash, \, I only knew as back slash.&amp;#160; When I encountered it in DOS paths, I was appalled that people used the name ‘slash’ interchangeably with ‘back slash’ and called ‘/’ ‘forward slash’.&amp;#160; Slash/back slash made sense to me because it fit cleanly with tick/back tick (‘ and ’).&lt;/p&gt;  &lt;p&gt;What I learned is that the character that we think of as slash (or forward slash to you heathens) is really called ‘&lt;a href="http://en.wikipedia.org/wiki/Solidus_%28punctuation%29"&gt;solidus&lt;/a&gt;’.&lt;/p&gt;  &lt;p&gt;I also found out that the paragraph symbol, ¶, is called ‘&lt;a href="http://en.wikipedia.org/wiki/Pilcrow"&gt;pilcrow&lt;/a&gt;’ or ‘alinea’.&lt;/p&gt;  &lt;p&gt;How about that?&lt;/p&gt;  &lt;p&gt;I’ll take “Punctuation Names” for $800, Alex.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx&amp;amp;;subject=What+is+%2f%3f" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx&amp;amp;;title=What+is+%2f%3f" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx&amp;amp;title=What+is+%2f%3f" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx&amp;amp;;title=What+is+%2f%3f" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx&amp;amp;;title=What+is+%2f%3f&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/05/what-is.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=20138" width="1" height="1"&gt;</description></item><item><title>DelegatedImageSource</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx</link><pubDate>Thu, 28 Jan 2010 21:24:07 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:20095</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>1</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/20095.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=20095</wfw:commentRss><description>&lt;p&gt;One common task in working with images is, given a file or a set of files, read in each page, perform some operation on it and write it as a page in a target file.&lt;/p&gt;  &lt;p&gt;This is tricky to do out of the box in dotImage in that a lot of the onus of memory management falls onto client code.&amp;#160; The client needs to know how to append images onto a possibly existing file in a way that won’t use up a ton of memory.&lt;/p&gt;  &lt;p&gt;Let me give you an example:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;TiffDocument doc = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; TiffDocument();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; i = 0; i &amp;lt; totalPages; i++) {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    AtalaImage page = GetSomePage(i);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    Watermark(page);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    doc.Pages.Add(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; TiffPage(page, TiffCompression.Default));
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    page.Dispose();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;doc.Save(someOutputFile);&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;This is a chunk of code that is meant to loop through some set of pages, watermark each one, add it to a TiffDocument and then save it to a TIFF.&amp;#160; We’re being good in that we’re calling Dispose() on the AtalaImage to let it go.&amp;#160; The problem is that TiffPage allocates memory for the image (in most cases compressed) so if you’re working with a dozen pages or less, you’ll be fine, but if you work with hundreds, you will bring your machine to a crawl.&lt;/p&gt;

&lt;p&gt;In thinking about this, I decided that what we needed was a flavor of ImageSource and RandomAccessImageSource that could adapt an existing ImageSource and allow the user to inject code into the process.&lt;/p&gt;

&lt;p&gt;To do this, we’ll create a subclass of ImageSource that takes another ImageSource as an argument.&amp;#160; It will let the provided ImageSource do all the heavy lifting, allowing code injection at the appropriate time:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; Atalasoft.Imaging;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; DelegatedImageSource
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; DelegatedImageSource : ImageSource
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        Func&amp;lt;AtalaImage, AtalaImage&amp;gt; _imageProc;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        ImageSource _source;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; DelegatedImageSource(ImageSource source, Func&amp;lt;AtalaImage, AtalaImage&amp;gt; imageProc)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (source == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ArgumentNullException(&amp;quot;&lt;span style="color:#8b0000;"&gt;source&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (imageProc == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ArgumentNullException(&amp;quot;&lt;span style="color:#8b0000;"&gt;imageProc&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _imageProc = imageProc;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source = source;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; ImageSourceNode LowLevelAcquireNextImage()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            AtalaImage image = _source.AcquireNext();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            AtalaImage processed = _imageProc(image);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            processed = processed ?? image;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (processed == image)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                processed = (AtalaImage)image.Clone();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source.Release(image);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ImageSourceNode(processed, &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; LowLevelDispose()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source.Dispose();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; LowLevelFlushOnReset()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; LowLevelHasMoreImages()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _source.HasMoreImages();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; LowLevelReset()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source.Reset();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; LowLevelSkipNextImage()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source.Release(_source.AcquireNext());
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; LowLevelTotalImages()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _source.TotalImages;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; LowLevelTotalImagesKnown()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _source.TotalImagesKnown;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;The main meat of the code is in LowLevelAcquireNextImage, which calls AcquireNext on the provided source, then hands the resulting AtalaImage off to the delegate.&amp;#160; If the delegate returns null or the original image, we return a clone, otherwise we return the image created by user code.&lt;/p&gt;

&lt;p&gt;Here is an example snippet which combines a set of images into a single TIFF:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;FileSystemImageSource source = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; FileSystemImageSource(@&amp;quot;&lt;span style="color:#8b0000;"&gt;\Images\Documents&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span style="color:#8b0000;"&gt;*&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;DelegatedImageSource dis = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; DelegatedImageSource(source,
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            (image) =&amp;gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;; });
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;TiffEncoder encoder = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; TiffEncoder();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (FileStream fs = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; FileStream(&amp;quot;&lt;span style="color:#8b0000;"&gt;output.tif&lt;/span&gt;&amp;quot;, FileMode.Create))
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    encoder.Save(fs, dis, &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;which is a sweet little chunk of code to combine image files into one TIFF.&amp;#160; Further, there won’t be the same memory issue as with our naive example because ImageSource handles resource management for you via the Acquire/Release model.&amp;#160; You might ask, “so why do need the TiffDocument class when I can do all the work like this?”&amp;#160; The answer is that when an AtalaImage is created from a TIFF document, the metadata associated with the page (EXIF, etc) is shed.&amp;#160; TiffDocument maintains that information.&lt;/p&gt;

&lt;p&gt;Now let’s change our task to be “mark each page with a red X and save as a PDF”.&amp;#160; The code doesn’t change much:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;DelegatedImageSource dis = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; DelegatedImageSource(source, (image) =&amp;gt;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    AtalaImage rgb = &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (image.PixelFormat == PixelFormat.Pixel24bppBgr || image.PixelFormat == PixelFormat.Pixel32bppBgr ||
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        image.PixelFormat == PixelFormat.Pixel32bppBgra)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        rgb = image;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        rgb = image.GetChangedPixelFormat(PixelFormat.Pixel24bppBgr);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (Graphics g = rgb.GetGraphics())
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (Pen p = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Pen(Color.Red, 25))
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            g.DrawLine(p, 0, 0, rgb.Width, rgb.Height);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            g.DrawLine(p, 0, rgb.Height, rgb.Width, 0);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; rgb;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;});
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;PdfEncoder encoder = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; PdfEncoder();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (FileStream fs = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; FileStream(&amp;quot;&lt;span style="color:#8b0000;"&gt;output.pdf&lt;/span&gt;&amp;quot;, FileMode.Create))
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    encoder.Save(fs, dis, &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Note that the save code is identical.&amp;#160; This is because both PdfEncoder and TiffEncoder are MultiFramedEncoder objects which can take an ImageSource in one flavor of Save().&lt;/p&gt;

&lt;p&gt;Let’s say that you want instead to overlay a watermark onto each image – the code, again, doesn’t change much:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;AtalaImage watermark = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; AtalaImage(@&amp;quot;&lt;span style="color:#8b0000;"&gt;C:\Users\shawley\Pictures\bunny.png&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;OverlayCommand overlay = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; OverlayCommand(watermark, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Point(20, 20));
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;overlay.Opacity = 0.50;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;overlay.ApplyToAnyPixelFormat = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;DelegatedImageSource dis = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; DelegatedImageSource(source, (image) =&amp;gt;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; overlay.Apply(image).Image;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;});
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;TiffEncoder encoder = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; TiffEncoder();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (FileStream fs = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; FileStream(&amp;quot;&lt;span style="color:#8b0000;"&gt;output.tif&lt;/span&gt;&amp;quot;, FileMode.Create))
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    encoder.Save(fs, dis, &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;In this case, I’m using the captured variable, overlay, to write onto the image, turning the actual watermarking code into a one-liner.&lt;/p&gt;

&lt;p&gt;And here, finally, is the same code modified to work specifically for RandomAccessImageSource:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Linq;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Text;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; Atalasoft.Imaging;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; DelegatedImageSource
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; DelegatedRandomAccessImageSource : RandomAccessImageSource
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        Func&amp;lt;AtalaImage, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;, AtalaImage&amp;gt; _imageProc;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        RandomAccessImageSource _source;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; DelegatedRandomAccessImageSource(RandomAccessImageSource source, Func&amp;lt;AtalaImage, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;, AtalaImage&amp;gt; imageProc)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (source == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ArgumentNullException(&amp;quot;&lt;span style="color:#8b0000;"&gt;source&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (imageProc == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ArgumentNullException(&amp;quot;&lt;span style="color:#8b0000;"&gt;imageProc&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _imageProc = imageProc;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source = source;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; ImageSourceNode LowLevelAcquire(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; index)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            AtalaImage image = _source[index];
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            AtalaImage processed = _imageProc(image, index);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            processed = processed ?? image;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (processed == image)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                processed = (AtalaImage)image.Clone();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source.Release(image);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ImageSourceNode(image, &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; ImageSourceNode LowLevelAcquireNextImage()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            AtalaImage image = _source.AcquireNext();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            AtalaImage processed = _imageProc(image, -1);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            processed = processed ?? image;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (processed == image)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                processed = (AtalaImage)image.Clone();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source.Release(image);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ImageSourceNode(processed, &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; LowLevelDispose()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source.Dispose();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; LowLevelFlushOnReset()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; LowLevelHasMoreImages()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _source.HasMoreImages();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; LowLevelReset()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source.Reset();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; LowLevelSkipNextImage()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            _source.Release(_source.AcquireNext());
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; LowLevelTotalImages()
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _source.TotalImages;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;So we see that by using delegates in tandem with ImageSource objects, we can make repetitive tasks much easier and remove a lot of issues in resource management at the same time.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx&amp;amp;;subject=DelegatedImageSource" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx&amp;amp;;title=DelegatedImageSource" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx&amp;amp;title=DelegatedImageSource" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx&amp;amp;;title=DelegatedImageSource" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx&amp;amp;;title=DelegatedImageSource&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/28/delegatedimagesource.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=20095" width="1" height="1"&gt;</description></item><item><title>Vignettes in DotImage</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx</link><pubDate>Fri, 15 Jan 2010 18:38:35 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:20047</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/20047.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=20047</wfw:commentRss><description>&lt;p&gt;On &lt;a href="http://www.stackoverflow.com"&gt;Stack Overflow&lt;/a&gt;, a user asked how to create vignettes in .NET.&amp;#160; I wrote up &lt;a href="http://stackoverflow.com/questions/2065199/vignetting-image-effect-algorithm-with-net/2065708#2065708"&gt;this answer&lt;/a&gt;, which explains the math and the general approach.&lt;/p&gt;  &lt;p&gt;To give you an idea of what this looks like, here is the output of an application which applies the vignette to an image.&amp;#160; This is different from the Stack Overflow answer in that I chose to do this in an ImageRegionCommand from within dotImage.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/stevehawley/image_16BE99CC.png"&gt;&lt;img style="border-right-width:0px;display:block;float:none;border-top-width:0px;border-bottom-width:0px;margin-left:auto;border-left-width:0px;margin-right:auto;" title="image" border="0" alt="image" src="http://www.atalasoft.com/cs/blogs/stevehawley/image_thumb_253995F1.png" width="369" height="557" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;To do this, I created a new class called VignetteCommand, overrode four members and added one utility method.&amp;#160; This command works on 24 bit RGB, 32 bit RGB, and 32 bit RGBA which a limitation imposed by GDI+.&amp;#160; Since this command works by painting on top of an existing image, InPlaceProcessing will be overridden to return true always.&amp;#160; In theory, we could do without, but we’d just be copying the existing image onto the new image, then painting.&amp;#160; We override VerifyProperties to make sure that any user set properties are right. Finally, we override PerformActualCommand to do the actual work.&amp;#160; All the rest of the infrastructure is handled by dotImage.&lt;/p&gt;  &lt;p&gt;Here is the code:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; Atalasoft.Imaging;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; Atalasoft.Imaging.ImageProcessing;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Drawing;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Drawing.Drawing2D;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; Vignette1
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;{
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; VignetteCommand : ImageRegionCommand
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; PixelFormat[] _supportedPixelFormats = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; PixelFormat[] {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            PixelFormat.Pixel24bppBgr, PixelFormat.Pixel32bppBgr, PixelFormat.Pixel32bppBgra
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        };
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; PixelFormat[] SupportedPixelFormats { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _supportedPixelFormats; } }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; InPlaceProcessing { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;; } }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; VerifyProperties(AtalaImage image)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (Positions == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; Factors == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (Positions == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt; || Factors == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ArgumentException(Positions == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt; ? &amp;quot;&lt;span style="color:#8b0000;"&gt;Positions&lt;/span&gt;&amp;quot; : &amp;quot;&lt;span style="color:#8b0000;"&gt;Factors&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (Positions.Length != Factors.Length)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ArgumentException(&amp;quot;&lt;span style="color:#8b0000;"&gt;position and length arrays must be the same length&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span style="color:#8b0000;"&gt;Positions&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; AtalaImage PerformActualCommand(AtalaImage source, AtalaImage dest, System.Drawing.Rectangle imageArea, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; ImageResults results)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (Graphics g = source.GetGraphics())
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                PaintVignette(g, imageArea);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; PaintVignette(Graphics g, Rectangle bounds)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            Rectangle ellipsebounds = bounds;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            ellipsebounds.Offset(-ellipsebounds.X, -ellipsebounds.Y);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; x = ellipsebounds.Width - (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)Math.Round(.70712 * ellipsebounds.Width);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; y = ellipsebounds.Height - (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)Math.Round(.70712 * ellipsebounds.Height);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            ellipsebounds.Inflate(x, y);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (GraphicsPath path = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; GraphicsPath())
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                path.AddEllipse(ellipsebounds);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (PathGradientBrush brush = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; PathGradientBrush(path))
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    brush.WrapMode = WrapMode.Tile;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    brush.CenterColor = Color.FromArgb(0, 0, 0, 0);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    brush.SurroundColors = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Color[] { Color.FromArgb(255, 0, 0, 0) };
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    Blend blend = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Blend();
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    &lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;[] positions = Positions;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    &lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;[] factors = Factors;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (positions == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt; || factors == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    {
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                        positions = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;[] { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0F };
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                        factors = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;[] { 0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 1.0f };
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    blend.Positions = positions;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    blend.Factors = factors;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    brush.Blend = blend;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    Region oldClip = g.Clip;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    g.Clip = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Region(bounds);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    g.FillRectangle(brush, ellipsebounds);
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                    g.Clip = oldClip;
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;                }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;            }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;[] Positions { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;; }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;[] Factors { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;; }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;}
&lt;/pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx&amp;amp;;subject=Vignettes+in+DotImage" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx&amp;amp;;title=Vignettes+in+DotImage" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx&amp;amp;title=Vignettes+in+DotImage" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx&amp;amp;;title=Vignettes+in+DotImage" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx&amp;amp;;title=Vignettes+in+DotImage&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/01/15/vignettes-in-dotimage.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=20047" width="1" height="1"&gt;</description></item><item><title>The Elements of Programming Style</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx</link><pubDate>Wed, 30 Dec 2009 17:01:29 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:19977</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/19977.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=19977</wfw:commentRss><description>&lt;p&gt;Many years ago, I had the pleasure of working at Murray Hill Bell Labs.&amp;#160; My job, of all things, was making violins, but that’s a story for another time.&amp;#160; My office was in section D of the 5th floor of building 2, which was also where the UNIX room was.&amp;#160; I learned a lot from looking at the code written by the creators of C and UNIX.&lt;/p&gt;  &lt;p&gt;It is terrific to watch &lt;a href="http://video.ias.edu/stream&amp;amp;ref=270"&gt;Brian Kernighan giving this talk&lt;/a&gt; about clarity in code.&amp;#160; A lot of what he shows as bad examples are grist for the mill of the &lt;a href="http://thedailywtf.com/"&gt;Daily WTF&lt;/a&gt; and such sites.&amp;#160; And while I don’t always meet all of the goals of clarity (who does?), I do try to write things so that they can be read.&lt;/p&gt;  &lt;p&gt;That’s one of the reasons why I was so pleased when Rick showed me his &lt;a href="http://www.atalasoft.com/cs/blogs/rickm/archive/2009/12/28/steepest-ascent-hill-climbing-in-c-and-f.aspx"&gt;hill climbing code&lt;/a&gt; before he wrote his blog article: it’s beautiful code.&amp;#160; It reads like a textbook algorithm.&amp;#160; Nice job, Rick.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx&amp;amp;;subject=The+Elements+of+Programming+Style" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx&amp;amp;;title=The+Elements+of+Programming+Style" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx&amp;amp;title=The+Elements+of+Programming+Style" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx&amp;amp;;title=The+Elements+of+Programming+Style" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx&amp;amp;;title=The+Elements+of+Programming+Style&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/30/the-elements-of-programming-style.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=19977" width="1" height="1"&gt;</description></item><item><title>Support Cases and Mourning</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx</link><pubDate>Tue, 15 Dec 2009 20:34:33 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:19873</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>1</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/19873.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=19873</wfw:commentRss><description>&lt;p&gt;I was thinking about how I handle support cases, and it tickled me that I often follow the &lt;a href="http://en.wikipedia.org/wiki/K%C3%BCbler-Ross_model"&gt;Kübler-Ross model of grief&lt;/a&gt;, although I prefer the steps outlined by Dr. Hibbert in “&lt;a href="http://www.snpp.com/episodes/7F11.html"&gt;The Deadly Blowfish&lt;/a&gt;”:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre&gt;   Dr. H: Now, a little death anxiety is normal.  You can expect to go through
          five stages.  The first is denial.
   Homer: No way!  Because I'm not dying! [hugs Marge]
   Dr. H: The second is anger.
   Homer: Why you little! [steps towards Dr. H]
   Dr. H: After that comes fear.
   Homer: What's after fear?  What's after fear? [cringes]
   Dr. H: Bargaining.
   Homer: Doc, you gotta get me out of this!  I'll make it worth your while!
   Dr. H: Finally, acceptance.
   Homer: Well, we all gotta go sometime.
   Dr. H: Mr. Simpson, your progress astounds me.&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;h1&gt;&amp;#160;&lt;/h1&gt;

&lt;h1&gt;Denial&lt;/h1&gt;

&lt;p&gt;“No way!&amp;#160; Because I fixed that bug.&amp;#160; The customer is wrong.”&lt;/p&gt;

&lt;h1&gt;Anger&lt;/h1&gt;

&lt;p&gt;“Gah!&amp;#160; This is keeping me from my work!”&lt;/p&gt;

&lt;h1&gt;Fear&lt;/h1&gt;

&lt;p&gt;“What if this bug is deeper than it appears?”&lt;/p&gt;

&lt;h1&gt;Bargaining&lt;/h1&gt;

&lt;p&gt;“If I can come up with a workaround, they’ll be happy with that, right?”&lt;/p&gt;

&lt;h1&gt;Acceptance&lt;/h1&gt;

&lt;p&gt;“Oh well, I’ll put in the fix.”&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx&amp;amp;;subject=Support+Cases+and+Mourning" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx&amp;amp;;title=Support+Cases+and+Mourning" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx&amp;amp;title=Support+Cases+and+Mourning" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx&amp;amp;;title=Support+Cases+and+Mourning" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx&amp;amp;;title=Support+Cases+and+Mourning&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/support-cases-and-mourning.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=19873" width="1" height="1"&gt;</description></item><item><title>More Property Wants – Polymorphic Set</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx</link><pubDate>Tue, 15 Dec 2009 18:26:24 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:19872</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/19872.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=19872</wfw:commentRss><description>&lt;p&gt;I was writing some property heavy code and I realized that if I can write this code:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetFoo(&lt;span class="kwrd"&gt;int&lt;/span&gt; x) { }
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetFoo(&lt;span class="kwrd"&gt;double&lt;/span&gt; y) { }
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetFoo(Rational z) { }&lt;/pre&gt;

&lt;p&gt;then I really want to have this syntax:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Foo {
    get { &lt;span class="rem"&gt;/* ... */&lt;/span&gt; }
    set { &lt;span class="rem"&gt;/* ... */&lt;/span&gt; }
    set (&lt;span class="kwrd"&gt;double&lt;/span&gt;) { &lt;span class="rem"&gt;/* ... */&lt;/span&gt; }
    set {Rational) { &lt;font color="#008000"&gt;/* ... */&lt;/font&gt; }
}&lt;/pre&gt;

&lt;p&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }Because they’re the same, really.&lt;/p&gt;

&lt;p&gt;In addition, I was to also see PropertyInfo.IsAssignableFrom(Type t) (although IsSettableFrom is better wording, the former matched the Type.IsAssignableFrom method) so that I can figure out from reflection if a set would throw.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx&amp;amp;;subject=More+Property+Wants+%e2%80%93+Polymorphic+Set" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx&amp;amp;;title=More+Property+Wants+%e2%80%93+Polymorphic+Set" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx&amp;amp;title=More+Property+Wants+%e2%80%93+Polymorphic+Set" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx&amp;amp;;title=More+Property+Wants+%e2%80%93+Polymorphic+Set" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx&amp;amp;;title=More+Property+Wants+%e2%80%93+Polymorphic+Set&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/15/more-property-wants-polymorphic-set.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=19872" width="1" height="1"&gt;</description></item><item><title>RC4 in C#</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx</link><pubDate>Fri, 11 Dec 2009 21:59:11 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:19858</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/19858.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=19858</wfw:commentRss><description>&lt;p&gt;I was working on a project this week that required some RC4 (SARC, ARC4, ARCFOUR) encryption.&amp;#160; In looking around, I didn’t find a public version that I liked, so working from Wikipedia, I created my own.&amp;#160; This version is in C# and I tried to build it so that it is efficient enough, but maximized usability.&amp;#160; Therefore, there are interfaces for byte arrays (immutable and not), Streams, and IEnumerable&amp;lt;byte&amp;gt;.&amp;#160; The code is not thread safe, so use a different instance in any thread that needs it. &lt;/p&gt;  &lt;p&gt;Feel free to use the code as your needs and jurisdiction allow.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// This source code is property of Atalasoft, Inc. (www.atalasoft.com)&lt;/span&gt;
&lt;span class="rem"&gt;// No warrantees expressed or implied.&lt;/span&gt;
&lt;span class="rem"&gt;// You are free to use this in your own code, provided that you&lt;/span&gt;
&lt;span class="rem"&gt;// leave this notice in place.&lt;/span&gt;

&lt;span class="rem"&gt;// Change History:&lt;/span&gt;
&lt;span class="rem"&gt;// December 11, 2009 - Initial version, Steve Hawley&lt;/span&gt;

&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Atalasoft
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Rc4
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] _S;
        &lt;span class="kwrd"&gt;int&lt;/span&gt; _x, _y;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; Rc4()
        {
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; Rc4(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] key)
            : &lt;span class="kwrd"&gt;this&lt;/span&gt;(key, key.Length)
        {
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; Rc4(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] key, &lt;span class="kwrd"&gt;int&lt;/span&gt; length)
        {
            SetKey(key, length);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetKey(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] key)
        {
            SetKey(key, key.Length);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetKey(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] key, &lt;span class="kwrd"&gt;int&lt;/span&gt; length)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_S == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                _S = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[256];

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (key == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;key&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (length &amp;lt; 1 || length &amp;gt; key.Length)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException(&lt;span class="str"&gt;&amp;quot;length&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 256; i++)
                _S[i] = (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)i;
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0, j = 0; i &amp;lt; 256; i++)
            {
                j = (j + key[i % length] + _S[i]) &amp;amp; 0xff;
                &lt;span class="kwrd"&gt;byte&lt;/span&gt; temp = _S[i];
                _S[i] = _S[j];
                _S[j] = temp;
            }
            Reset();
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Reset()
        {
            _x = _y = 0;
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt; GetNextMask()
        {
            _x = (_x + 1) &amp;amp; 0xff;
            _y = (_y + _S[_x]) &amp;amp; 0xff;
            &lt;span class="kwrd"&gt;byte&lt;/span&gt; temp = _S[_x];
            _S[_x] = _S[_y];
            _S[_y] = temp;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _S[(_S[_x] + _S[_y]) &amp;amp; 0xff];
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerable&amp;lt;&lt;span class="kwrd"&gt;byte&lt;/span&gt;&amp;gt; Process(IEnumerable&amp;lt;&lt;span class="kwrd"&gt;byte&lt;/span&gt;&amp;gt; data)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (data == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_S == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Need to call SetKey before calling Process&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;byte&lt;/span&gt; b &lt;span class="kwrd"&gt;in&lt;/span&gt; data)
                &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(b ^ GetNextMask());
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessInPlace(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] data)
        {
            ProcessInPlace(data, 0, data.Length);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessInPlace(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] data, &lt;span class="kwrd"&gt;int&lt;/span&gt; index, &lt;span class="kwrd"&gt;int&lt;/span&gt; length)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (data == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_S == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Need to call SetKey before calling ProcessInPlace&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (index &amp;lt; 0 || index &amp;gt;= data.Length)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException(&lt;span class="str"&gt;&amp;quot;index&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (length &amp;lt;= 0 || index + length &amp;gt; data.Length)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException(&lt;span class="str"&gt;&amp;quot;length&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; length; i++)
                data[i + index] = (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(data[i + index] ^ GetNextMask());
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] Process(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] data)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; Process(data, 0, data.Length);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] Process(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] data, &lt;span class="kwrd"&gt;int&lt;/span&gt; index, &lt;span class="kwrd"&gt;int&lt;/span&gt; length)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (data == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_S == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Need to call SetKey before calling Process&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (index &amp;lt; 0 || index &amp;gt;= data.Length)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException(&lt;span class="str"&gt;&amp;quot;index&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (length &amp;lt;= 0 || index + length &amp;gt; data.Length)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException(&lt;span class="str"&gt;&amp;quot;length&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] output = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[length];

            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; length; i++)
                output[i] = (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(data[i + index] ^ GetNextMask());
            &lt;span class="kwrd"&gt;return&lt;/span&gt; output;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Process(Stream data, Stream output)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_S == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Need to call SetKey before calling Process&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;int&lt;/span&gt; databyte;
            &lt;span class="kwrd"&gt;while&lt;/span&gt; ((databyte = data.ReadByte()) &amp;gt;= 0)
                output.WriteByte((&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(databyte ^ GetNextMask()));
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Process(Stream data, Stream output, &lt;span class="kwrd"&gt;long&lt;/span&gt; length)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (length &amp;lt;= 0 || data.Position + length &amp;gt; data.Length)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException(&lt;span class="str"&gt;&amp;quot;length&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_S == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Need to call SetKey before calling Process&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;long&lt;/span&gt; i = 0; i &amp;lt; length; i++)
            {
                &lt;span class="kwrd"&gt;int&lt;/span&gt; databyte = data.ReadByte();
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (databyte &amp;lt; 0)
                    &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; EndOfStreamException(&lt;span class="str"&gt;&amp;quot;unexpected end of stream processing RC4&amp;quot;&lt;/span&gt;);
                output.WriteByte((&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(databyte ^ GetNextMask()));
            }
        }
    }
}&lt;/pre&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx&amp;amp;;subject=RC4+in+C%23" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx&amp;amp;;title=RC4+in+C%23" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx&amp;amp;title=RC4+in+C%23" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx&amp;amp;;title=RC4+in+C%23" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx&amp;amp;;title=RC4+in+C%23&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/12/11/rc4-in-c.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=19858" width="1" height="1"&gt;</description></item><item><title>Awesome Support</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx</link><pubDate>Mon, 30 Nov 2009 16:13:56 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:19796</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/19796.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=19796</wfw:commentRss><description>&lt;p&gt;If you’ve had an issue with one of our products or attended a &lt;a href="http://www.atalasoft.com/education/"&gt;webinar&lt;/a&gt;, chances are you’ve spoken with Elaine.&amp;#160; She is the head of support and works with Kevin to help you, our customers, do what you need to do.&amp;#160; I’m very impressed at how well Elaine works with the people that call in.&amp;#160; At various points, I have worked the support lines and I know that I just don’t do that job nearly as well.&amp;#160; I have a great deal of respect for people who do with alacrity what I cannot.&lt;/p&gt;  &lt;p&gt;Elaine carries her support outside of the office as well.&amp;#160; In September, &lt;a href="http://www.atalasoft.com/cs/blogs/office/archive/2009/09/01/support-support.aspx"&gt;she signed up to help raise money&lt;/a&gt; for the &lt;a href="http://www.mdsc.org/"&gt;Massachusetts Down Syndrome Congress&lt;/a&gt;, and played goalie in a hockey game against (retired) Boston Bruins.&amp;#160; This is the second time she has done this, but the first time that she was in the net against the Bruins (in the previous game, she was “traded” for the Bruins goalie to balance things a bit).&lt;/p&gt;  &lt;p&gt;Here is a picture of Elaine at work:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/stevehawley/elainegoalie_17FE8739.jpg"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;" title="elainegoalie" border="0" alt="elainegoalie" src="http://www.atalasoft.com/cs/blogs/stevehawley/elainegoalie_thumb_2DE7F989.jpg" width="504" height="336" /&gt;&lt;/a&gt;the Bruins were rough on her.&amp;#160; She made some good saves, but they scored pretty heavily – just as you might expect pro players to do on any amateur.&amp;#160; I’m deeply, deeply proud of Elaine for doing this event.&amp;#160; The team raised over $40,000 for the MDSC, and a lot of people got to see her working hard on the ice.&amp;#160; Unfortunately, the power in the arena went out just before the end of the first period, so the game was called.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/stevehawley/aliceskating_1245FE44.jpg"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;" title="aliceskating" border="0" alt="aliceskating" src="http://www.atalasoft.com/cs/blogs/stevehawley/aliceskating_thumb_6D483DCA.jpg" width="229" height="281" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;And while I don’t usually talk about personal issues on my professional blog, I’m doubly proud of her because my older child, Alice, has Down syndrome.&amp;#160; The MDSC has done a great deal to help educate my family and my extended family.&amp;#160; Without their resources, I don’t think that we would have the tools to manage the present or have so hopeful a view of the future for her.&amp;#160; Stepping up and getting involved in this event speaks volumes for her caring and commitment, and I appreciate it greatly.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx&amp;amp;;subject=Awesome+Support" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx&amp;amp;;title=Awesome+Support" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx&amp;amp;title=Awesome+Support" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx&amp;amp;;title=Awesome+Support" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx&amp;amp;;title=Awesome+Support&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/30/awesome-support.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=19796" width="1" height="1"&gt;</description></item><item><title>A Few Neat Things – Finding Your Way Around</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx</link><pubDate>Wed, 25 Nov 2009 16:19:23 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:19786</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>0</slash:comments><comments>http://www.atalasoft.com/cs/blogs/stevehawley/comments/19786.aspx</comments><wfw:commentRss>http://www.atalasoft.com/cs/blogs/stevehawley/commentrss.aspx?PostID=19786</wfw:commentRss><description>&lt;p&gt;When I was 12, my local PBS station broadcast a program that forever changed the way that I saw science, technology, and history.&amp;#160; It was the show &lt;a href="http://www.imdb.com/title/tt0078588/"&gt;Connections&lt;/a&gt;, written and hosted by James Burke.&amp;#160; For me, it was the way that history was no longer presented as a function of time, but as a function of change and influence.&amp;#160; He traced the effects of technological changes especially how they enable more and more technologies.&lt;/p&gt;  &lt;p&gt;I thought of that when I was watching &lt;a href="http://www.treehugger.com/files/2009/11/ted-talk-13th-century-astrolabe-the-first-popular-computers.php"&gt;this TED talk about the astrolabe&lt;/a&gt;.&amp;#160; The astrolabe was an early form of celestial computer that could be used for navigation, surveying, and time keeping.&amp;#160; That reminded me of an episode of connections that covered the challenges of ballistics and surveying, which includes the development of the &lt;a href="http://en.wikipedia.org/wiki/Theodolite"&gt;theodolite&lt;/a&gt;.&amp;#160; &lt;a href="http://www.youtube.com/watch?v=jegFEixfe50&amp;amp;feature=PlayList&amp;amp;p=E8DAEDACA0ACFD7F&amp;amp;playnext=1&amp;amp;playnext_from=PL&amp;amp;index=1"&gt;This is a 10 minute segment from the video&lt;/a&gt; – take the time to watch it.&lt;/p&gt;  &lt;p&gt;Now compare the &lt;a href="http://mi.eng.cam.ac.uk/~qp202/my_papers/BMVC09/"&gt;ProFORMA project&lt;/a&gt;, which using a web cam alone can build a 3D model of a shape in front of a web cam.&amp;#160; The tasks are very similar and a lot of the math will be the same.&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx&amp;amp;;subject=A+Few+Neat+Things+%e2%80%93+Finding+Your+Way+Around" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx&amp;amp;;title=A+Few+Neat+Things+%e2%80%93+Finding+Your+Way+Around" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx&amp;amp;title=A+Few+Neat+Things+%e2%80%93+Finding+Your+Way+Around" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx&amp;amp;;title=A+Few+Neat+Things+%e2%80%93+Finding+Your+Way+Around" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx&amp;amp;;title=A+Few+Neat+Things+%e2%80%93+Finding+Your+Way+Around&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2009/11/25/a-few-neat-things-finding-your-way-around.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=19786" width="1" height="1"&gt;</description></item></channel></rss>