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

<channel>
	<title>Nathanael Jones &#187; Image Resizing</title>
	<atom:link href="http://nathanaeljones.com/category/asp-net/image-resizing/feed/" rel="self" type="application/rss+xml" />
	<link>http://nathanaeljones.com</link>
	<description>Ramblings of a computer linguist</description>
	<lastBuildDate>Mon, 04 Jan 2010 21:12:43 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Version 2.1b released!</title>
		<link>http://nathanaeljones.com/438/version-2-1b-released/</link>
		<comments>http://nathanaeljones.com/438/version-2-1b-released/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 23:36:06 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Image Resizing]]></category>

		<guid isPermaLink="false">http://nathanaeljones.com/?p=438</guid>
		<description><![CDATA[Better performance, better installation, better samples, more features! Installation has been simplified to copying and pasting. ]]></description>
			<content:encoded><![CDATA[<p><strong>Better performance, better installation, better samples, more features!</strong></p>
<h2 style="font-size: 1.8em; margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; color: #262625; letter-spacing: -1px; padding: 0px;">Fixed</h2>
<ul>
<li>I finally tracked down a simple, yet elusive performance bug  that was particularly problematic for users with many thousands of images. Performance should be much better for everyone now, so upgrading is highly suggested.  This bug was introduced with version 2.0., and caused a filesystem listing hit for each request.</li>
<li>All requests are now forced to pass through the UrlAuthorizationModule now. Previously, any URL rewriting (like customfolders.cs) caused URL auth rules to be circumvented. This was documented behavior, but a secure solution has now been found.</li>
</ul>
<h2 style="font-size: 1.8em; margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; color: #262625; letter-spacing: -1px; padding: 0px;">Added</h2>
<ul>
<li>New users will find it much easier to get things working &#8211; <strong>Messing with IIS is now completely optional! <img src='http://nathanaeljones.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  <img src='http://nathanaeljones.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </strong><br />
Instead of writing  <em>&#8220;image.jpg?width=500&#8243;</em> as you normally would, type <em>&#8220;image.jpg</em><strong><em>.axd</em></strong><em>?width=500&#8243;</em>. If you use the new syntax, you won&#8217;t be forced to configure wildcard mapping on IIS6/IIS7 classic.<br />
<strong>Both syntaxes will be supported in the future.<br />
<span style="font-weight: normal;">The suggested extension is .axd, but that can be changed or disabled using the ResizeExtension application setting.</span><br />
</strong></li>
<li>Dithering support added! You can dither an 8-bit image using the <strong>?dither=</strong> command. You can specify a dither percent, &#8220;true&#8221;, or &#8220;4pass&#8221;.</li>
<li>UploadSample  project (in VB). Resizing images as they are uploaded is now trivally easy. ImageManager.BuildImage now accepts an HttpPostedFile instance for resizing.</li>
<li>DisableCustomQuantization setting to allow GIFs to be generated on servers where the Marshal class is prohibited.</li>
<li>PerfTests project to run benchmarks on the image resizing and encoding code.</li>
</ul>
<h2 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.8em; margin-left: 0px; color: #262625; font-size: 1.8em; letter-spacing: -1px; padding: 0px; border: 0px initial initial;">Upgrade proccess</h2>
<ol style="padding-top: 0px; padding-right: 0px; padding-bottom: 1.2em; padding-left: 2em; margin: 0px; border: 0px initial initial;">
<li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 20px; list-style-type: decimal; list-style-position: initial; list-style-image: initial; padding: 0px; border: 0px initial initial;">Replace the old files with the new files from the ImageResizer folder. If you are using the .DLL, replace the DLL in the bin folder. Keep your old CustomFolders.cs and WatermarkSettings.cs files if you have modified them.</li>
<li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 20px; list-style-type: decimal; list-style-position: initial; list-style-image: initial; padding: 0px; border: 0px initial initial;">Delete the /imagecache directory.</li>
<li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 20px; list-style-type: decimal; list-style-position: initial; list-style-image: initial; padding: 0px; border: 0px initial initial;">Insert/change the following application settings in web.config if you want to use the new syntax.</li>
</ol>
<blockquote>
<pre>&lt;add key="ResizeExtension" value=".axd"/&gt;</pre>
<pre>&lt;add key="AllowURLRewriting" value="true"/&gt;</pre>
</blockquote>
<p>If you are upgrading from 1.2, <a href="http://nathanaeljones.com/159/image-resizer-2-0-upgrade-notes/">follow the 1.2-&gt;2.0 upgrade instructions first.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/438/version-2-1b-released/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Design of an Image Resizing Module</title>
		<link>http://nathanaeljones.com/196/design-of-an-image-resizing-module/</link>
		<comments>http://nathanaeljones.com/196/design-of-an-image-resizing-module/#comments</comments>
		<pubDate>Tue, 26 May 2009 16:00:28 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[Image Resizing]]></category>

		<guid isPermaLink="false">http://66.29.219.39/?p=196</guid>
		<description><![CDATA[In this sequel to 20 Image Resizing Pitfalls, I'm outlining the architecture of my image resizing module, and including the source code for the HttpModule (but not the supporting classes).]]></description>
			<content:encoded><![CDATA[<p>In this sequel to  20 Image Resizing Pitfalls, I&#8217;m outlining the architecture of my image resizing module, and including the source code for the HttpModule (but not the supporting classes).</p>
<p>Read <a href="/11191_20_Image_Resizing_Pitfalls">20 Image Resizing Pitfalls</a> first (part 1).  It explains why you need an HttpModule instead of an HttpHandler, why disk caching is a requirement, and why you always want to let IIS serve static files.</p>
<p>This article gives an architectural overview of my image resizer. The design has evolved several times as my needs grew, but I think the design has now matured to be very simple, modular, and extensible.</p>
<h3>Request flow</h3>
<ol class="normallist">
<li>Only intercept image requests that include certain querystring commands. Leave other requests intact. </li>
<li>Check to see if the resized image for the request URL is already cached. If cached and still up-to-date with the source file, goto step 4.</li>
<li>If not already cached, process the image and cache it. </li>
<li>Rewrite the request (not redirect) to the cached file. This will allow IIS to serve the file with full HTTP support (range requests, caching, not-modified support, etc).</li>
</ol>
<h3>A few other goals</h3>
<ol class="normallist">
<li>Allow custom syntaxes like /resize(50,50)/image.jpg or ?theme=smallthumb to be easily added without bloating the core module. </li>
<li>Permit or disable filename rewriting from Web.config. /resize(50,50)/ would be path rewriting, wheras ?theme=smallthumb would be just rewriting the querystring. This configurability is important, since path rewriting could make subfolder-based web.config authorization settings on image files have no effect.</li>
<li>Allow client caching time to be configurable. This will keep requests down, since clients won&#8217;t check for updates until the specified amount of time expires.</li>
<li>Make both server-side memory and disk  caching invalidate when the source file changes.</li>
<li>Allow a easily extensible and large set of commands, affecting the cropping/sizing, visual effects, color choices/border/padding, and image output format/compression.</li>
<li>Prevent DOS attacks by limiting the disk cache to a configurable number of images.</li>
<li>Allow easy watermarking or post-processing of resized images</li>
</ol>
<h2>Overview of classes</h2>
<p>With these goals in mind, I found it optimal to segment the logic into the following classes. While you may question my decision to split querystring parsing into 4 classes, it resulted in much cleaner code, and a much more usable interface for image manipulation from other classes. </p>
<ul class="normallist">
<li><strong>InterceptModule</strong><br />
IHttpModule that checks for relevant requests during PostAuthorizeRequest, caches the ImageManger-proccessed images using DiskCache, and rewrites the request to the cached file. It also sets HTTP caching headers later in PreSendRequestHeaders. The disk-cached filename is an SHA256, base16 encoded hash of the request URL. Although the image is coming from a different file, the user never sees the URL of the cached file &#8211; the original filename is maintained.</li>
<li><strong>DiskCache</strong>
<p>Completely abstracts away disk caching, cleanup, and the associated threading issues. InterceptModule calls method <em>UpdateCachedVersionIfNeeded(sourceFile,cachedFile, delegate updateMethod, int fileLockTimeout)</em> with   <em>ImageManager.getBestInstance().BuildImage(sourcePath, cachedPath, queryString);</em> as the contents of the delegate. DiskCache performs the modified date checks, cache cleanup, and thread locking to prevent the same image from being resizied by two different threads at the same time (it happens frequently!). The delegate is only executed if the cached file needs to be created or updated.</li>
<li><strong>CustomFolders</strong><br />
Exposes a single method,  static string processPath(string filePath, NameValueCollection q). This allows both URL rewriting and modifications to the querystring, such as /resize(w,h)/ syntax. InterceptModule simply calls this once prior to checking the querystring for valid commands.</li>
<li><strong>ImageManager</strong>
<p> exposes several overloads of a method called BuildImage() which allow both querystring and settings class configuration, and both bitmap and filename source and output. While BuildImage performs all the actual GDI calls, the querystring parsing, mathematics, and image writing are handled by other classes below.</li>
<li><strong>ResizeSettings</strong>(querystring)<br />
 Accepts a single NameValueCollection (Querystring) as the constructor argument. Stretch, crop, scale, flip, sourceFlip, width, height, maxwidth, and maxheight are parsed into member variables. Exposes a  <em>ImageSizingData CalculateSizingData(SizeF originalImageSize, SizeF maxBounds)</em> method that handles all mathematics. ImageSizingData includes the source rectangle on the image to copy from, the destination polygon for the image data, and a polygon that includes any whitespace.</li>
<li><strong>ImageOutputSettings</strong>(querystring) 
<p>Parses the format, colors, and quality commands. It also exposes a SaveImage(Stream s, Image i) method that handles the writing of the various image types based on the querystring arguments. Static methods for saving images are also available.</li>
<li><strong>ImageSettings</strong>(querystring) <br />
Parses the bgcolor, paddingWidth, paddingColor, borderWidth, and borderColor commands. BuildImage() uses this data when drawing the image.</li>
<li><strong>WatermarkSettings</strong>(querystring)<br /> allows for custom drawing on images. It exposes a  <em>ModifySettings(ResizeSettings rs, ImageSettings opts, ImageFilter adjustments, ImageOutputSettings ios)</em> method for adjusting settings prior to resizing, and a <em>Process(Bitmap b, Graphics g)</em> method for post-processing of resized images.</li>
</ul>
<h2>InterceptModule code</h2>
<p>I hope this overview is clear enough &#8211; if not, please leave a question below. Understanding the design, the source code for InterceptModule should now make sense. Thankfully, this is one of the shortest classes, but it should help you write your own HttpModule. I&#8217;ve removed the class declaration, imports, and profiling code for clarity. The original source code comments explain everything pretty clearly.</p>
<pre name="code" class="brush:c-sharp">
/// &lt;summary&gt;
/// This is where we filter requests and intercet those that want resizing performed.
/// We first check for image extensions...
/// If it is one, then we run it through the CustomFolders method to see if if there is custom resizing for it..
/// If there still aren't any querystring params after that, then we ignore the request.
/// If the file doesn't exist, we also ignore the request. They're going to cause a 404 anyway.
///
/// &lt;/summary&gt;

/// &lt;param name=&quot;sender&quot;&gt;&lt;/param&gt;
/// &lt;param name=&quot;e&quot;&gt;&lt;/param&gt;
protected virtual void CheckRequest_PostAuthorizeRequest(object sender, EventArgs e)
{
	//Get the http context, and only intercept requests where the Request object is actually populated
	HttpApplication app = sender as HttpApplication;
	if (app != null &amp;&amp; app.Context != null &amp;&amp; app.Context.Request != null)
	{

		//Is this an image request? Checks the file extension for .jpg, .png, .tiff, etc.
		if (ImageOutputSettings.IsAcceptedImageType(app.Context.Request.FilePath))
		{
			//Init the caching settings. These only take effect if the image is actually resized
			//CustomFolders.cs can override these during processPath
			app.Context.Items[&quot;ContentExpires&quot;] = DateTime.Now.AddHours(24); //Default to 24 hours
			string cacheSetting = ConfigurationManager.AppSettings[&quot;ImageResizerClientCacheMinutes&quot;];
			if (!string.IsNullOrEmpty(cacheSetting)){
				double f;
				if (double.TryParse(cacheSetting,out f)){
					if (f &gt;= 0)
						app.Context.Items[&quot;ContentExpires&quot;] = DateTime.Now.AddMinutes(f);
					else
						app.Context.Items[&quot;ContentExpires&quot;] = null;
				}
			}

			//Copy the querystring
			NameValueCollection q = new NameValueCollection(app.Context.Request.QueryString);

			//Call CustomFolders.cs to do resize(w,h,f)/ parsing and any other custom syntax.
			//The real virtual path should be returned (with the resize() stuff removed)
			//And q should be populated with the querystring values
			string basePath = CustomFolders.processPath(app.Context.Request.Path, q);

			//If the path has changed, this will circumvent the URL auth system.
			//Make sure the user has explicity allowed it through web.config
			if (!basePath.Equals(app.Context.Request.Path))
			{
				//Make sure the resize() notation is allowed.
				string allow = ConfigurationManager.AppSettings[&quot;AllowURLRewriting&quot;];
				if (string.IsNullOrEmpty(allow)) allow =ConfigurationManager.AppSettings[&quot;AllowFolderResizeNotation&quot;];
				if (string.IsNullOrEmpty(allow) || allow.Equals(&quot;false&quot;, StringComparison.OrdinalIgnoreCase)){
					return; //Skip the request
				}
				//Prevent access to the /imagecache/ directory (URL auth won't be protecting it now)
				if (new yrl(basePath).Local.StartsWith(DiskCache.GetCacheDir(), StringComparison.OrdinalIgnoreCase))
				{
					throw new HttpException(403, &quot;Access denied to image cache folder.&quot;);
				}
			}
			//See if resizing is wanted (i.e. one of the querystring commands is present).
			//Called after processPath so processPath can add them if needed.
			//Checks for thumnail, format, width, height, maxwidth, maxheight and a lot more
			if (ImageManager.getBestInstance().HasResizingDirective(q))
			{
				//Build a URL using the new basePath and the new Querystring q
				yrl current = new yrl(basePath);
				current.QueryString = q;

				//If the file exists, resize it
				if (current.FileExists)
					ResizeRequest(app.Context,current);

			}
		}
	}
}

/// &lt;summary&gt;

/// Builds the physical path for the cached version, using the hashcode of the normalized URL.
/// &lt;/summary&gt;
/// &lt;param name=&quot;request&quot;&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
protected string getCachedVersionFilename(yrl request)
{
	string dir = DiskCache.GetCacheDir();
	if (dir == null) return null;
	//Build the physical path of the cached version, using the hashcode of the normalized URL.
        //We don't use String.GetHashCode(), since it returns a 32-bit integer. Chances of a hash collision are low, but possible.
        // So, we use a 256-bit hash instead.
	SHA256 h = System.Security.Cryptography.SHA256.Create();
	byte[] hash = h.ComputeHash(new System.Text.UTF8Encoding().GetBytes(request.ToString().ToLower()));
	//Can't use base64 hash... filesystem has case-insensitive lookup.
	//Would use base32, but too much code to bloat the resizer. Simple base16 encoding is fine
	return dir.TrimEnd('/', '\\') + &quot;\\&quot; + Base16Encode(hash) + &quot;.&quot; + new ImageOutputSettings(request).GetFinalExtension();
}
/// &lt;summary&gt;

/// Returns a lowercase hexadecimal encoding of the specified binary data
/// &lt;/summary&gt;
protected string Base16Encode(byte[] bytes)
{
	StringBuilder sb = new StringBuilder(bytes.Length * 2);
	foreach (byte b in bytes)
		sb.Append(b.ToString(&quot;x&quot;).PadLeft(2, '0'));
	return sb.ToString();
}

/// &lt;summary&gt;
/// Generates the resized image to disk (if needed), then rewrites the request to that location.
/// Perform 404 checking before calling this method. Assumes file exists.
/// Called during PostAuthorizeRequest
/// &lt;/summary&gt;
/// &lt;param name=&quot;r&quot;&gt;&lt;/param&gt;
/// &lt;param name=&quot;extension&quot;&gt;&lt;/param&gt;

protected virtual void ResizeRequest(HttpContext context, yrl current)
{
	//This is where the cached version goes
	string cachedFile = getCachedVersionFilename(current);

	//Disk caching is good for images because they change much less often than the application restarts.

	//Make sure the resized image is in the disk cache.
	bool succeeded = DiskCache.UpdateCachedVersionIfNeeded(current.Local, cachedFile,
		delegate(){

			//This runs if the update is needed. This delegate is preventing from running in more
			//than one thread at a time for the specified source file (current.Local)
			ImageManager.getBestInstance().BuildImage(current.Local, cachedFile, current.QueryString);
		},30000);

	//If a co-occurring resize has the file locked for more than 30 seconds, quit with an error.
	if (!succeeded)
		throw new ApplicationException(&quot;Failed to acquire a lock on file \&quot;&quot; + current.Virtual +
                                              &quot;\&quot; within 30 seconds. Image resizing failed.&quot;);

	//Get domain-relative path of cached file.
	string virtualPath = yrl.GetAppFolderName().TrimEnd(new char[] { '/' }) + &quot;/&quot; + yrl.FromPhysicalString(cachedFile).ToString();

	//Add content-type headers (they're not added correctly when the source URL extension is wrong)
	//Determine content-type string;
	string contentType = new ImageOutputSettings(current).GetContentType();

	context.Items[&quot;FinalContentType&quot;] = contentType;
	context.Items[&quot;FinalCachedFile&quot;] = cachedFile;

	//Rewrite to cached, resized image.
	context.RewritePath(virtualPath, false);
}
/// &lt;summary&gt;

/// We don't actually send the data - but we still want to control the headers on the data.
/// PreSendRequestHeaders allows us to change the content-type and cache headers at excatly the last
/// second. We populate the headers from context.Items[&quot;FinalContentType&quot;],
/// context.Items[&quot;ContentExpires&quot;], and context.Items[&quot;FinalCachedFile&quot;].
/// This also indirectly enables server-side mem caching. (HttpCacheability.Public does it)
/// We set the file dependency to FinalCachedFile so changes are update quickly server-side
/// - however, clients will not check for updates until ContentExpires occurs.
///
/// &lt;/summary&gt;
/// &lt;param name=&quot;sender&quot;&gt;&lt;/param&gt;
/// &lt;param name=&quot;e&quot;&gt;&lt;/param&gt;

protected void context_PreSendRequestHeaders(object sender, EventArgs e)
{
	HttpApplication app = sender as HttpApplication;
	HttpContext context = (app != null) ? app.Context : null;
	//Check to ensure the context and Response is in good shape (it's needed)
	if (context != null &amp;&amp; context.Items != null &amp;&amp; context.Items[&quot;FinalContentType&quot;] != null
                          &amp;&amp; context.Items[&quot;FinalCachedFile&quot;] != null)
	{
		//Clear previous output
		//context.Response.Clear();
		context.Response.ContentType = context.Items[&quot;FinalContentType&quot;].ToString();
		//Add caching headers
		context.Response.AddFileDependency(context.Items[&quot;FinalCachedFile&quot;].ToString());

		//It's not UTC - server time zone.
		if (context.Items[&quot;ContentExpires&quot;] != null)
			context.Response.Cache.SetExpires((DateTime)context.Items[&quot;ContentExpires&quot;]);

		//Enables in-memory caching
		context.Response.Cache.SetCacheability(HttpCacheability.Public);
		context.Response.Cache.SetLastModifiedFromFileDependencies();
		context.Response.Cache.SetValidUntilExpires(false);
	}

}
</pre>
<p>I&#8217;m sure a lot of people will think I&#8217;m nuts for posting the source code to the main class of my image resizer,<br />
but I know that this will help a lot of people.  </p>
<p>Based on the response I get to this article, I may continue with additional parts. I would like to cover the math behind scaling and cropping, the GDI bugs, and maybe even image output/compression. </p>
<p>Hope this helps!<br />Nathanael</p>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/196/design-of-an-image-resizing-module/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Demo Version of Image Resizing Module</title>
		<link>http://nathanaeljones.com/199/demo-version-of-image-resizing-module/</link>
		<comments>http://nathanaeljones.com/199/demo-version-of-image-resizing-module/#comments</comments>
		<pubDate>Thu, 21 May 2009 16:00:35 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[Image Resizing]]></category>
		<category><![CDATA[image resizer]]></category>

		<guid isPermaLink="false">http://66.29.219.39/?p=199</guid>
		<description><![CDATA[I've received many requests for a 'trial' version of the image resizer. This demo version is fully-functional, but watermarks 50% of the generated images with "Unlicensed".]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve received many requests for a &#8216;trial&#8217; of the <a href="/products/asp-net-image-resizer/">image resizer</a>. This demo version is fully-functional, but watermarks 50% of the generated images with &#8220;Unlicensed&#8221;. Another note: the trial version includes supports resizing animated GIFs. That plug-in isn&#8217;t included in the default version; contact me for details.</p>
<p>Installation is the <a href="/11141_Image_Resizer_Installation">same as for the full version</a>.</p>
<p><a onclick="javascript:pageTracker._trackPageview('/download/resizertrial');" href="/wp-content/uploads/2009/11/ImageResizer2.1b-Nov-3-09-Trial-Version.zip">Download Trial version and sample project (4MB)</a></p>
<p>When you upgrade to the full version, remember to delete the <em>imagecache</em> directory, or you will continue to see the word &#8220;Unlicensed&#8221; on old pictures.</p>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/199/demo-version-of-image-resizing-module/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>20 Image Resizing Pitfalls</title>
		<link>http://nathanaeljones.com/163/20-image-resizing-pitfalls/</link>
		<comments>http://nathanaeljones.com/163/20-image-resizing-pitfalls/#comments</comments>
		<pubDate>Tue, 19 May 2009 15:18:49 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[Image Resizing]]></category>
		<category><![CDATA[image resizer]]></category>

		<guid isPermaLink="false">http://66.29.219.39/?p=163</guid>
		<description><![CDATA[Dozens of articles on server-side image resizing have been written. If we count other tongues, maybe hundreds. These contributions to the community have been invaluable to me, and I truly appreciate the time each author spent to share his or her knowledge.]]></description>
			<content:encoded><![CDATA[<p>
        Dozens of articles on server-side image resizing have been written. If we count other tongues, maybe hundreds. These contributions to the community<br />
        have been invaluable to me, and I truly appreciate the time each author spent to share his or her knowledge.</p>
<p>
        So why am I writing another? </p>
<p>
        Because each article I have read includes one of the errors below, leading readers to write either<br />
        slow, insecure, or incorrectly functioning code.  I have discovered many of these pitfalls the hard way.<br />
         I hope others won&#8217;t have to.
         </p>
<p>Instead of giving step-by-step instructions, this article will simply list pitfalls and the alternatives. I hope to publish my approach in a Part 2.</p>
<h2>
        Security and Performance Pitfalls</h2>
<ol class="normallist">
<li>Not using using(){}. You *must* wrap your Graphics, Bitmap, and MemoryStream objects<br />
            in a using(){} clause, or else they will not get cleaned out of memory for a while.<br />
            Under load this can cause *serious* issues. Read<br />
            <a href="http://blogs.msdn.com/tess/archive/2009/02/03/net-memory-leak-to-dispose-or-not-to-dispose-that-s-the-1-gb-question.aspx"><br />
                <em>to dispose, or not to dispose, that&#8217;s the 1GB question</em></a> if you have<br />
            any doubts regarding the severity of this error.</p>
<p>If you find yourself nesting a lot of using(){} statements, you can also use equivalent try{}finally{} code.</p>
<pre name="code" class="brush:c-sharp">
//Using method. object must implement IDisposable for this to work
using (object a = new object())
{
    using (object b = new object())
    {
        using (object c = new object())
        {

        }
    }
}

//Try finally method
object a = null;
object b = null;
object c = null;
try
{
    a = new object();
    b = new object();
    c = new object();
}
finally
{
    if (a != null) a.Dispose(); //If one of the Dispose methods throws an error, the others will not execute.
    if (b != null) b.Dispose(); //So there is an advantage to using nested using(){} clauses
    if (c != null) c.Dispose(); //You could nest try{} finally{ try{} finally{ try{} finally{}}} to solve that...
    //Two different techniques - take your pick
}
</pre>
</li>
<li>Using on-the-fly image resizing <em>without</em> disk caching! The ASP.NET<br />
            memory cache won&#8217;t cut it here folks &#8211; it gets cleaned out every application reboot,<br />
            and besides, you probably have more images than RAM. Resizing an image is fast,<br />
            but it will still flood the CPU if a single user browses a single page with 20 or more<br />
            resized images on it. This is a do-it-yourself <a href="http://en.wikipedia.org/wiki/Denial-of-service_attack"><br />
                DOS</a> attack. On-the-fly resizing is fine if you have disk caching. </li>
<li><em>Not</em> using on-the-fly resizing. This one bites also. If you decide to convert all<br />
            your images up-front, please realize how difficult it will be to track down the<br />
            originals and resizing them again next time you make a resolution jump. I&#8217;ve been<br />
            through this enough, and it&#8217;s painful &#8211; that&#8217;s why I wrote a dynamic image resizer!
        </li>
<li>Disk-caching without checking for updated (or reverted!) source files. Debugging<br />
            a resized image that won&#8217;t update can eat up lots of time. Make sure you set the<br />
            LastWriteTimeUTC on your cached images to match the source image file (and check<br />
            they match) &#8211; don&#8217;t simply check to see if the source file is newer than the cached<br />
            file, since that will break if you copy an older file over a source image. Always<br />
            use something like RoughCompare() to compare filesystem dates &#8211; *never* inequalities.<br />
            Remember that filesystem dates are less precise than DateTime, and get rounded.</p>
<pre name="code" class="brush:c-sharp">
/// &lt;summary&gt;
/// Returns true if both dates are equal (to the nearest 200th of a second)
/// &lt;/summary&gt;
/// &lt;param name=&quot;modifiedOn&quot;&gt;&lt;/param&gt;
/// &lt;param name=&quot;dateTime&quot;&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
private static bool RoughCompare(DateTime d1, DateTime d2)
{
	return (new TimeSpan((long)Math.Abs(d1.Ticks - d2.Ticks)).Milliseconds &lt;= 5);
}
</pre>
</li>
<li>Disk-caching without cleanup! Another do-it-yourself <a href="http://en.wikipedia.org/wiki/Denial-of-service_attack"><br />
            DOS</a> attack, although not quite as bad as the first. Left unchecked, your cache<br />
            directory could grow very large over a few years as orphaned<br />
            image versions accumulate. If a malicious visitor realizes that you have automatic resizing,<br />
            he could try to fill up your hard drive by requesting an endless variety of resolutions<br />
            for a given image. Of course, security-conscious developers will have cache-limiting<br />
            systems in place. I suggest cleaning out the least recently used 10-20% of the cache<br />
            directory whenever the file limit is reached. Handle locked files gracefully.</li>
<li>Checking the cache size for cleanup every image request. This will swamp your I/O.<br />
        Instead of running that directory listing each time, keep a static counter that  tracks how many <em>new</em> images have been resized<br />
        since the application started. Run the cache cleanup on the first image request and each time the counter passes the cleanup threshold.</li>
<li>Disk caching without protecting the cache directory. Unless you want anonymous users to potentially view the same images<br />
        as authorized users, you need your cache directory locked down. A Web.config file in the directory can do this &#8211; just verify your URL rewriting rules<br />
        don&#8217;t leave another way to access the directory. </p>
<p>
        The cache directory needs to stay inside the application to permit request rewriting to the cached files.  </p>
</li>
<li>Disk caching without proper locking code. This is a minor problem, since the<br />
            consequences are light &#8211; but it is good to remember that 2 image requests for the<br />
            same image size could happen at the same time, and (if they aren&#8217;t cached), they<br />
            may conflict when trying to write to the same file at the same time. You&#8217;ll probably<br />
            get a &#8220;The process cannot access the file because it is being used by another process.&#8221;<br />
            message if this happens. You can prevent this by creating a locking system so that<br />
            only one thread can save a give resized image at a time. Optimally, you want multiple resizes for different images to occur at the same time. If you&#8217;re<br />
            not as concerned about concurrency performance as I was, you could cheat at make the whole resizing method locked. (For new image requests only!) </li>
<li>Writing directly to the output stream. If you&#8217;re caching to disk, but still serving<br />
            the image contents in code, you&#8217;re only supporting a little bit of the HTTP standard,<br />
            and you&#8217;re bypassing all of the work <a id="A1" href="~/11081" runat="server">Thomas<br />
                Marquardt did to bring StaticFileHandler up to snuff</a> . Implement your resizer<br />
                as and HttpModule, not an HttpHandler or you&#8217;re stuck.</li>
<li>Serving a file from disk by loading it into memory. Think about how much RAM your server has,<br />
        how large a single image is, how long<br />
            it has to stay in memory before users finish downloading it, and how many users<br />
            you have requesting images. Don&#8217;t load anything into memory after the initial resize.</p>
<p><a href="http://msdn.microsoft.com/en-us/library/dyfzssz9.aspx">WriteFile()</a><br />
            serves directly from disk, and is *much* safer and more efficient. However &#8211; you<br />
            shouldn&#8217;t be using WriteFile() either if you can avoid it. Letting StaticFileHandler<br />
            do its job is a much better choice. </p>
</li>
<li>Making an HttpHandler instead of an HttpModule. I actually did this in<br />
            v1.0, and it was a *mess*, as well as being non-optimal from a performance standpoint.<br />
            There are several problems with doing this as an HttpHandler.</p>
<ol class="normallist">
<li>It&#8217;s very difficult to make an HttpHandler catch only *some* requests (i.e., those<br />
                    requesting resizing), for a certain extension. It&#8217;s very hard, in fact, and involves<br />
                    subclassing DefaultHttpHandler and re-implementing a lot of code. While that&#8217;s possible<br />
                    on IIS5/6/7 classic, it doesn&#8217;t work on IIS7 Integrated. So IIS7 integrated is a<br />
                    complete deal-breaker if you want to let standard images alone. </li>
<li>It&#8217;s difficult to pass a request from one HttpHandler to another. When building<br />
                    an image resizer, we don&#8217;t want to be responsible for serving the resized file,<br />
                    just making sure the resized version has been cached to disk, and then rewriting<br />
                    the request to point to that file. An HttpModule, on the other hand, is perfectly<br />
                    suited to checking for image resize requests, caching the results, and rewriting<br />
                    the request so StaticFileHandler or whatever is the default in IIS 8 , 9, or 10<br />
                    can take of it. I do this in PostAuthorizeRequest, by calling context.RewritePath(virtualPath, false);</li>
</ol>
</li>
<li>Not setting context.Response.ContentType properly. You&#8217;ll get all kinds of interesting,<br />
            varied, and peculiar results from browsers if you omit this step. Things can be really<br />
            interesting if the format is changed during the resize, since the extension will<br />
            match the original format. </li>
<li>Obvious, but you should have caching enabled for your images, regardless<br />
            of whether they are being resized or not. Disk caching is great, but memory caching allows for even faster responses to frequently requested images, and shouldn&#8217;t be omitted.<br />
            In addition, HttpCacheability.Public enables client and proxy caching too, so browsers and some firewalls will cache the result from the server. You can adjust the amount of time<br />
            the files are cached with SetExpires.</p>
<p>
            This is the code I use during PreSendRequestHeaders
        </p>
<pre name="code" class="brush:c-sharp">
HttpApplication app = sender as HttpApplication;
HttpContext context = (app != null) ? app.Context : null;

if (context != null &amp;&amp; context.Items != null &amp;&amp; context.Items[&quot;FinalContentType&quot;] != null &amp;&amp; context.Items[&quot;FinalCachedFile&quot;] != null)
{
	//Clear previous output
	//context.Response.Clear();
	context.Response.ContentType = context.Items[&quot;FinalContentType&quot;].ToString(); //FinalContentType is set to image/jpeg or whatever the image mime-type is earlier in code.
	//Add caching headers
	context.Response.AddFileDependency(context.Items[&quot;FinalCachedFile&quot;].ToString());

	if (context.Items[&quot;ContentExpires&quot;] != null)
		context.Response.Cache.SetExpires((DateTime)context.Items[&quot;ContentExpires&quot;]); //ContentExpires is set to DateTime.Now.AddMinutes(x), where x is how long the clients should locally cache the image before checking for updates.

	//Enables in-memory caching
	context.Response.Cache.SetCacheability(HttpCacheability.Public);
	context.Response.Cache.SetLastModifiedFromFileDependencies();
	context.Response.Cache.SetValidUntilExpires(false);
}
</pre>
</li>
<li>Accepting the file path as a querystring parameter. This mistake makes me cringe<br />
            &#8211; I find it amazing each time how much people trust their filtering code to prevent<br />
            abuse of this feature. (If they have path filtering code at all!) Just&#8230; don&#8217;t&#8230;<br />
            do it&#8230; please. Do you know how many ways there are to encode filenames and circumvent<br />
            pattern-matching techniques? Yes, there are ways to protect this kind of system, but why?</p>
<p>Why choose /resizeimage.ashx?path=~%2fimg%2fproducts%2fbox.jpg&amp;maxwidth=100&amp;maxheight=100<br />
            over /img/products/box.jpg?maxwidth=100&amp;maxheight=100 ?</p>
<p>
            If you&#8217;re stuck in IIS6 and you aren&#8217;t allowed to modify handler mappings, you should look for a better host.</p>
</li>
</ol>
<h2>
        Pitfalls in Image Resizing</h2>
<ol class="normallist">
<li>Using GetThumbnailImage(). <a href="http://msdn.microsoft.com/en-us/library/system.drawing.image.getthumbnailimage.aspx"><br />
            GetThumbnailImage</a>() seems the obvious choice, and many articles recommend its<br />
            use.<br />
            Unfortunately, it always grabs the embedded jpeg thumbnail if present.<br />
            Some photos have these, some don&#8217;t &#8211; it usually depends on your camera. You&#8217;ll wonder<br />
            why GetThumbnailImage works good on some photo, but on others is horribly<br />
            blurred. GetThumbnailImage() isn&#8217;t reliable for photos larger than 10px by 10px for that reason.</li>
<li>Forgetting to set InterpolationMode, SmoothingMode, CompositingQuality, and PixelOffsetMode.<br />
            With all these set properly, you<br />
            should be able to get resized images indistinguishable from Photoshop results. If<br />
            you don&#8217;t, you&#8217;ll end up with trash. GDI has dumb defaults. (BTW, the low-quality<br />
            settings aren&#8217;t always much faster) <a href="http://www.glennjones.net/Post/799/Highqualitydynamicallyresizedimageswithnet.htm"><br />
                This article</a> explains why those are needed to make DrawImage compose the<br />
            image well.</p>
<pre name="code" class="brush:c-sharp">
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode  = SmoothingMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
            </pre>
</li>
<li>Not maintaining aspect ratio. I see this often, and I&#8217;m not sure why &#8211; the math<br />
            isn&#8217;t too hard. Well, for those who are wondering how, I hope this code is rather<br />
            transparent (no pun intended).</p>
<pre name="code" class="brush:c-sharp">
double aspectRatio = imageWidth/imageHeight;
double boxRatio = maxWidth/maxHeight;
double scaleFactor = 0;
if (boxRatio &gt; aspectRatio)
 //Use height, since that is the most restrictive dimension of box.
 scaleFactor = maxHeight / imageHeight;
else
 scaleFactor = maxWidth / imageWidth;

double newWidth = imageWidth * scaleFactor;
double newHeight = imageHeight * scaleFactor;
</pre>
</li>
<li>Not setting the Jpeg quality to 90. You&#8217;ll get huge Jpegs from Image.Save unless<br />
            you pass in the proper parameters. 90 seems to be the magic value &#8211; great quality<br />
            and much lower file size than 100.</p>
<pre name="code" class="brush:c-sharp">
int quality = 90; //90 is the magic setting - really. It has excellent quality and file size.
System.Drawing.Imaging.EncoderParameters encoderParameters = new System.Drawing.Imaging.EncoderParameters(1);
encoderParameters.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)quality);
thumb.Save(stream, GetImageCodeInfo(&quot;image/jpeg&quot;), encoderParameters);

/// &lt;summary&gt;
/// Returns the first ImageCodeInfo instance with the specified mime type. Some people try to get the ImageCodeInfo instance by index - sounds rather fragile to me.
/// &lt;/summary&gt;
/// &lt;param name=&quot;mimeType&quot;&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public static ImageCodecInfo GetImageCodeInfo(string mimeType)
{
	ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
	foreach (ImageCodecInfo ici in info)
		if (ici.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase)) return ici;
	return null;
}
</pre>
</li>
<li>Using the built-in quantization (palette creation) for GIFs, 8-bit PNGs and BMPs.<br />
            The default palette is truly terrible, and while you can specify your own set of<br />
            255 colors &#8211; which ones should they be? The process of determining which colors<br />
            to choose for the palette and to produce the best quality images is call quantization.<br />
            I recommend the very efficient and decent-quality <a href="http://codebetter.com/blogs/brendan.tompkins/archive/2004/01/26/use-gdi-to-save-crystal-clear-gif-images-with-net.aspx"><br />
                octree quantization algorithm</a>. It does have a number of bugs you will have<br />
            to patch. Follow the transparency patch instructions found in the comments. Use the safe version of the library. Patch the Marshal.ReadInt32() bug (original is ReadByte()).<br />
            Change any casts from IntPtr->int to IntPtr->long to make the code 64-bit safe.</p>
<p>I&#8217;m working on adding adjustable Floyd-Steinberg dithering to <a href="http://nathanaeljones.com/products/asp-net-image-resizer/">the version in my resizer </a>, and<br />
           the results have been very promising so far.</p>
</li>
<li>Inheriting the palette from the original image. While at first this seems like an<br />
            <a href="http://getlara.com/north-america/canada/alberta/edmonton/post/2008/10/13/png-jpg-gif-image-resize-with-net-with-transparency"><br />
                easy way to solve the palette problem</a> for GIFs, realize that the bicubic<br />
            resizing will have combined colors, and the new thumbnail may not have any of colors<br />
            of the original image. Also, any operations performed on the bitmap in 8-bit mode<br />
            will be poor quality, and this won&#8217;t allow conversion between image formats. There are<br />
            other ways to keep transparency. This is probably better than leaving the default palette, but YMMV.</li>
<li>Resizing images that don&#8217;t request it. Your code should only activate when an image has a querystring with one of the supported<br />
        commands. Pushing all images through your code is unnecessary. </li>
<li>And one last piece of advice.<strong> Have Good Defaults. Always.</strong>
<p>The output image type should default to the source image type, unless it&#8217;s a BMP or TIFF.<br />
        Default behavior should always preserve aspect ratio.
        </p>
<p>Many developers stop after making their code configurable. They don&#8217;t take that extra 10 minutes to give<br />
        everything smart defaults. Smart defaults distinguish good software from <em>great</em> software.</p>
</li>
</ol>
<p>I hope to post Part 2 soon. I plan on revealing the architecture that has evolved in my resizer,<br />
    and how to design a IIS5/6/7 compatible HttpModule.</p>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/163/20-image-resizing-pitfalls/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Server-side Image Resizing Module for ASP.NET, ASP, &amp; PHP/IIS</title>
		<link>http://nathanaeljones.com/162/server-side-image-resizing-module-for-asp-net-asp-phpiis-3/</link>
		<comments>http://nathanaeljones.com/162/server-side-image-resizing-module-for-asp-net-asp-phpiis-3/#comments</comments>
		<pubDate>Sun, 17 May 2009 04:20:03 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[Image Resizing]]></category>
		<category><![CDATA[image resizer]]></category>

		<guid isPermaLink="false">http://66.29.219.39/?p=162</guid>
		<description><![CDATA[Version 2.0 beta is now available!]]></description>
			<content:encoded><![CDATA[
<p style="position: absolute; height: 5px; width: 5px; top: -3000px">
Open-source image resizing module for ASP.NET. Great for thumbnails and slideshows. Features managed disk caching, jpeg/png/gif support, and bicubic resizing.
</p>
<p><script type="text/javascript">
	$(function() {
		$("#tabs").tabs();
	});
	</script></p>
<style type="text/css">
div.articleBody {
line-height:2.1em;
padding:15px 15px 15px 15px;
}
.smallcomments blockquote{
line-height:1em; font-size:8pt;
}
</style>
<div id="tabs">
<ul>
<li><a href="#why">Why</a></li>
<li><a href="#opensource">Open Source</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#quality">Quality</a></li>
<li><a href="#performance">Performance</a></li>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#changelog">Changelog</a></li>
</ul>
<div id="why">
<h3>You need this module if you work with images.</h3>
<p>Once installed, you can size, crop, and change the format of images from anywhere&#8230; HTML, ASP.NET, ASP, PHP, Flex, or Flash &#8230; Just add the desired behavior to the URL with &#8220;?width=100&#8243; or &#8220;?format=jpg&#8221;. It supports scaling, cropping, rotating, flipping, stretching, padding, borders, transparency, jpeg, png, and gif formats. Aspect ratio is <em>always</em> maintained unless &#038;stretch=fill is specified.
</p>
<p class="rightbox">The difference between the actual size and wanted size  of an uploaded image is inversely proportional to the quantiy of time available and the sluggishness of Photoshop.</p>
<p>Server-side image resizing is one of those little features that can have incredible ROI. It can save webmasters several hours each day, and gives you the ability to change the resolution of an image without having to hunt up the original. <%--However, many of the approaches currently on the web don't take security or performance into account.--%></p>
<p>I developed this image resizing system around two years ago. I needed something very intuitive, simple, secure, and efficient. We&#8217;ve been using this system heavily on a live, high-traffic site (<a href="http://youngfoundations.org">youngfoundations.org</a>) for two years, and we have had zero stability problems, memory leaks, or reliability issues with it. It&#8217;s very mature and stable. Version 2.0 is even faster and more scalable than the previous versions, and includes dozens of new features.</p>
<p>Check out the <a href="~/11201" runat="server">samples page</a> to see what it can do. The <a href="~/11151" runat="server">license</a> is much like the GPL, and allows you to redistribute the source code as part of a larger project. You&#8217;ll find the source code very clean, organized, and well commented. </p>
<div class="rightbox">
<a class="download" href="https://www.e-junkie.com/ecom/gb.php?i=254264&#038;c=single&#038;cl=41912">Download Source ($69)</a></p>
<p style="margin-bottom:0;padding-top:0;font-size:7.5pt; color:#909090;">Includes v2.0b &#8211; May 16, 2009</p>
<p><a href="~/11151" runat="server">License</a><br />
<a href="~/11201" runat="server">Samples</a><br />
<a href="~/11141" runat="server">Installation</a></p>
<p>If you have any questions after reading the documentation, leave a comment or e-mail <strong>nathanael.jones@gmail.com</strong>. </p>
</div>
<p>Although I typically release my components for free, I decided to charge a &#8216;download fee&#8217; for this one to help support my other open-source projects. Don&#8217;t worry, this component is still open-source, and the license permits source redistribution as part of a larger system. However, I&#8217;m asking that people who want to integrate this component purchase the download instead of ripping it out of another open-source project. My free to non-free LOC (lines of code) ratio is still over 40 to 1, and I plan on keeping it that way.  I trust this will keep everybody happy.</p>
<p>Your donations are the reason Version 2 exists.</p>
<h2>A few user comments&#8230;</h2>
<div class="smallcomments">
<blockquote>
<p>To anyone thinking of using this module, it worked great and saved me lots of custom-coding time for a client project. On top of that, Nathanael reworked some of the code to my needs for a very reasonable rate, so I have the custom solution I needed. </p>
<p>
If you&#8217;re working on an image display project in asp.net, just use this code and enjoy. It&#8217;s bullet proof!</p>
<p>Jason<br/><br />
<a href="http://webmanufactory.blogspot.com/">http://webmanufactory.blogspot.com/</a>
</p></blockquote>
<blockquote>
<p>Nathanael, I downloaded your code this weekend to use in our portal code base. I was tired of writing code to pick between icon/medium/large/original sizes of the images for different pickers / viewers etc. I was skeptical as to whether the component would be fast enough for the performance we are after in our software, but I am glad to report that your code is super fast and does exactly what you say it does. It was easy to install, and works perfectly. Thank you so much for building this tool, it is going to come in handy!</p>
<p>I do have one question though, which is why the tool will not resize an image to be larger than the original source image. I have a few images that are 800X600 jpegs, and when I tried ?width=1024 the code returned the original image size of 800X600? Is this by design? How hard would it be to make the code upsize and image? <em>[v2 allows this with &amp;scale=both]</em></p>
<p>
Again, thank you for the tool, and to other skeptic developers, Nathan&#8217;s code rocks out of the box.
</p>
<p>Thanks, <br/><br />
Steve
</p></blockquote>
<blockquote><p>
By Dave<br />
just like to say, since using the code (and getting working and donating in next to no time) we have moved three or four of our sites over to using this technique. Previously we had manually run batch resizes initially and then made clients create multiple sizes of the image&#8230; very time consuming and some clients weren&#8217;t technically up to the task. Having been after such a solution for so long, i was really worried that the time to generate images on the fly and the resultant quality would be a problem, but WOW&#8230;.. this code nails it entirely&#8230;i can only say if you are reading these comments, worry not and get this code straight away&#8230;. so much work seems to have gone into this solution, i can&#8217;t rate it too highly&#8230; my find of the year&#8230;&#8230;. thanks Nathanael&#8230;.
</p></blockquote>
</div>
</div>
<div id="buy">
</div>
<div id="features">
<p>Querystring-based resizing is super-simple and can be used from any language (HTML, ASP.NET, PHP, Flash, Flex, etc). </p>
<p>Supports scaling, cropping, rotating, flipping, stretching, padding, borders, transparency, and the 4 main image formats. Aspect ratio is maintained unless <strong>&amp;stretch=fill</strong> is specified.</p>
<p>For example, to make an image 400px or less wide, just add <strong>?width=400</strong>. If you want to set both the maximum height and width, use <strong>?maxwidth=400&amp;maxheight=400</strong>.</p>
<p>Sometimes you need all your images to be exactly the same size, regardless of the original aspect ratio. There are several solutions to this. If you specify both <strong>width</strong> and <strong>height</strong>, whitespace will be automatically added to two sides to make up the difference. Set whitespace color with <strong>&amp;bgcolor</strong>. If you don&#8217;t want whitespace, you can try <strong>&amp;crop=auto</strong>. This &#8220;smart cropping&#8221; will figure out the minimal amount of cropping needed to center the image in the box without changing the aspect ratio or leaving whitespace. And, of course, you could stretch your images with <strong>&amp;stretch=fill</strong>&#8230; if you really wanted to.</p>
<p>Convert between jpg, png, gif, tiff, and bmp images with <strong>&amp;format=jpg|png|gif</strong>. Adjust the quality/size tradeoff of Jpegs with <strong>&amp;quality=1-100</strong>, and the palette size of GIFs and PNGs with <strong>&amp;colors=2-255</strong></p>
<p>Not just for thumbnails &#8211; useful for resizing entire slideshows in real-time as the user changes the window size.</p>
<p>Check out the <a href="~/11201" runat="server">samples page</a> to see the features in action.</p>
<ul class="normallist">
<li>Supported input formats: BMP, GIF, JPG, PNG and TIFF</li>
<li>Supported output formats: <strong>JPG, PNG, and GIF</strong></li>
</li>
</ul>
</div>
<div id="quality">
<p>Bicubic resampling is used exclusively, resulting in very high-quality output. Jpeg compression is excellent, and uses the native windows JPEG encoder. Version 2.0 adds octree quantization for GIF and 8-bit PNG output, providing excellent palette generation for those also.</p>
<p>In my tests, the native windows JPEG encoder and Photoshop have the same visual quality and file size results. Expect photoshop-quality results for both JPEG and PNG output. </p>
<p>GIF and 8-bit PNG output is drastically improved in version 2.0 due to the addition of octree quantization. The primary difference you will notice between Photoshop and module output is the lack of dithering. In most scenarios this doesn&#8217;t affect visual quality much and actually makes the image look &#8216;cleaner&#8217;. Very gentle gradients do benefit from dithering, as do gradients against transparency. </p>
<p>File sizes are excellent &#8211; don&#8217;t expect a measurable improvement when you use Photoshop or ImageReady to compress your images with the same quality settings.</p>
</div>
<div id="performance">
<p>The key to the excellent performance of this module is the disk caching system. This allows even a relatively low-end server to handle the same number of dynamic requests as static file requests.</p>
<ul class="normallist">
<li>Caching doesn&#8217;t get in your way &#8211; if you modify the source file, the resized versions are also updated.</li>
<li>You can resize the same image to several different sizes, and the different versions are cached separately.</li>
<li><strong>Managed disk cache</strong>. If the number of cached files exceeds the configured threshold, a cleanup pass is made on the directory, and a block of the least recently used files are removed.</li>
<li>Client-side caching directives are sent, minimizing repetitive requests from the same client.</li>
<li>Thumbnail generation in <strong>under 20 milliseconds</strong> for most images.</li>
<li>Suitable for slideshows and lists of images. Even the initial resizing of 50 images concurrently isn&#8217;t noticeably slow.</li>
<li>Good with large source files (1-5MB)</li>
</ul>
</div>
<div id="requirements">
<ul class="normallist">
<li>Runs on any of the following following: Windows 2000,  Server 2000, XP, Server 2003, Vista, Server 2008, or Windows 7*. *Not tested, but I don&#8217;t know of any breaking changes to IIS occuring.</li>
<li>Requires .NET 2.0 or higher to be installed on the server and enabled on the website.</li>
<li>The customer must have the ability to copy and paste configuration settings, download files, copy files, and follow simple directions for configuring IIS 6 and below.</li>
<li>Users of version 1.0 should get the free upgrade to 1.2 if they wish to use IIS7 Integrated Mode.</li>
</ul>
</div>
<div id="opensource" style="padding-left:25px">
<p>While I do charge a download fee, the license allows you to redistribute the source as part of another open-source project. I&#8217;m trying to achieve several objectives: 1) Remove the need for users to track licenses, 2) Promote use in open-source projects, 3) Still provide financial support so the project can continue to evolve rapidly.</p>
<ul class="normallist">
<li>Complete source code and an example project is included</li>
<li>Clean, well documented, well designed code. </li>
<li>Great platform to build your own image processing systems on. You can use the disk caching system or image processing code independently from each other.</li>
<li>Very extensible, easy to add new features.</li>
</ul>
<p>CustomFolders.cs can be *easily* modified to do all kinds of work:</p>
<ul class="normallist">
<li>Build rules to automatically resize images based on folder name or other criteria. </li>
<li>Add a new syntax for abbreviating or simplifying common resizing operations. Like /resize(w,h)/.</li>
<li>Easily perform URL rewriting for your images with String.Replace calls. (Regexes work too, if you like them).</li>
</ul>
<p>By purchasing the download, you are permitted to </p>
<ol>
<li>Modify and use the component in all of your projects. </li>
<li>Redistribute the source code as part of another project, provided the component<br />
is less than 5% of the project (in lines of code), and you keep this information attached.</li>
<li>If you received the source code as part of another open source project,<br />
you cannot extract it (by itself) for use in another project without purchasing a download<br />
from http://nathanaeljones.com/. If nathanaeljones.com is no longer running, and a download<br />
cannot be purchased, then you may extract the code.</li>
</ol>
<p>This is basically a developer license &#8211; if you aren&#8217;t a developer (i.e., a hosting company wanting a site or server license), please e-mail me (nathanael.jones@gmail.com).</p>
</div>
<div id="changelog">
<h2>Releases</h2>
<ol class="normallist">
<li>1.0 &#8211; August 6, 2008 (Initial release to the public.) </li>
<li>1.2 &#8211; Nov 23, 2008 (<a href="~/11171" runat="server">Upgrade Notes from 1.0 to 1.2</a>) (<a href="~/11131" runat="server">Original product page</a>) </li>
<li>2.0a Jan 30, 2009 (E-mail distribution)</li>
<li>2.0a Mar 4, 2009 (E-mail distribution)</li>
<li>2.0b May 16, 2009  (<a href="~/11181" runat="server">Upgrade notes from 1.2 to 2.0</a>)
</li>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/162/server-side-image-resizing-module-for-asp-net-asp-phpiis-3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Image Resizer 2.0 &#8211; Upgrade notes</title>
		<link>http://nathanaeljones.com/159/image-resizer-2-0-upgrade-notes/</link>
		<comments>http://nathanaeljones.com/159/image-resizer-2-0-upgrade-notes/#comments</comments>
		<pubDate>Sun, 17 May 2009 04:12:57 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[Image Resizing]]></category>
		<category><![CDATA[image resizer]]></category>

		<guid isPermaLink="false">http://66.29.219.39/?p=159</guid>
		<description><![CDATA[Version 2.0 includes dozens of new features and performance enhancements. Upgrading is simple, but there are a few things you should know.]]></description>
			<content:encoded><![CDATA[<h2>Behavior changes</h2>
<ul class="normallist">
<li>When both <strong>?width=x&amp;height=y</strong> are specified, the default behavior has changed. Instead of stretching the image and losing aspect ratio, whitespace is added (controlled with <strong>&amp;bgcolor=color name|code</strong>). You can reinstate the original behavor by adding <strong>&amp;stretch=fill</strong>. Based on customer feedback.</li>
<li>ICC profiles are now read on source images, but changes are merged into the image before output. Since most browsers (including Firefox) do not read ICC profiles, this should produce consistent cross-browser behavior. If you want to ignore the original ICC profile for an image, add <strong>&amp;ignoreicc=true</strong>.</li>
<li>The CustomFolders.cs format has changed, and is now much, much more powerful. All querystring commands can be used, and URL rewriting can be performed. (AllowURLRewriting must be true).</li>
</ul>
<h2>New features</h2>
<p>Check out the <a href="~/11201">samples page</a> to see these features in action.</p>
<ul class="normallist">
<li>Automatic cropping and centering can be performed with <strong>?crop=auto&amp;width=x&amp;height=y</strong>. You can also choose a crop rectangle from the source image manually with <strong>&amp;crop=(x1,y1,x2,y2)</strong>. Negative values indicate distances relative to the bottom-right corner. (10,10,-10,-10) would crop a 10-pixel border off the source image.</li>
<li>Support for 8-bit PNG file output with <strong>&amp;colors=2-255</strong>. Sets the palette size for both PNG and GIF images.</li>
<li>GIF and 8-bit PNG files are now much, much better. Instead of using the GDI default palette, octree quantization is used to calculate the optimal color palette for each image.</li>
<li>Upscaling can be enabled using &amp;scale=both. The default is &amp;scale=downscaleonly. &amp;scale=upscaleonly is also available for certain zooming situations.</li>
<li> Image rotation is supported in degrees. Ex. &amp;rotate=45. Image sizing is performed before rotation, so rotation will cause the final image size to be larger than the size specified in the querystring.</li>
<li>Image flipping can be performed using <strong>&amp;flip=h|v|both.</strong> To flip the source image before other commands occur, use <strong>&amp;sourceFlip=h|v|both</strong>.</li>
<li>BMP and TIFF source files are now supported.</li>
<li>You can add padding around the image with <strong>&amp;paddingWidth=px&amp;paddingColor=color|hex</strong>. paddingColor defaults to bgcolor, which defaults to white.</li>
<li> You can add a border around the image with <strong>&amp;borderWidth=px&amp;borderColor=color|hex</strong>.</li>
<li>Transparency is maintained while resizng PNG files, and when converting from PNG to GIF.</li>
<li>DisableCacheCleanup=true|false is now supported in Web.config. If you have plenty of disk space and wish to manually purge old files from the cache, this setting will allow it. Leave the default value to false unless you have a very good reason.</li>
<li> DiskCacheAlwaysInvalid=true|false is a new Web.config setting for debugging. It forces every request to update the disk cache before responding. Very, very slow, so make *sure* this is false before you launch.</li>
<li>Websites located on UNC paths are now supported. (Ex. \\server\share\website).</li>
</ul>
<h2>Installation</h2>
<ol class="normallist">
<li>Replace the old files with the new files from the ImageResizer folder. If you are using the .DLL, replace the DLL in the bin folder.  Keep a copy of your old CustomFolders.cs if you have modified it.</li>
<li>Delete the /imagecache directory.</li>
<li>If you use both width and height to stretch any images, add <strong>&amp;stretch=fill</strong> to those URLs to maintain the same behavior.</li>
<li>Migrate CustomFolders.cs if you have modified it. The new file includes source comments explaining the process.</li>
</ol>
<p>If you haven&#8217;t upgraded to 1.2, follow <a href="~/11171"> these instructions first</a></p>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/159/image-resizer-2-0-upgrade-notes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Image Resizer v2 Examples</title>
		<link>http://nathanaeljones.com/155/image-resizer-v2-examples/</link>
		<comments>http://nathanaeljones.com/155/image-resizer-v2-examples/#comments</comments>
		<pubDate>Fri, 08 May 2009 19:23:59 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[Image Resizing]]></category>

		<guid isPermaLink="false">http://66.29.219.39/?p=155</guid>
		<description><![CDATA[Here are some examples of what can be done with Version 2.0. ]]></description>
			<content:encoded><![CDATA[<p>Here are some examples of what can be done with Version 2.0.</p>
<p>Hover over the images to view the querystrings used. All commands can be combined.</p>
<h2>Resizing using maxwidth and/or maxheight</h2>
<p>Aspect ratio is always maintained with maxwidth and maxheight. The image is scaled to fit within those bounds.</p>
<p>    <img src="red-leaf.jpg?maxwidth=300" title="With ?maxwidth=300"/><br />
    <img  src="grass.jpg?maxheight=300"  title="With ?maxheight=300"/></p>
<p>    <img  src="tulip-leaf.jpg?maxwidth=300&amp;maxheight=300"  title="With ?maxwidth=300&amp;maxheight=300"/></p>
<h2>Resizing using width and height</h2>
<p>Specifying only one of <em>width</em> or <em>height</em> will behave the same as using <em>maxwidth</em><br />
    or <em>maxheight</em>. The difference is when you specify both.</p>
<p>Specifying both width and height will force the image to those exact dimensions, unless the<br />
    image is already smaller (see scale). This is done by adding whitespace to the image. To center and crop instead, use<br />
    <strong>&amp;crop=auto</strong>. To lose aspect ratio and fill the specified rectangle, use <strong>&amp;stretch=fill</strong>.</p>
<p>    <img style="border:1px solid gray;" src="grass.jpg?width=200&#038;height=200"  title="Shown with a border so you can see the added whitespace. ?width=200&#038;height=200"/><br />
     <img src="grass.jpg?width=200&#038;height=200&#038;bgcolor=black"  title="With ?width=200&#038;height=200&#038;bgcolor=black"/><br />
    <img  src="red-leaf.jpg?width=100&#038;height=200&#038;stretch=fill" title="Distorted to 100x200. ?width=100&#038;height=200&#038;stretch=fill"/><br />
    <img src="red-leaf.jpg?width=100&#038;height=200&#038;crop=auto"   title="Cropped to 100x200. ?width=100&#038;height=200&#038;crop=auto"/></p>
<h2>Scaling</h2>
<p>By default, images are not upscaled. If an image is already smaller than width/height/maxwidth/maxheight, it is not resized.<br />
    To upscale images, use <strong>?scale=both</strong>. <strong>?scale=downscaleonly</strong> is the default.</p>
<p>    <img src="tractor-tiny.jpg?scale=both&#038;width=200"  title="Upscaled from 100px to 200px using ?scale=both&#038;width=200" /><br />
    <br />
    The slight blur around the edges is a bug in Graphics.DrawImage(). You can control the color by setting <strong>&amp;bgcolor=color|hex</strong>.</p>
<h2>Cropping</h2>
<p>To enable cropping, you can use <strong>&amp;crop=auto</strong>, which minimally crops and centers to preserve aspect ratio, or custom cropping.</p>
<p><strong>&amp;crop=(x1,y1,x2,y2)</strong> specifies the rectangle to crop on the image. You can still resize and modify the cropped portion<br />
    using the other commands as normal. Negative coordinates are relative to the bottom-right corner &#8211;<br />
    which makes it easy to trim off a 50-pixel border by specifying <strong>&amp;crop=(50,50,-50,-50)</strong>.</p>
<p>    <img id="Img5" src="tractor.jpg?crop=(10,150,200,350)"   title="Cropping out a 200x200 square using ?crop=(10,150,200,350)" /><br />
    <img id="Img6" src="tractor.jpg?crop=(60,200,250,400)"    title="Cropping out a 200x200 square using ?crop=(60,200,250,400)"  /><br />
    <img id="Img7" src="tractor.jpg?crop=auto&#038;width=300&#038;height=150"    title="Cropping out to 300x150 square using ?crop=auto&#038;width=300&#038;height=150"/></p>
<h2>Rotation</h2>
<p>Rotation is easy &#8211; just specify the number of degrees. You may want to set bgcolor also.</p>
<p>    <img id="Img8" src="red-leaf.jpg?rotate=30&#038;maxwidth=100"   title="With ?rotate=30&#038;maxwidth=100"/></p>
<p>    <img id="Img9" src="tractor.jpg?rotate=-30&#038;crop=(60,200,250,400)"   title="Using ?rotate=-30&amp;crop=(60,200,250,400)" /></p>
<p>    <img id="Img10" src="grass.jpg?rotate=45&#038;width=200&#038;height=200&#038;crop=auto&#038;bgcolor=black"  title="With ?rotate=45&#038;width=200&#038;height=200&#038;crop=auto&#038;bgcolor=black"/></p>
<h2>Flipping</h2>
<p>You can horizontally or verically flip an image, as well as both. <strong>&amp;flip=h|v|both</strong></p>
<p>    <img id="Img11" src="tractor.jpg?flip=v&#038;crop=(60,200,250,400)"   title="Using ?flip=v&#038;crop=(60,200,250,400)"  /><br />
     <img id="Img12" src="tractor.jpg?flip=both&#038;crop=(60,200,250,400)"   title="Using ?flip=both&#038;crop=(60,200,250,400)"/><br />
    <img id="Img13" src="tractor.jpg?crop=(60,200,250,400)"   title="Using ?crop=(60,200,250,400)"  /><br />
     <img id="Img14" src="tractor.jpg?flip=h&#038;crop=(60,200,250,400)"   title="Using ?flip=h&#038;crop=(60,200,250,400)" /></p>
<h2>Source flipping</h2>
<p>Since normal flipping applies after rotation and cropping occur, it can be<br />
    difficult to work with if you are just wanting the source image flipped before the other<br />
    adjustments are applied. To flip the source prior to work, use <strong>&amp;sourceFlip=h|v|both</strong>.</p>
<p>Note how the same crop coordinates return different sections of the image. This is because the source image is flipped before *anything* happens.</p>
<p>    <img id="Img20" src="tractor.jpg?maxwidth=100"   title="Using ?maxwidth=100" /><br />
    <img id="Img15" src="tractor.jpg?crop=(0,0,100,100)"   title="Using ?crop=(0,0,100,100)"/><br />
    <img id="Img16" src="tractor.jpg?flip=both&#038;crop=(0,0,100,100)"   title="Using ?flip=both&#038;crop=(0,0,100,100)" /></p>
<h2>Stretching</h2>
<p>To stretch an image to width and height, use <strong>&amp;stretch=fill</strong>. </p>
<p>    <img id="Img17" src="tractor.jpg?stretch=fill&#038;width=200&#038;height=100"   title="Using ?stretch=fill&#038;width=200&#038;height=100)"  /></p>
<h2>Padding</h2>
<p>You can add padding around the image with <strong>&amp;paddingWidth=px</strong> and<br />
    <strong>&amp;paddingColor=color|hex</strong>. paddingColor defaults to bgcolor, which defaults to white.<br />
    This setting can be&#8230;. useful.</p>
<p>    <img id="Img18" src="grass.jpg?maxwidth=200&#038;paddingColor=black&#038;paddingwidth=20"  title="With ?maxwidth=200&#038;paddingColor=black&#038;paddingwidth=20"/></p>
<h2>Borders</h2>
<p>You can add a border around the image with <strong>&amp;borderWidth=px</strong>,<br />
    <strong>&amp;borderColor=color|hex</strong>.</p>
<p>    <img id="Img19" src="grass.jpg?maxwidth=200&#038;paddingColor=white&#038;paddingwidth=20&#038;borderWidth=8&#038;borderColor=808080" title="With ?maxwidth=200&#038;borderWidth=8&#038;borderColor=808080&#038;paddingwidth=20"/></p>
<h1>Output format</h1>
<p>GIF, JPG, and PNG output is supported. BMP and TIFF input fils are additionally supported, and every format can be converted to any other format with <strong>&amp;format=jpg|png|gif</strong></p>
<h2>Jpeg compression levels 0-100 (&amp;quality=0-100)</h2>
<p>The sizes of these images range from 855B to 12KB. The largest size jump is from 90 to 100 (5KB to 12KB). I think 90 is a good balance, and is therefore the default.</p>
<p>     <img id="Img31" src="tulip-leaf.jpg?quality=0&#038;maxwidth=100"  /><br />
    <img id="Img21" src="tulip-leaf.jpg?quality=10&#038;maxwidth=100"  /><br />
    <img id="Img22" src="tulip-leaf.jpg?quality=20&#038;maxwidth=100"  /><br />
    <img id="Img23" src="tulip-leaf.jpg?quality=30&#038;maxwidth=100"  /><br />
    <img id="Img24" src="tulip-leaf.jpg?quality=40&#038;maxwidth=100"  /><br />
    <img id="Img25" src="tulip-leaf.jpg?quality=50&#038;maxwidth=100"  /><br />
    <img id="Img26" src="tulip-leaf.jpg?quality=60&#038;maxwidth=100"  /><br />
    <img id="Img27" src="tulip-leaf.jpg?quality=70&#038;maxwidth=100"  /><br />
    <img id="Img28" src="tulip-leaf.jpg?quality=80&#038;maxwidth=100"  /><br />
    <img id="Img29" src="tulip-leaf.jpg?quality=90&#038;maxwidth=100"  /><br />
    <img id="Img30" src="tulip-leaf.jpg?quality=100&#038;maxwidth=100"  /></p>
<h2>Quantization (8-bit PNG and GIFs)</h2>
<p>The default GDI quantization is terrible, and produces lousy GIFs. Using the Octree quantizer, you can<br />
    control the number of colors (and therefore the size and quality) of an image using <strong>&amp;colors=2-255</strong></p>
<h3>GIFs, in 4,8,16,32,64,128, and 256 colors</h3>
<p>    <img id="Img32" src="tractor.jpg?&#038;maxwidth=100&#038;format=gif&#038;colors=4"  /><br />
    <img id="Img33" src="tractor.jpg?&#038;maxwidth=100&#038;format=gif&#038;colors=8"  /><br />
    <img id="Img34" src="tractor.jpg?&#038;maxwidth=100&#038;format=gif&#038;colors=16"  /><br />
    <img id="Img35" src="tractor.jpg?&#038;maxwidth=100&#038;format=gif&#038;colors=32"  /><br />
    <img id="Img36" src="tractor.jpg?&#038;maxwidth=100&#038;format=gif&#038;colors=64"  /><br />
    <img id="Img37" src="tractor.jpg?&#038;maxwidth=100&#038;format=gif&#038;colors=128"  /><br />
    <img id="Img38" src="tractor.jpg?&#038;maxwidth=100&#038;format=gif&#038;colors=256"  /></p>
<h3>PNGs, in 4,8,16,32,64,128, 256, and 16 million colors</h3>
<p>        <img id="Img39" src="tractor.jpg?&#038;maxwidth=100&#038;format=png&#038;colors=4"  /><br />
    <img id="Img40" src="tractor.jpg?&#038;maxwidth=100&#038;format=png&#038;colors=8"  /><br />
    <img id="Img41" src="tractor.jpg?&#038;maxwidth=100&#038;format=png&#038;colors=16"  /><br />
    <img id="Img42" src="tractor.jpg?&#038;maxwidth=100&#038;format=png&#038;colors=32"  /><br />
    <img id="Img43" src="tractor.jpg?&#038;maxwidth=100&#038;format=png&#038;colors=64"  /><br />
    <img id="Img44" src="tractor.jpg?&#038;maxwidth=100&#038;format=png&#038;colors=128"  /><br />
    <img id="Img45" src="tractor.jpg?&#038;maxwidth=100&#038;format=png&#038;colors=256"  /><br />
    <img id="Img46" src="tractor.jpg?&#038;maxwidth=100&#038;format=png"  /></p>
<h2>Transparent GIFs and PNGs</h2>
<h3>Transparency is maintained when resizing PNGs</h3>
<p>    <img id="Img49" src="/wp-content/uploads/2009/10/sun_256.png"  /><br />
    <img id="Img47" src="/wp-content/uploads/2009/10/sun_256.png?maxwidth=100"  /><br />
    <img id="Img48" style="background-color:black" src="/wp-content/uploads/2009/10/sun_256.png?&#038;maxwidth=200"  /></p>
<h3>Matte backgrounds can be applied with bgcolor. </h3>
<p>    <img id="Img50" src="/wp-content/uploads/2009/10/moon_256.png?maxwidth=100&#038;bgcolor=red"  /><br />
    <img id="Img51" src="/wp-content/uploads/2009/10/moon_256.png?maxwidth=100&#038;bgcolor=blue"  /><br />
    <img id="Img52" src="/wp-content/uploads/2009/10/moon_256.png?maxwidth=100&#038;bgcolor=green"  /></p>
<h3>Transparent PNGs can be converted to transparent GIFs</h3>
<p>It&#8217;s ugly, but GIFs only get 1 bit for transparency.</p>
<p>    <img id="Img1" src="/wp-content/uploads/2009/10/saturn_256.png?format=gif"  /></p>
<h2>Single frames can be extracted from animated GIFs with &amp;frame=x</h2>
<p>    <img id="Img2" src="/wp-content/uploads/2009/11/2_computers.gif"  /><br />
    <img id="Img3" src="/wp-content/uploads/2009/11/2_computers.gif?frame=5"  /><br />
    <img id="Img4" src="/wp-content/uploads/2009/11/2_computers.gif?frame=8"  /><br />
    <img id="Img53" src="/wp-content/uploads/2009/11/2_computers.gif?frame=10"  /></p>
<p></p>
<h2>/resize(width,height,format)/ syntax</h2>
<p>For the URL-conscious, you can replace <strong>img/image.jpg?maxwidth=x&amp;maxheight=y</strong> with<br />
     <strong>img/resize(x,y)/image.jpg</strong>. A third argument, format, is also allowed.</p>
<p><em>However</em>, enabling this (AllowURLRewriting) will make the ASP.NET URL authorization system unable to match URLs&#8230;. But that only affects you if you set permissions in web.config.</p>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/155/image-resizer-v2-examples/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Image Resizer 1.2, 2.0 &#8211; Web.config</title>
		<link>http://nathanaeljones.com/149/image-resizer-1-2-2-0-web-config/</link>
		<comments>http://nathanaeljones.com/149/image-resizer-1-2-2-0-web-config/#comments</comments>
		<pubDate>Fri, 21 Nov 2008 22:44:56 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[Image Resizing]]></category>
		<category><![CDATA[image resizer]]></category>

		<guid isPermaLink="false">http://66.29.219.39/?p=149</guid>
		<description><![CDATA[Adding web.config settings]]></description>
			<content:encoded><![CDATA[
<p>Version 1.2 of the image resizer is much easier to install in web.config, since it is implemented as an HttpModule instead of an HttpHandler. It still integrates quite well with ASP.NET&#8217;s URL authorization system, and doesn&#8217;t allow access to protected files.</p>
<p>This integration isn&#8217;t valuable to most people, however, since they aren&#8217;t protecting any static files.<br />
Users who don&#8217;t need this protection can enable the &#8220;AllowFolderResizeNotation&#8221; setting to gain additional URL flexibility in exchange.</p>
<p>Version 1.2 now passes *all* file serving work back to IIS. The cached image is now written to disk first rather than last, allowing a simple RewritePath call to handle the work.</p>
<p>The same code can now be used for both IIS5, 6, 7c and 7i. The httpModules section handles IIS5/6/7c, and the modules section handles IIS7 integrated mode.</p>
<pre name="code" class="brush:xml">
&lt;system.web>
  ...
  &lt;httpModules>
    &lt;add name="ImageResizer" type="fbs.ImageResizer.InterceptModule"/>
  &lt;/httpModules>
  ...
&lt;/system.web>
&lt;system.webServer>
  &lt;validation validateIntegratedModeConfiguration="false"/>
  ...
  &lt;modules>
    &lt;add name="ImageResizer" type="fbs.ImageResizer.InterceptModule"/>
  &lt;/modules>
&lt;/system.webServer>
</pre>
<p></script></p>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/149/image-resizer-1-2-2-0-web-config/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Image Resizer Documentation</title>
		<link>http://nathanaeljones.com/142/image-resizer-documentation/</link>
		<comments>http://nathanaeljones.com/142/image-resizer-documentation/#comments</comments>
		<pubDate>Fri, 08 Aug 2008 18:28:00 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[Image Resizing]]></category>
		<category><![CDATA[image resizer]]></category>

		<guid isPermaLink="false">http://66.29.219.39/?p=142</guid>
		<description><![CDATA[Installation and configuration instructions for the Image Resizer]]></description>
			<content:encoded><![CDATA[<div style="font-size:130%">
<div style="font-size:12pt; border:1px solid gray; padding:15px; padding-bottom:0; margin-bottom:15px;">
<p>Installation is quick and simple, provided you follow the steps carefully. 99% of problems users encounter are due to skipping a step.</p>
<p>1) <strong>Copy and paste</strong> ImageResizer.dll and ImageResizer.pdb into the /bin directory of your app.<br />
Alternatively, you can copy the inner ImageResizer folder (which contains .cs files) into /App_Code. This second approach allows modification of CustomFolders.cs and Watermark.cs.</p>
<p>2) <strong>Copy and paste</strong> the settings at the bottom of the page into web.config to configure the module.</p>
<p>3) Users of 2.1+, <strong>you&#8217;re done</strong>! You can now resize images using the &#8220;image.jpg.<strong>axd</strong>?width=500&#8243; syntax.<br />
For versions prior to 2.1, or for users wanting the cleaner &#8220;image.jpg?width=500&#8243; syntax, some <a href="/11111">additional IIS configuration is needed</a>.</p>
<p><strong>Upgrading?</strong> Read the <a href="/11171">v1.0-v1.2</a>, <a href="/11181">v1.2 to v2.0</a>, or the <a href="/438/version-2-1b-released/">v2.0-v2.1</a> upgrade notes</a> instead.</div>
<h2>Configuration</h2>
<p>You will need to insert the following settings into web.config in the designated places.</p>
<pre class="brush:xml">&lt;system.web&gt;
  ...
  &lt;httpModules&gt;
    &lt;add name="ImageResizer" type="fbs.ImageResizer.InterceptModule"/&gt;
  &lt;/httpModules&gt;
  ...
&lt;/system.web&gt;
&lt;system.webServer&gt;
  &lt;validation validateIntegratedModeConfiguration="false"/&gt;
  ...
  &lt;modules&gt;
    &lt;add name="ImageResizer" type="fbs.ImageResizer.InterceptModule"/&gt;
  &lt;/modules&gt;
&lt;/system.webServer&gt;</pre>
<p>Last, some app settings for the resizer. You can use the following safely with v2.1 and up. Full configuration reference and notes for other versions can be found in the next section.</p>
<pre class="brush:xml">&lt;appSettings&gt;
    ...
    &lt;add key="ImageDiskCacheDir" value="imagecache" /&gt;
    &lt;add key="MaxCachedImages" value="30000" /&gt;
    &lt;add key="ImageResizerMaxWidth" value="1680" /&gt;
    &lt;add key="ImageResizerMaxHeight" value="1680" /&gt;
    &lt;add key="ImageResizerClientCacheMinutes" value="1440" /&gt;
    &lt;add key="AllowURLRewriting" value="true" /&gt;
    &lt;add key ="ResizeExtension" value=".axd"/&gt;
    ...
&lt;/appSettings&gt;</pre>
<h2>Complete reference</h2>
<pre class="brush:xml">    &lt;!-- The directory to store cached version of images. Relative to the application root --&gt;
    &lt;add key="ImageDiskCacheDir" value="imagecache" /&gt;  

    &lt;!-- How many files to keep in the cache. The 10% least recently used files will be deleted
when this limit is reached. Don't set this lower than the number of images on your site. 2x the image count is a
 good default. If you are getting "Access Denied" messages, this is the cuplrit - you need to increase it --&gt;
    &lt;add key="MaxCachedImages" value="30000" /&gt;  

    &lt;!-- The following settings are optional: --&gt;  

    &lt;!-- The maximum size to permit images to be resized to. --&gt;
    &lt;add key="ImageResizerMaxWidth" value="1680" /&gt;
    &lt;add key="ImageResizerMaxHeight" value="1680" /&gt;  

    &lt;!-- Takes effect in version 1.2. The default (for all versions) is 1440 minutes (24 hours).
        Set to 0 to disable *client* caching (304 "Not Modified" responses will still be returned
        if nothing has changed). Client caching is not related to disk caching. --&gt;
    &lt;add key="ImageResizerClientCacheMinutes" value="1440" /&gt;  

    &lt;!-- This enables /resize(x,y,f)/image.jpg notation in v1.2+. Enabling this
      will make URL authorization ineffective on image files. Changed to AllowURLRewriting in 2.0--&gt;
    &lt;add key="AllowFolderResizeNotation" value="true" /&gt;  

    &lt;!-- This enables /resize(x,y,f)/image.jpg notation and other CustomFolders.cs
rewriting (other than querystring-only changes) in v2.0. Enabling this
      will make URL authorization ineffective on image files on version prior to 2.1b.--&gt;
    &lt;add key="AllowURLRewriting" value="true" /&gt;  

    &lt;!-- (v2.0a+ only) Prevents use of cached files - useful for development when changing resizing algorithms.
          Causes terrible performance - don't leave enabled.--&gt;
        &lt;add key="DiskCacheAlwaysInvalid" value="false"/&gt;  

    &lt;!-- (v2.0b+ only) Prevents the cache cleanup routine from running. If you want to
        manually purge the image cache yourself, and aren't worried about running out
        of disk space via a DOS attack, you can disable this. Not advised. --&gt;
    &lt;add key="DisableCacheCleanup" value="false"/&gt;  

  &lt;!-- (v2.1+ only) Disabling custom quantization allows the resizer to function in low trust
     environments where managed pointer access and data type marshaling is prohibited.
     However, PNGs and BMPs can only be output in 32-bit mode, and GIFs will use the default
     halftone pallete. Enable this if JPGs and PNGs work, but GIFs don't, and using colors=255
      on PNGs causes them to break also.
     Causes much lower quality GIFs to be generated.
      Version 2.1+.
    --&gt;
    &lt;add key ="DisableCustomQuantization" value="false"/&gt;  

     &lt;!-- (v2.1b+ only) This allows images to be resized without any IIS configuration whatsoever.
        Just set this value to ".axd", ".ashx", ".aspx", or any extension
        already registered in IIS, and add the same extension to your image URLs when you are resizing them.
    Doesn't conflict with other pages/files with that extension, unless you name them .jpeg.ashx., etc.

        Ex. /images/media/flower.jpg -&gt; /images/media/flower.jpg.axd?width=x&amp;height=y  

        AllowURLRewriting must be true.   

      Version 2.1b+.
    --&gt;
    &lt;add key ="ResizeExtension" value=".axd"/&gt;</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/142/image-resizer-documentation/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Image Resizer License</title>
		<link>http://nathanaeljones.com/145/image-resizer-license/</link>
		<comments>http://nathanaeljones.com/145/image-resizer-license/#comments</comments>
		<pubDate>Wed, 06 Aug 2008 18:38:07 +0000</pubDate>
		<dc:creator>Nathanael Jones</dc:creator>
				<category><![CDATA[Image Resizing]]></category>

		<guid isPermaLink="false">http://66.29.219.39/?p=145</guid>
		<description><![CDATA[License agreement for the Image Resizer]]></description>
			<content:encoded><![CDATA[<p>By <strong>purchasing the download</strong>, you (the developer) are permitted to</p>
<ol>
<li><strong>Modify and use</strong> the component in all of your projects.</li>
<li><strong>Redistribute the source code as part of another project</strong>, provided the component<br />
is <strong>less than 5% of the project</strong> (in lines of code), and you keep this information attached.</li>
</ol>
<p>You may <strong>not</strong></p>
<ol>
<li><strong>Extract it from a project</strong> for re-use (in a different project) without purchasing a download<br />
from http://nathanaeljones.com/. If nathanaeljones.com is no longer running, and a download<br />
cannot be purchased, then you may extract the code.</li>
</ol>
<p><strong>This is basically a developer license</strong> &#8211; if you aren&#8217;t a developer (i.e., a hosting company wanting a site or server license), please e-mail me (nathanael.jones@gmail.com).</p>
<p style="margin-bottom:10em">
<h3>Aaand&#8230; the stock software disclaimer, in highly annoying all caps</h3>
<h4>Disclaimer of Warranty</h4>
<p>THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</p>
<h4>Limitation of Liability</h4>
<p>IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>
]]></content:encoded>
			<wfw:commentRss>http://nathanaeljones.com/145/image-resizer-license/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
